Prompt for y/N Without readline Cruft

Every CLI script needs a confirm() one day. The full Inquirer ceremony is overkill. Here is the small wrapper I copy into deploy scripts when I need 'are you sure? [y/N]' that defaults to no.

JavaScript
Frontend
2 snippets
input-output
code-template
petrawilson

By @petrawilson

April 25, 2026

·

Updated May 20, 2026

1,007 views

33

Rate

// Split the prompt into two pieces. The pure half ('did the user type yes?')
// is testable; the IO half (read a line from stdin) is the thin wrapper that
// changes between Node, browser, and a test harness.

// Pure: takes the raw answer string, returns boolean per the default-no rule.
function interpretAnswer(rawAnswer, defaultAnswer) {
    const trimmed = String(rawAnswer || '').trim().toLowerCase();
    if (trimmed === '') return defaultAnswer;
    return trimmed === 'y' || trimmed === 'yes';
}

// The hint is what tells the user the default. Capital N is the convention
// every git/cargo/kubectl prompt uses; veteran terminal users read it as
// 'press Enter for no'.
function promptHint(defaultAnswer) {
    return defaultAnswer ? '[Y/n]' : '[y/N]';
}

// Tests of the pure layer; in a real codebase these go in a Jest file.
const cases = [
    ['',     false, false],
    ['',     true,  true ],
    ['y',    false, true ],
    ['Yes',  false, true ],
    ['n',    true,  false],
    ['lol',  true,  false],
    ['  Y ', false, true ],
];
for (const [input, def, expected] of cases) {
    const got = interpretAnswer(input, def);
    const marker = got === expected ? 'ok ' : 'FAIL';
    console.log(`${marker} interpretAnswer(${JSON.stringify(input)}, default=${def}) = ${got}`);
}
console.log('hint default=false:', promptHint(false));
console.log('hint default=true :', promptHint(true));

Splitting the parsing logic from the IO is the design choice that makes this prompt testable. interpretAnswer is a pure function: same input always produces the same output, so the matrix of edge cases (empty string, mixed case, whitespace, junk) is cheap to verify in unit tests. The default-answer parameter is what gives the prompt the right semantics for destructive operations: confirm('Drop database?', { default: false }) defaults to no, so a fat-finger Enter does not nuke the DB. The [y/N] capitalization in promptHint is a convention every veteran terminal user reads as 'default is no'.