Skip to content

Repository files navigation

TextUI

npm node dependencies license

A dependency-free TypeScript terminal UI runtime. Screens are plain data; JSX is one way to write them.

npm install @textui/kit
import { Box, Text, render, useInput, useState } from '@textui/kit';

function Counter() {
  const [count, setCount] = useState(0);

  useInput((e) => {
    if (e.name !== '+') return false;

    setCount((c) => c + 1);
    return true;
  });

  return (
    <Box border="round" padding={1} direction="column">
      <Text bold>Count: {count}</Text>
      <Text dim>+ to increment, ctrl+c to quit</Text>
    </Box>
  );
}

const { waitUntilExit } = render(<Counter />);
await waitUntilExit();

Status: pre-1.0. The surface is still moving.

A quick taste

Let's cut to the chase, shall we?

TextUI dark theme

TextUI can go from a small interactive prompt to a full-screen terminal application.

Get startedRead the documentation

The one idea

JSX compiles to data.

<Row gap={1}>
  <Text>Hello</Text>
</Row>

and:

{
  component: 'Row',
  gap: 1,
  children: [
    { component: 'Text', children: ['Hello'] }
  ]
}

describe the same screen.

A screen can be written in TypeScript, loaded from JSON, generated, edited or sent over a wire without the runtime changing.

Everything else follows from that: one reactive store addressed by paths, typed registries for components, commands, themes, shells and resources, and a renderer that diffs cells rather than redrawing frames.

Start with @textui/kit

One package is enough to have something on screen:

npm install @textui/kit
# pnpm add @textui/kit

@textui/kit is the runtime, a terminal to put it on, and render.

Box, Text, the hooks and render all come from here. The example above needs nothing else.

render() mounts the application and returns a handle immediately:

const { app, waitUntilExit } = render(<App />);
await waitUntilExit();
On the handle What it does
app Commands, themes, focus, the store — everything hello world did not need
waitUntilExit() Resolves when the application stops, however it stopped
unmount() Stops the app, puts the terminal back, resolves waitUntilExit()
rerender(node) Swaps the root

For one frame and no terminal — a report, --help, a test — use renderOnce or renderToString instead.

Those return. render() runs.

Add the component catalog

For Panel, Table, Row, Column, charts, overlays, forms and the rest of the catalog, add @textui/widgets:

npm install @textui/widgets
# pnpm add @textui/widgets

Components imported directly can be used directly:

import { Badge, Card } from '@textui/widgets';

function Status() {
  return (
    <Card title="Server">
      <Badge label="Online" tone="success" />
    </Card>
  );
}

Nothing to register.

When a screen names components in data, a string has to resolve to something. That is the case that needs the registry:

import { render } from '@textui/kit';
import { registerBuiltins } from '@textui/widgets';

render(<Dashboard />, {
  onBoot: registerBuiltins,
});

Forget it and nothing throws. The name resolves to nothing, and TextUI draws the name itself in red where the component should have been:

$ node dashboard.js
<Card>

That red <Card> on screen is the error message: a missing registration, not a missing import.

Or start with the CLI

For a project set up for you, and for components copied into your source rather than imported:

npx @textui/cli init
# pnpm dlx @textui/cli init

And when something renders wrong:

npx @textui/cli doctor

doctor tells you what this terminal can actually do: Unicode level, colour depth, keyboard protocol and the capabilities TextUI detected.

Packages

All six published packages use the same version and depend only on each other.

Package Version What it is Source
@textui/kit npm One install: the runtime, a terminal and render. Start here. packages/facade
@textui/core npm The runtime: store, registries, renderer, hooks and the four host primitives packages/core
@textui/widgets npm Component catalog: layout, display, controls, data, overlays and charts packages/widgets
@textui/terminal npm Terminal adapters, capability detection, ANSI writing and input decoding packages/terminal
@textui/testing npm Headless harness: semantic queries, input, resizing and time packages/testing
@textui/cli npm textui init / add / create / doctor, and primitives for your own CLI packages/cli

Also in the repository

Not published yet:

Project What it is
@textui/documents Document buffers, resource viewers and content adapters
@textui/textide An IDE that runs in a terminal, built on TextUI
@textui/textide-git Git for TextIDE, as a loadable extension
components/ The source-copy registry — components you own, not import
playground/ The showcase, focused playgrounds and a filesystem explorer

Zero dependencies

Nothing third-party is installed alongside it.

@textui/core has an empty dependencies field, and the packages above it depend only on each other — so what you audit is what you get, and the tree does not grow behind your back.

That also keeps the source close to running unbuilt. Node has erased types by default since 23.6, and most of this codebase is already erasable syntax.

The full argument, and what is still in the way, is in DEVELOPER.md.

Requirements

Node >= 22, or Bun — the packages are plain ESM with no native code, and run on either.

TypeScript is how the examples are written rather than something TextUI needs. For TSX:

{
  "compilerOptions": {
    "jsx": "react-jsx",
    "jsxImportSource": "@textui/kit"
  }
}

See Getting started.

Documentation

Published at softov.github.io/textui and readable in docs/ as plain Markdown.

Start here:

Document What it answers
Getting started From nothing to a running application
The vocabulary The words everything else assumes
Architecture The model: store, graph, registries, surfaces, shells
Decisions and tradeoffs What was chosen, and what it cost

Then by subsystem:

Section What it covers
Store Paths, scopes, computed, collections, providers, events
Components The catalog, how to write one, and the templates
Themes Tokens, glyphs, borders, capability downgrade, syntax
Platform Commands, keybindings, focus, layers, screens, extension points
Terminal Adapters, capabilities, managed and embedded sessions
Documents Resource kinds, providers, viewers, editors, buffers
CLI The developer CLI and the registry model
Testing The harness, and what to assert

Themes

dark

TextUI dark theme

light

TextUI light theme

console

TextUI console theme

paper-dark

TextUI paper-dark theme

paper

TextUI paper-light theme

workbench

TextUI workbench theme

mono

TextUI mono theme

Developing

Working on TextUI rather than with it — building, testing, the playgrounds, the docs site and how a release is cut — is in DEVELOPER.md.

License

MIT

About

A dependency-free TypeScript terminal UI runtime. Screens are plain data; JSX is one way to write them.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages