Terminal

Pro

A command line for your app: a title bar, a monospace scrollback and a prompt with ghost completion and a block cursor. Presentational parts on the theme's tokens; your app runs the commands, so it fits a dev console, a search console or a REPL alike.

Koala shell
Koala shell 1.0
Type 'help' to see the commands. Tab completes, ↑ ↓ walk the history.
PS C:\Users\koala>
Tab complete↑↓ historyEsc clear the line

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Activate your Pro license (once per machine)npx koalaui-cli@latest login <key># Add this component (its dependencies come along)npx koalaui-cli@latest add terminal

Usage#

The parts paint; the loop is yours. A working shell is a list of lines, the text being typed, and a key handler that turns Enter into output.

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Anatomy#

import {  Terminal,  TerminalBar,  TerminalCaption,  TerminalCaptionButton,  TerminalControls,  TerminalField,  TerminalIndicator,  TerminalInputLine,  TerminalLine,  TerminalPrompt,  TerminalScreen,  TerminalTab,  TerminalTitle,  TerminalTitleTag,  TerminalTray,  TerminalWatermark,} from "@/components/ui/terminal"<Terminal>  {/* A faint stamp behind the scrollback */}  <TerminalWatermark />  {/* The title bar, and the drag handle */}  <TerminalBar>    {/* A tab, or the indicator and title straight in the bar */}    <TerminalTab>      <TerminalIndicator />      <TerminalTitle>        <TerminalTitleTag />      </TerminalTitle>    </TerminalTab>    <TerminalControls />    {/* Minimize, maximize, close: flush in the corner */}    <TerminalCaption>      <TerminalCaptionButton action="minimize" />    </TerminalCaption>  </TerminalBar>  {/* The scrollback, a ScrollArea */}  <TerminalScreen>    <TerminalLine />    <TerminalInputLine>      <TerminalPrompt />      <TerminalField />    </TerminalInputLine>  </TerminalScreen>  {/* Live results, suggestions, a status line */}  <TerminalTray /></Terminal>

Line tones#

tone sets a line's ink. in is a command that was run, in the foreground ink; out (the default) and raw are output in the reading ink; dim is a comment in the meta grey; err and ok take the status hues' text step, which still reads on the light themes.

ci $ npm test
# 3 suites, 41 tests
PASS components/button.test.tsx
PASS components/terminal.test.tsx
FAIL components/chart.test.tsx: expected 12 bars, got 11
Tests: 1 failed, 40 passed, 41 total
Snapshots: 18 passed

Clickable lines#

Give a line onClick and it becomes a button: focusable, run by a click, Enter or Space, with a highlight that keeps the text on its column. For search results, a file listing, or a #N the user would otherwise have to type.

DISPATCH> units --active
# CALL SIGN STATUS
1 ADAM-12 Available
2 LINCOLN-4 En route
3 MARY-7 On scene
Click a unit, or Tab to it and press Enter.

Prompt, completion and cursor#

TerminalPrompt takes a prefix and a mark ("> " by default). TerminalField paints what is typed and a block cursor at the caret: it follows the arrow keys and sits over the character it is on. ghost is the grey completion after it; accepting it is your key handler's job (Tab or → here, at the end of the line). The cursor is a solid block while the field has focus and a hollow cell when it doesn't; drive cursorVisible from a timer to make it blink.

koala λ

A blink that restarts lit on every keystroke, and holds still under reduced motion:

This example is part of Koala UI Pro

The preview is yours to explore. Its code comes with a Pro license, paid once and used in every project.

Have a license? Unlock it here

Tray#

TerminalTray is the band under the scrollback, on a quieter tint: live results while the user types, suggestions, a status line. It holds Koala components (a Badge, a Kbd, a Command list) or clickable TerminalLines, as here.

Type a name: the matches show up under the scrollback.
FIND>
#1Ada LovelaceAL-1815
#2Alan TuringAT-1912
#3Hedy LamarrHL-1914
db #
postgres · 20 rows · 4 msEnter run

Window chrome#

TerminalBar carries the TerminalIndicator, a TerminalTitle (with an optional TerminalTitleTag), TerminalControls for your own 32px buttons, and TerminalCaption: Windows' minimize, maximize and close, 46px wide and flush in the corner, close going red on hover. What they do is yours: here they minimize, widen and close the window, and a double-click on the bar widens it too. movable gives the bar a grab cursor and dragging holds the grabbing one while your pointer handlers move the window. TerminalWatermark lays a faint stamp behind the scrollback.

Buildproduction
ci $ npm run build
â–˛ Next.js 16.3.6
Creating an optimized production build…
âś“ Compiled successfully in 14.2s
Collecting page data and generating 412 static pages
âś“ Done in 41.8s

API reference#

Terminal

The surface, a div: a Windows-style window (8px corners, popover fill, the lg shadow) every part reads its styles from. Every part is optional but the root. Forwards every div prop; every part merges className last. terminalVariants is the recipe.

PropTypeDefaultDescription
movablebooleanfalseThe bar shows a grab cursor. Moving the window is your pointer handler on TerminalBar.
draggingbooleanfalseThe grabbing cursor, and no text selection while it lasts.
Data attributeDescription
data-slot"terminal".
CSS variableDescription
--surfaceSet to var(--popover), so controls nested inside paint the panel's ground.

