Getting started
OpenTUI is a native terminal UI core written in Zig with TypeScript bindings. The native core exposes a C ABI and can be used from any language. OpenTUI powers OpenCode in production today and will also power terminal.shop. It is an extensible core with a focus on correctness, stability, and high performance. It provides a component-based architecture with flexible layout capabilities, allowing you to create complex terminal applications.
Installation
OpenTUI’s renderer examples use Bun. You can import portable entry points such as @opentui/keymap and
@opentui/core in Node.js without installing Bun or enabling FFI. These imports do not create a native renderer. To
create a native renderer in Node.js, you need Node.js 26.4.0 with experimental FFI enabled.
mkdir my-tui && cd my-tui
bun init -y
bun add @opentui/core
Runtime support
Importing packages does not require native FFI. For example, Node.js can load
await import("@opentui/keymap") and await import("@opentui/core") without --experimental-ffi.
Creating a native renderer requires FFI. This includes calling createCliRenderer() or any other API that loads and calls
OpenTUI’s native Zig renderer. In Node.js, use Node.js 26.4.0 with --experimental-ffi. If you use Node.js permissions,
you must also add --allow-ffi and the filesystem permissions your app needs. OpenTUI does not install Node.js, so select
the required version before you run Node.js-specific examples or scripts.
Hello world
Create index.ts:
import { createCliRenderer, Text } from "@opentui/core"
const renderer = await createCliRenderer({
exitOnCtrlC: true,
})
renderer.root.add(
Text({
content: "Hello, OpenTUI!",
fg: "#00FF00",
}),
)
Run it:
bun index.ts
You should see green text. Press Ctrl+C to exit.
Composing components
Components nest naturally. Here’s a bordered panel with content:
import { createCliRenderer, Box, Text } from "@opentui/core"
const renderer = await createCliRenderer({
exitOnCtrlC: true,
})
renderer.root.add(
Box(
{ borderStyle: "rounded", padding: 1, flexDirection: "column", gap: 1 },
Text({ content: "Welcome", fg: "#FFFF00" }),
Text({ content: "Press Ctrl+C to exit" }),
),
)
Box and Text are factory functions. The first argument is props; additional arguments are children.
What’s next
Core concepts
- Renderer - The rendering engine
- Layout - Flexbox positioning
- Constructs - The declarative component API
Components
Framework bindings
The OpenTUI monorepo includes @opentui/react and @opentui/solid. Other language and framework bindings live in
separate repositories.