termprompt

Cancel Handling

How termprompt handles Esc and Ctrl+C with type-safe cancellation.

Preview

Active prompt

before cancel
Project name?
my-a

After Esc or Ctrl+C

cancelled
Project name?
cancelled

The Problem

When a user presses Esc or Ctrl+C, the prompt needs to return something. Returning null or undefined is ambiguous because those could be valid values. Returning false collides with confirm() results.

The Solution

termprompt uses a unique symbol for cancellation. Every prompt returns T | Cancel, and you check with isCancel().

import { input, isCancel } from 'termprompt';

const name = await input({ message: 'Name?' });

if (isCancel(name)) {
  // User pressed Esc or Ctrl+C
  console.log('Bye');
  process.exit(0);
}

// TypeScript now knows `name` is a string
console.log(name.toUpperCase());

Why a Symbol?

isCancel() is a type guard. After the check, TypeScript narrows the type from string | Cancel to string. Full type safety without casting.

const confirmed = await confirm({ message: 'Continue?' });

if (isCancel(confirmed)) {
  // confirmed is Cancel here
  process.exit(0);
}

// confirmed is boolean here, not boolean | Cancel
if (confirmed) {
  deploy();
}

The CANCEL Symbol

You can also import the symbol directly for comparisons, though isCancel() is preferred.

import { CANCEL } from 'termprompt';
import type { Cancel } from 'termprompt';

// These are equivalent:
if (isCancel(value)) { ... }
if (value === CANCEL) { ... }

With group()

When using group(), cancellation in any prompt stops the entire chain. Use the onCancel callback to handle it.

import { group, input, confirm, log } from 'termprompt';

const answers = await group(
  {
    name: () => input({ message: 'Name?' }),
    proceed: () => confirm({ message: 'Continue?' }),
  },
  {
    onCancel() {
      log.warn('Cancelled.');
      process.exit(0);
    },
  },
);
group cancelled on second prompt
Name?
my-app
Continue?
cancelled
Cancelled.

On this page