@ismail-elkorchi/terminal-ui
v0.1.5
Published
Typed terminal UI framework for prompts, full-screen apps, accessible components, deterministic rendering, and testing.
Maintainers
Readme
@ismail-elkorchi/terminal-ui
Build typed prompts and full-screen terminal applications from the same component, layout, input, accessibility, and testing foundations.
terminal-ui is ESM-only, has no runtime dependencies, and supports Node
>=24, current Deno and Bun, and memory-backed tests.
The 0.1.x line is a development release. Public declarations are marked
stable, beta, or experimental in the generated
API reference. Terminal graphics remain
experimental pending physical-terminal compatibility evidence.
Install
Node:
npm install @ismail-elkorchi/terminal-uiBun:
bun add @ismail-elkorchi/terminal-uiDeno:
deno add jsr:@ismail-elkorchi/terminal-uiUse the root entrypoint for ordinary applications. Focused entrypoints such as
/prompts, /testing, /theme, and /component keep specialized APIs
discoverable without requiring private imports.
Run a Prompt
import { input, runPrompt } from '@ismail-elkorchi/terminal-ui/prompts';
const result = await runPrompt(input({
label: 'Project name',
required: true
}));
if (result.status === 'submitted') {
console.log(result.value);
} else {
console.error(`Prompt ${result.reason}`);
}Cancellation, validation failure, timeout, non-TTY denial, and host failure are typed results rather than ordinary control-flow exceptions.
Build a TUI
Applications own state. Components render that state and emit typed messages;
update() is the only place that changes it.
import {
button,
column,
defineTui,
runTui,
text
} from '@ismail-elkorchi/terminal-ui';
interface State {
readonly count: number;
}
type Message =
| { readonly kind: 'increment' }
| { readonly kind: 'quit' };
const app = defineTui<State, Message>({
id: 'counter',
init: () => ({ state: { count: 0 } }),
update: (state, message) => {
if (message.kind === 'quit') {
return { state, exit: { reason: 'quit' } };
}
return { state: { count: state.count + 1 } };
},
view: (state) => column([
text({ content: `Count: ${String(state.count)}` }),
button({
id: 'increment',
label: 'Increment',
onPress: (): Message => ({ kind: 'increment' })
}),
button({
id: 'quit',
label: 'Quit',
onPress: (): Message => ({ kind: 'quit' })
})
])
});
const exit = await runTui(app);
if (exit.status === 'interrupted') {
console.error('The terminal session was interrupted.');
}Save this as counter.ts and run it with node counter.ts,
deno run counter.ts, or bun counter.ts. Use Tab and Shift+Tab to move
focus and Enter to activate a button.
runTui() resolves for application completion, cancellation, and host
interruption. Operational failures reject with TuiRunError, whose exit
contains diagnostics and the final accessible snapshot.
Compose the Interface
- Layout factories such as
column(),row(),grid(),surface(), andviewport()own geometry. - Components own interaction and accessibility while application state remains controlled by the caller.
- The
behaviornamespace provides pure reducers, retained collections, and indexes for editing, keyboard and pointer text selection, paste, navigation, scrolling, and large data. - Semantic themes adapt to terminal color capabilities; top-level component
stylesprovide typed local anatomy and state overrides. - Effects and subscriptions perform asynchronous work outside the serialized state transition.
Start with Building terminal apps, then use the component catalog, layout guide, and theme guide as the application grows.
Test Without a Terminal
import { text } from '@ismail-elkorchi/terminal-ui';
import { renderElementSnapshot } from '@ismail-elkorchi/terminal-ui/testing';
const snapshot = renderElementSnapshot({
element: text({ content: 'Ready' }),
terminalSize: { columns: 20, rows: 2 }
});
if (!snapshot.plainTextFrame.includes('Ready')) {
throw new Error('Expected rendered text.');
}The testing entrypoint also provides controlled clocks, input and resize scripts, frames, diffs, accessibility snapshots, transcripts, and PTY-style harnesses.
Documentation
- Documentation map
- Prompts
- Building terminal apps
- Components
- Layout
- Themes
- Testing harness
- Runtime support
- API stability
- API overview and entrypoints
- Generated API reference
Runnable applications are in examples. Reusable component authors can continue with Component definitions.
terminal-ui owns terminal interaction. Argument parsing, command trees,
configuration, application persistence, networking, and plug-in semantics
remain application concerns.