TerminalBar

The title bar, a div, and the drag handle: hang onPointerDown on it. Drop it for a console embedded in a page.

Data attributeDescription
data-slot"terminal-bar".

TerminalTab

A tab in the title bar, a div, the way Windows Terminal draws one: put a TerminalIndicator and a TerminalTitle inside. The open tab merges into the screen below it.

PropTypeDefaultDescription
activebooleantrueThe open tab: the screen's fill and a hairline frame. Inactive tabs sit back in the strip in muted ink.
Data attributeDescription
data-slot"terminal-tab".
data-activeThe active prop.

TerminalIndicator

The live dot before the title, a decorative span (aria-hidden).

Data attributeDescription
data-slot"terminal-indicator".

TerminalTitle

The title, a span that ends a long title in an ellipsis.

Data attributeDescription
data-slot"terminal-title".

TerminalTitleTag

The title's secondary label, a span after a middle dot. Goes inside TerminalTitle.

Data attributeDescription
data-slot"terminal-title-tag".

TerminalControls

The window buttons at the end of the bar, a div. Controls inside default to the sm tier (32px); an explicit size still wins.

Data attributeDescription
data-slot"terminal-controls".
data-control-size"sm".

TerminalCaption

The window buttons, a div flush in the bar's top-right corner: the window's corner clips the last button's fill. Goes last in TerminalBar, after TerminalControls if there are any.

Data attributeDescription
data-slot"terminal-caption".

TerminalCaptionButton

A 46 by 40 window button, a button with the Windows hairline glyph and an aria-label from its action (override either). Wire onClick yourself: the window geometry is your app's.

PropTypeDefaultDescription
action*"minimize" | "maximize" | "restore" | "close"-Which button: its glyph and its label. close fills red on hover. The type is exported as TerminalCaptionAction.
childrenReact.ReactNode-Replaces the glyph.
Data attributeDescription
data-slot"terminal-caption-button".
data-actionThe action prop.

TerminalScreen

The scrollback, on ScrollArea: takes its props but the axis (orientation and draggable are left out). Its content is a role="log", so assistive tech announces new lines.

PropTypeDefaultDescription
fadebooleanfalseFades the edge that still has content beyond it.
viewportRefReact.Ref<HTMLDivElement>-The scrolling element itself: use it to keep the scrollback at the bottom.
type"auto" | "always" | "scroll" | "hover""hover"When the scrollbars show, as on ScrollArea.
Data attributeDescription
data-slot"terminal-screen", on the log inside the scroller.

TerminalWatermark

A faint stamp behind the scrollback (a logo, a seal), a decorative img (aria-hidden, not draggable). Set its opacity with style. Forwards every img prop.

PropTypeDefaultDescription
altstring""Empty by default: the image is decorative.
Data attributeDescription
data-slot"terminal-watermark".

TerminalLine

One line of the scrollback, a div that wraps long text. It needs no Terminal around it. terminalLineVariants({ tone, interactive, className }) returns a line's classes for your own markup.

PropTypeDefaultDescription
tone"in" | "out" | "err" | "ok" | "dim" | "raw""out"The line's ink. The type is exported as TerminalTone.
onClick(e: React.MouseEvent<HTMLDivElement> | React.KeyboardEvent<HTMLDivElement>) => void-Makes the line a role="button" in the tab order, run by click, Enter or Space.
Data attributeDescription
data-slot"terminal-line".
data-toneThe line's tone.

TerminalInputLine

The prompt row, a div: the prompt and the field on one baseline. Keep it last in the screen so the prompt scrolls with the output, the way a shell does.

Data attributeDescription
data-slot"terminal-input-line".

TerminalPrompt

The prompt, a span: the prefix in full-weight ink, then the mark.

PropTypeDefaultDescription
prefix*React.ReactNode-What comes before the mark: the system, the host, the unit.
markReact.ReactNode"> "The prompt mark. Keep its trailing space.
Data attributeDescription
data-slot"terminal-prompt", with terminal-prompt-prefix and terminal-prompt-mark inside.

TerminalField

The prompt's field: painted text with a block cursor at the caret, under a transparent <input> that takes the keyboard. Every input prop goes to that input, className and ref included; spellcheck, autocomplete, autocapitalize and autocorrect are off unless you turn them on.

PropTypeDefaultDescription
value*string-The controlled text.
ghoststring-The grey completion painted after the caret when it is at the end. Your key handler accepts it, usually on Tab.
cursorVisiblebooleantrueThe blink beat while focused: drive it from a timer to blink, leave it true for a steady cursor. Out of focus the cursor is a still, hollow cell.
placeholderstring-Painted in the ghost's grey while the field is empty.
Data attributeDescription
data-slot"terminal-field" on the wrapper, "terminal-input" on the input, "terminal-cursor" on the cursor.
data-visibleOn the cursor: the cursorVisible beat.

TerminalTray

The band under the scrollback, a div: live results, suggestions, a status line. Drop it when nothing runs live.

Data attributeDescription
data-slot"terminal-tray".

FAQ#

Command filters a fixed list and runs the row you pick. Terminal runs whatever is typed and keeps a transcript. They combine: a Command list in the tray makes a fine live preview.