Lightweight terminal UI for React with streaming output, ANSI colors, command history, and AI/LLM mode.
Headless hook + styled component.
- Headless + Styled: Use
useTerminal()hook for full control, or drop in<Terminal>for instant UI - ANSI Colors: Built-in parser for 16/256/RGB colors, bold, italic, underline, strikethrough
- Streaming-First: Async command handlers with
write()andwriteln()for AI/LLM output - Tiny: ~7KB minified, zero dependencies beyond React
- Accessible: ARIA live regions, keyboard navigation, screen reader support
- Command History: Arrow key navigation with deduplication
- Tab Completion: Auto-complete registered command names
- Theming: Dark and light themes, fully customizable via CSS
npm install react-termviewimport{Terminal}from"react-termview";import"react-termview/styles.css";functionApp(){return(<Terminalcommands={{hello: (args)=>`Hello, ${args[0]||"world"}!`,clear: (_args,terminal)=>terminal.clear(),}}/>);}import{useTerminal,Terminal}from"react-termview";import"react-termview/styles.css";functionApp(){constterminal=useTerminal({commands: {greet: (args)=>`Hi ${args[0]}!`,},prompt: "> ",});return(<div><buttononClick={()=>terminal.controls.writeln("System message")}>
Inject Output
</button><Terminalterminal={terminal}/></div>);}<Terminalcommands={{ask: async(args,terminal)=>{terminal.writeln("Thinking...");constresponse=awaitfetchAI(args.join(" "));forawait(constchunkofresponse){terminal.write(chunk);}terminal.writeln("");},}}/>The built-in ANSI parser renders colored text without any extra dependencies:
<Terminalcommands={{status: ()=>"\x1b[32mOK\x1b[0m - All systems operational",error: ()=>"\x1b[1;31mERROR\x1b[0m - Something went wrong",rainbow: ()=>["\x1b[31mR\x1b[33mA\x1b[32mI\x1b[36mN\x1b[34mB\x1b[35mO\x1b[91mW\x1b[0m",].join(""),}}/>Supported: 16 colors, 256 colors (\x1b[38;5;Nm), RGB (\x1b[38;2;R;G;Bm), bold, dim, italic, underline, strikethrough.
| Prop | Type | Default | Description |
|---|---|---|---|
commands | Record<string, CommandHandler> | {} | Command name to handler map |
onUnknownCommand | CommandHandler | — | Called for unregistered commands |
initialLines | TerminalLine[] | [] | Lines to display on mount |
prompt | string | "$ " | Input prompt string |
maxLines | number | 1000 | Max lines in scrollback |
maxHistory | number | 100 | Max command history entries |
editable | boolean | true | Whether input is enabled |
theme | "dark" | "light" | "dark" | Color theme |
title | string | "Terminal" | Title bar text |
showTitleBar | boolean | true | Show/hide title bar |
titleBar | ReactNode | — | Custom title bar content |
terminal | UseTerminalReturn | — | External hook instance |
className | string | — | Additional CSS class |
style | CSSProperties | — | Inline styles |
onLine | (line: TerminalLine) => void | — | Called when a line is added |
Returns UseTerminalReturn with:
| Property | Type | Description |
|---|---|---|
lines | TerminalLine[] | Current terminal output |
input | string | Current input value |
controls | TerminalControls | write(), writeln(), clear(), focus() |
setInput | (value: string) => void | Set input programmatically |
handleKeyDown | KeyboardEventHandler | Attach to input element |
suggestions | string[] | Current tab completion suggestions |
isStreaming | boolean | Whether a command is executing |
inputRef | RefObject<HTMLInputElement> | Ref to the input element |
typeCommandHandler=(args: string[],terminal: TerminalControls,)=>undefined|string|Promise<undefined|string>;Return a string to output it. Use terminal.write() / terminal.writeln() for streaming.
Standalone ANSI parsing utilities:
import{parseAnsi,stripAnsi}from"react-termview";parseAnsi("\x1b[31mred\x1b[0m");// => [{ text: "red", style: { color: "#e74c3c" }}]stripAnsi("\x1b[31mred\x1b[0m");// => "red"| Key | Action |
|---|---|
Enter | Execute command |
ArrowUp/Down | Navigate command history |
Tab | Auto-complete command |
Ctrl+C | Cancel current input |
Ctrl+L | Clear terminal |
Escape | Close suggestions |
Import the default styles and override with CSS:
.rt-terminal {
font-size:14px;
border-radius:12px;
}
.rt-terminal--dark {
background:#0d1117;
color:#c9d1d9;
}All classes use the rt- prefix. See styles.css for the full list.
MIT
