npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

termprompt

v0.2.3

Published

Beautiful terminal prompts with OSC 7770 structured output for rich terminal hosts

Downloads

600

Readme

termprompt

Beautiful terminal prompts for Node.js. Zero dependencies.

Every prompt emits OSC 7770 escape sequences alongside the TUI. Smart terminals (web terminals, IDE terminals, multiplexers) can intercept the structured data and render native UI. Standard terminals ignore the sequences and show the TUI. Zero config, zero degradation.

Documentation

┌  create-app
│
◆  Project name?
│  my-app
◆  Pick a framework
│  Next.js
◆  Select features
│  TypeScript, Vitest
◆  Initialize git?
│  Yes
◆  Project created!
└  Happy coding.

Install

npm install termprompt

Quick start

import { setTheme, intro, outro, select, input, isCancel, log } from 'termprompt';

setTheme({ accent: '#7c3aed' });
intro('create-app');

const name = await input({
  message: 'Project name?',
  placeholder: 'my-app',
});
if (isCancel(name)) process.exit(0);

const framework = await select({
  message: 'Pick a framework',
  options: [
    { value: 'next', label: 'Next.js', hint: 'React SSR' },
    { value: 'hono', label: 'Hono', hint: 'Edge-first' },
    { value: 'astro', label: 'Astro', hint: 'Content sites' },
  ],
});
if (isCancel(framework)) process.exit(0);

log.success(`Created ${name} with ${framework}.`);
outro('Happy coding.');

Prompts

select

Pick one option from a list.

const framework = await select({
  message: 'Pick a framework',
  options: [
    { value: 'next', label: 'Next.js', hint: 'React SSR' },
    { value: 'hono', label: 'Hono', hint: 'Edge-first' },
    { value: 'express', label: 'Express', disabled: true },
  ],
  initialValue: 'next',
  maxItems: 5,
});
◇  Pick a framework
│  ◉ Next.js (React SSR)
│  ○ Hono
│  ○ Astro
└

Keys: Up/Down or j/k to navigate, Enter to submit, Esc to cancel.

confirm

Yes or no.

const ok = await confirm({
  message: 'Deploy to production?',
  initialValue: true,
  active: 'Yes',
  inactive: 'No',
});
◇  Deploy to production?
│  Yes / No
└

Keys: Left/Right or h/l to toggle, y/n shortcuts, Enter to submit.

input

Free text with optional validation.

const name = await input({
  message: 'Project name?',
  placeholder: 'my-app',
  validate: (v) => (v.length > 0 ? true : 'Required'),
});
◇  Project name?
│  my-app█
└

Keys: full text editing, Ctrl+A/E for home/end, Ctrl+U to clear, Ctrl+W to delete word.

multiselect

Pick multiple options.

const features = await multiselect({
  message: 'Select features',
  options: [
    { value: 'ts', label: 'TypeScript' },
    { value: 'lint', label: 'ESLint' },
    { value: 'test', label: 'Vitest' },
    { value: 'ci', label: 'GitHub Actions' },
  ],
  initialValues: ['ts'],
  required: true,
});
◇  Select features
│  >■ TypeScript
│   □ ESLint
│   ■ Vitest
│   □ GitHub Actions
└

Keys: Space to toggle, a to toggle all, Enter to submit.

password

Masked text input. Password prompts are marked as sensitive: secret values are not sent in OSC resolve payloads.

const secret = await password({
  message: 'API key?',
  mask: '•',
  validate: (v) => (v.length > 0 ? true : 'Required'),
});
◇  Enter your API key
│  ••••••••
└

number

Numeric input with optional min/max/step.

const port = await number({
  message: 'Port number?',
  initialValue: 3000,
  min: 1,
  max: 65535,
  step: 1,
});
◇  Port number?
│  3000█
└

Keys: Up/Down to increment/decrement by step, Enter to submit.

search

Type-to-filter selection. Filters by label and hint, case-insensitive.

const tz = await search({
  message: 'Select timezone',
  options: [
    { value: 'utc', label: 'UTC', hint: '+00:00' },
    { value: 'est', label: 'Eastern', hint: '-05:00' },
    { value: 'pst', label: 'Pacific', hint: '-08:00' },
  ],
  placeholder: 'Type to filter...',
  maxItems: 5,
});
◇  Select timezone
│  pac
│  ◉ Pacific (UTC-8)
│  ○ Asia/Pacific
└

Keys: type to filter, Up/Down to navigate, Enter to submit.

Display

spinner

Animated spinner for async operations.

const s = spinner();
s.start('Installing dependencies...');
// ... do work
s.message('Compiling...');
// ... more work
s.stop('Installed 142 packages');    // success ◆
s.stop('Failed', 1);                // error ▲
◒  Installing dependencies...
◆  Installed 142 packages

progress

Determinate progress bar.

const p = progress();
p.start('Downloading...');
p.update(30, 'Downloading...');
p.update(60, 'Downloading...');
p.update(100, 'Downloading...');
p.stop('Download complete');
████████████░░░░░░░░  Downloading...  60%
◆  Download complete

tasks

Run multiple tasks with status tracking.

const result = await tasks([
  {
    title: 'Install dependencies',
    task: async () => { /* ... */ },
  },
  {
    title: 'Generate types',
    task: async (ctx, update) => {
      update('Generating schema...');
      /* ... */
    },
  },
  {
    title: 'Run tests',
    task: async () => { /* ... */ },
    enabled: false, // skip this task
  },
], { concurrent: false });
│
◆  Install dependencies
◒  Generating schema...
○  Run tests
│

note

Boxed note with optional title.

note('cd my-app\nnpm run dev', 'Next steps');
│
│  ────────────────
│  Next steps
│  cd my-app
│  npm run dev
│  ────────────────

log

Structured log lines with icons.

log.info('Connected to database');     // ⓘ  info
log.success('Build complete');         // ◆  success
log.warn('Deprecated config');         // ▲  warning
log.error('Connection failed');        // ▲  error
log.step('Running migrations');        // │  gray

intro / outro

Session markers that bracket your CLI flow.

intro('my-cli v1.0');
// ... prompts and work
outro('All done!');
┌  my-cli v1.0
│
│  ... your prompts here ...
│
└  All done!

Composition

group

Chain prompts together. Each step receives previous results. Stops on cancel and returns collected answers up to that point.

const answers = await group({
  name: () => input({ message: 'Project name?' }),
  framework: () => select({
    message: 'Framework?',
    options: [
      { value: 'next', label: 'Next.js' },
      { value: 'hono', label: 'Hono' },
    ],
  }),
  confirm: ({ results }) =>
    confirm({ message: `Create ${results.name} with ${results.framework}?` }),
}, {
  onCancel: () => process.exit(0),
});

Theming

Five semantic colors. All optional. Flows through every prompt, spinner, log, and focus indicator.

import { setTheme } from 'termprompt';

setTheme({
  accent: '#7c3aed',    // interactive states (default: cyan)
  success: '#22c55e',   // submitted/completed (default: green)
  error: '#ef4444',     // failures (default: red)
  warning: '#f59e0b',   // cancel/validation (default: yellow)
  info: '#3b82f6',      // informational (default: blue)
});

Accepts hex, rgb, named colors ('cyan', 'magenta'), or any (text: string) => string function. Works with chalk, picocolors, or raw ANSI.

Cancel handling

Every prompt returns T | Cancel. Use isCancel() to check.

import { select, isCancel } from 'termprompt';

const result = await select({
  message: 'Pick one',
  options: [{ value: 'a', label: 'A' }],
});

if (isCancel(result)) {
  console.log('User cancelled');
  process.exit(0);
}

// result is narrowed to T here

Ctrl+C or Escape triggers cancellation. With group(), cancelling any prompt cancels the entire group.

Full example

See examples/basic.ts for a complete example that uses every component: group, input, select, search, number, multiselect, password, confirm, spinner, progress, tasks, note, and log.

npm run build && node --experimental-strip-types examples/basic.ts

OSC 7770

Every prompt, spinner, progress bar, and log message emits an OSC 7770 escape sequence with a JSON payload describing the structured data:

ESC ] 7770 ; {"v":1,"type":"select","id":"...","message":"Pick a framework","options":[...]} BEL

Terminal hosts (web terminals, IDE terminals, multiplexers) can register an OSC handler for code 7770, intercept the payload, and render native UI (dropdowns, modals, checkboxes, progress bars) instead of the TUI. When the user makes a selection, the host writes a resolve message back to PTY stdin.

For sensitive prompts (for example password), hosts should return values as normal PTY keystrokes instead of OSC resolve payload values.

Terminals that don't support OSC 7770 silently ignore the sequences per ECMA-48. The TUI works exactly as it would without the protocol.

Your code doesn't change. No feature flags. No configuration. The library handles everything.

See SPEC.md for the full protocol specification.

License

MIT