OpenTUI: React-Based Terminal UIs with a Zig Rendering Core
OpenTUI is a terminal UI library built on Bun that allows developers to write TUI components in TypeScript using React or Solid.js. The rendering engine is written in Zig and communicates with the JavaScript layer through Bun's Foreign Function Interface (FFI), avoiding the overhead of pure JavaScript rendering.
Why a new TUI library
Ink is the established standard for React-based terminal UIs, used by GitHub Copilot CLI, Cloudflare Wrangler, and Prisma's CLI. Two characteristics make it unsuitable for high-throughput applications:
Memory usage. Applications built with Ink typically consume over 50MB of RAM due to Node.js runtime overhead and React's reconciliation process operating in a terminal context.
Frame rate cap. Ink throttles rendering to 32 FPS.
For applications streaming large amounts of output continuously (coding agent output, log viewers), 32 FPS produces visible sluggishness. OpenTUI was built by Anomaly (the team behind OpenCode) to address these limitations for their rewrite from Go/Bubble Tea to TypeScript.
Architecture
Zig core. The rendering engine, layout manager, and event processor are written in Zig. This handles drawing to the terminal, managing the Flexbox layout (via the Yoga engine), and processing keyboard events.
TypeScript bindings. Application components are written in TypeScript with React or Solid.js. The standard component model, hooks, and state management all work as expected.
Bun FFI. Bun's FFI connects the TypeScript layer to the Zig core with near-zero overhead.
This removes the performance ceiling imposed by pure JavaScript rendering. React components communicate with the Zig core at native speed.
Project setup
OpenTUI requires the Bun runtime.
Scaffold a new project:
The wizard asks for a project name and a template. Available templates: Core (no framework), React, Solid, or a custom GitHub URL. The following examples use the React template.
Initial project structure
The generated src/index.tsx:
The primitive components (<box>, <text>, <ascii-font>) replace HTML elements. Layout props (alignItems, justifyContent, flexGrow, flexDirection) work like CSS Flexbox via the Yoga engine.
createCliRenderer() initializes the Zig rendering engine. createRoot(renderer).render(<App />) is the equivalent of ReactDOM.createRoot(...).render(<App />) for the terminal.
Interactive input
React's useState integrates with OpenTUI's input component directly.
onInput={setName} fires with the current input value on each keystroke. focused gives the field focus on mount. The <box border title="Name"> wrapper renders a bordered container with a title label.
Animations with useTimeline
OpenTUI provides a useTimeline hook for frame-accurate animations. The following example fades and slides in a greeting after the user submits the input form.
offset and opacity are React state values applied as component props. timeline.add() defines start values, end values, easing, and an onUpdate callback that receives interpolated values on each frame. The callback updates state, which causes React to re-render the component with the new prop values. This produces smooth motion at the Zig core's frame rate.
To wire this into the form, add a submitted state and conditional rendering:
onSubmit fires when the user presses Enter.
Comparison with alternatives
vs. Ink. OpenTUI removes the 32 FPS cap and reduces memory overhead. The developer experience is similar since both use React, but OpenTUI requires Bun rather than Node.js.
vs. native libraries (Bubble Tea, Ratatui). Go and Rust libraries produce smaller binaries and have marginally better raw performance, but they require learning a different language and UI paradigm. OpenTUI delivers sufficient performance for demanding TUIs while staying in the TypeScript/JSX ecosystem.
Final thoughts
OpenTUI is most valuable for teams already working in TypeScript who need a TUI with real-time output or interactive components where Ink's frame rate cap creates a visible problem. The React component model, familiar hooks, and Flexbox layout make the transition from web to terminal UI development straightforward.
For simpler CLIs that display static output or have minimal interaction, Ink remains a reasonable choice with a larger ecosystem and more community resources. OpenTUI's Bun dependency is also a consideration for projects that need to run in environments where only Node.js is available.
Source code and documentation are at github.com/opentui/opentui.