Skip to content
ztui

ztui

Build terminal UIs with React. Run the same widget tree in a terminal or a browser canvas.

Declarative React

Write JSX with state and hooks. A custom React reconciler commits your tree to a widget DOM that lays out and renders into a grid of styled cells.

Two backends, one tree

The same widgets render to a terminal (ANSI diff) or a browser <canvas> (hardware-accelerated). The cell grid is the portable hand-off.

Batteries included

Dozens of built-in widgets — tables, trees, inputs, forms, markdown, diffs, sparklines, terminals — built on modern terminal features: mouse capture, the system clipboard, hyperlinks, and desktop notifications.

Graphics with graceful fallback

Inline images via Kitty / iTerm2 / Sixel, degrading to Unicode block art — chosen automatically from probed terminal capabilities.

Extensible

Subclass Widget to build your own, registered in one call. The widget layer is framework-agnostic — use the React binding, or write your own for Solid, Vue, or anything else.

AI-native & testable

The DOM and rendered buffer serialize to JSON / HTML / text; headless drivers and a REST inspector let agents and CI see and assert on the UI.

// app.tsx — run with: bun run app.tsx
import { useState } from "react";
import { App } from "@huyz0/ztui";
import { Button, Label, render, VBox } from "@huyz0/ztui/react";
function Counter() {
const [count, setCount] = useState(0);
return (
<VBox style={{ width: 40, height: 10, align: "center", verticalAlign: "middle" }}>
<Label style={{ bold: true, color: "cyan" }}>Count: {count}</Label>
<Button onClick={() => setCount(count + 1)} style={{ background: "blue", color: "white" }}>
Increment
</Button>
</VBox>
);
}
const app = new App();
render(<Counter />, app.activeScreen);
app.run();

A few of the built-ins — see the full gallery for ~60 more.

ztui is MIT licensed — free for personal and commercial use.