@hyperfrontend/questions
Terminal prompting library with composable, functional API for text, select, confirm, and multiselect prompts
What is @hyperfrontend/questions?
A terminal prompting library built on functional programming principles. Create interactive CLI experiences with composable, type-safe prompts that return structured outcomes.
Key Features
- Pure Functions — Every prompt is a pure function returning
Promise<PromptOutcome<T>>, making results predictable and easily testable - Composable API — Build complex interactive flows by combining simple prompt functions
- Type-Safe — Full TypeScript support with discriminated unions for prompt outcomes
- Zero External Dependencies — Uses only Node.js built-ins and
@hyperfrontendutilities - Searchable Multiselect — Type-to-filter functionality for large option lists
Architecture Highlights
Each prompt follows a functional state machine pattern:
- Immutable State — All prompt state is frozen; updates create new state objects
- Explicit Outcomes — Prompts return either
{ result: 'submitted', value: T }or{ result: 'cancelled', value: undefined } - Terminal Abstraction — Low-level I/O is encapsulated in a
Terminalinterface for testability
Why Use @hyperfrontend/questions?
When building CLI tools, you need interactive prompts that are:
- Predictable — Know exactly what a prompt returns, always
- Composable — Chain prompts without callback hell
- Cancellable — Handle Ctrl+C gracefully with structured cancellation
- Lightweight — No large dependency trees for simple prompts
This library provides all four while staying true to functional programming principles.
Installation
npm install @hyperfrontend/questions
Quick Start
import { text, confirm, select, multiselect, PromptResult } from '@hyperfrontend/questions'
// Text input
const nameResult = await text({
message: 'What is your name?',
validate: (value) => (value.length < 2 ? 'Name too short' : undefined),
})
if (nameResult.result === PromptResult.Submitted) {
console.log(`Hello, ${nameResult.value}!`)
}
// Confirmation
const continueResult = await confirm({
message: 'Continue?',
initial: true,
})
// Single select
const colorResult = await select({
message: 'Pick a color:',
choices: [
{ label: 'Red', value: 'red' },
{ label: 'Green', value: 'green', hint: 'recommended' },
{ label: 'Blue', value: 'blue' },
],
})
// Multiselect with search
const featuresResult = await multiselect({
message: 'Select features:',
choices: [
{ label: 'TypeScript', value: 'ts' },
{ label: 'ESLint', value: 'eslint' },
{ label: 'Prettier', value: 'prettier' },
],
searchable: true,
min: 1,
})
API Overview
| Function | Description |
|---|---|
text |
Free-form text input with optional validation |
confirm |
Yes/no confirmation prompt |
select |
Single selection from a list of choices |
multiselect |
Multiple selections with optional search |
PromptResult |
Discriminated union: 'submitted' | 'cancelled' |
All prompts return Promise<PromptOutcome<T>> where:
type PromptOutcome<T> = { result: 'submitted'; value: T } | { result: 'cancelled'; value: undefined }
Compatibility
| Environment | Supported |
|---|---|
| Node.js >= 18 | ✅ |
| TTY Terminal | ✅ |
| Tree Shakeable | ✅ |
License
API Reference§
Filter:
ƒFunctions
Prompts for yes/no confirmation.
Pure functional prompt that asks a yes/no question and returns a boolean. Supports default values and responds to y/Y/n/N keys.
Pure functional prompt that asks a yes/no question and returns a boolean. Supports default values and responds to y/Y/n/N keys.
Parameters
| Name | Type | Description |
|---|---|---|
§config | ConfirmConfig | Confirm prompt configuration |
Returns
Promise<PromptOutcome<boolean>>Promise resolving to boolean value or cancellation
Examples
Basic confirmation
const outcome = await confirm({ message: 'Continue?' })
if (outcome.result === 'submitted' && outcome.value) {
console.log('Proceeding...')
}With default value
const outcome = await confirm({
message: 'Enable feature?',
initial: true, // Default to yes
})Prompts for multiple selections from a list of choices.
Pure functional prompt with arrow key navigation, space to toggle, scrolling support, min/max constraints, and optional type-to-filter search.
Pure functional prompt with arrow key navigation, space to toggle, scrolling support, min/max constraints, and optional type-to-filter search.
Parameters
| Name | Type | Description |
|---|---|---|
§config | MultiselectConfig<T> | Multiselect prompt configuration |
Returns
Promise<PromptOutcome<unknown>>Promise resolving to array of selected values or cancellation
Examples
Basic multiselect
const outcome = await multiselect({
message: 'Select toppings:',
choices: [
{ label: 'Cheese', value: 'cheese' },
{ label: 'Pepperoni', value: 'pepperoni' },
{ label: 'Mushrooms', value: 'mushrooms' },
],
})
if (outcome.result === 'submitted') {
console.log(`You selected: ${outcome.value.join(', ')}`)
}With search and constraints
const outcome = await multiselect({
message: 'Select features:',
choices: features.map((f) => ({ label: f.name, value: f.id })),
searchable: true,
min: 1,
max: 5,
})Pre-selected values
const outcome = await multiselect({
message: 'Select permissions:',
choices: permissions,
initial: [0, 2], // First and third choices pre-selected
})Prompts for single selection from a list of choices.
Pure functional prompt with arrow key navigation, scrolling support, and optional disabled choices.
Pure functional prompt with arrow key navigation, scrolling support, and optional disabled choices.
Parameters
| Name | Type | Description |
|---|---|---|
§config | SelectConfig<T> | Select prompt configuration |
Returns
Promise<PromptOutcome<T>>Promise resolving to selected value or cancellation
Examples
Basic select
const outcome = await select({
message: 'Choose a color:',
choices: [
{ label: 'Red', value: 'red' },
{ label: 'Green', value: 'green' },
{ label: 'Blue', value: 'blue' },
],
})
if (outcome.result === 'submitted') {
console.log(`You chose: ${outcome.value}`)
}With hints and disabled options
const outcome = await select({
message: 'Select plan:',
choices: [
{ label: 'Free', value: 'free', hint: '$0/month' },
{ label: 'Pro', value: 'pro', hint: '$10/month' },
{ label: 'Enterprise', value: 'enterprise', disabled: true },
],
initial: 1, // Start on Pro
})Prompts for text input with optional validation.
Pure functional prompt that reads text from the user with support for default values, input validation, and display formatting.
Pure functional prompt that reads text from the user with support for default values, input validation, and display formatting.
Parameters
| Name | Type | Description |
|---|---|---|
§config | TextConfig | Text prompt configuration |
Returns
Promise<PromptOutcome<string>>Promise resolving to submitted value or cancellation
Examples
Basic text input
const outcome = await text({ message: 'What is your name?' })
if (outcome.result === 'submitted') {
console.log(`Hello, ${outcome.value}!`)
}With validation
const outcome = await text({
message: 'Enter email:',
validate: (value) => {
if (!value.includes('@')) return 'Must be a valid email'
return undefined
},
})Password input with masking
const outcome = await text({
message: 'Password:',
format: (value) => '*'.repeat(value.length),
})◈Interfaces
Choice item for select/multiselect prompts.
Configuration for confirmation prompts.
Configuration for multi-select prompts.
Properties
Outcome when user cancels the prompt.
Base configuration shared by all prompts.
Outcome when user submits a value.
Configuration for single-select prompts.
Properties
◆Types
A prompt function that asks a question and returns a value.
type PromptFunction = (config: TConfig) => Promise<PromptOutcome<TValue>>Outcome of a prompt interaction.
type PromptOutcome = PromptSubmittedOutcome<T> | PromptCancelledOutcome●Variables
const
PromptResultType:
ReadonlyValue:
...