OpenTUI Python
A Pythonic port of OpenTUI — build rich terminal UIs in Python with reactive signals, flexbox layout, and a full component library.
OpenTUI is the rendering engine behind OpenCode. This package brings that same engine to Python: the native Zig core handles rendering and layout, while the Python layer provides an idiomatic API with signals, components, hooks, and async rendering.
Disclaimer: This is an independent community project. It is not affiliated with, endorsed by, or connected to OpenTUI, OpenCode, or Anomaly in any way. OpenTUI is developed by the anomalyco/opentui team and is used here under its MIT license.
Features
- Reactive signals — fine-grained reactivity with
Signal,computed,effect, andExproperators - Flexbox layout — powered by Yoga via yoga-python
- Rich components —
Box,Text,Input,Textarea,Select,ScrollBox,Markdown,Code,Diff, and more - Native performance — Zig core with nanobind C++ bindings for rendering-critical paths
- Full input handling — keyboard, mouse, and paste events
- Image support — Kitty and SIXEL graphics protocols
- Syntax highlighting — Tree-sitter integration for code blocks
- 4,700+ tests — comprehensive parity with the OpenTUI core test suite
Installation
pip install opentui
With optional extras:
pip install opentui[images] # Pillow for image support
pip install opentui[highlighting] # Tree-sitter syntax highlighting
pip install opentui[dev] # pytest, ruff, ty
Quick Start
import asyncio
from opentui import render, Box, Text, Signal, component, use_keyboard, use_renderer
count = Signal(0, name="count")
@component
def App():
return Box(
Text(lambda: f"Count: {count()}"),
Text("Press +/- to change, q to quit"),
padding=2, border=True, gap=1,
)
def on_key(event):
if event.name == "q":
use_renderer().stop()
elif event.name in ("+", "="):
count.add(1)
elif event.name == "-":
count.add(-1)
async def main():
use_keyboard(on_key)
await render(App)
asyncio.run(main())
Reactive Patterns
OpenTUI provides three tiers of reactivity — choose the simplest one that fits:
Direct signal prop — pass a Signal directly to any supported prop for zero-overhead updates:
color = Signal("red", name="color")
Text("Hello", fg=color) # updates paint when color changes
Lambda / callable — use a lambda for computed or derived values:
count = Signal(0, name="count")
Text(lambda: f"Count: {count()}")
.map() transform — transform a signal's value without a full lambda:
Text(count.map(lambda v: f"Count: {v}"))
Expr operators — signals support arithmetic and comparison operators that return reactive expressions:
doubled = count * 2 # Expr: evaluates to count() * 2
is_high = count > 5 # Expr: evaluates to count() > 5
label = count.if_("yes", "no") # Conditional: "yes" if truthy, "no" otherwise
Batch updates — group multiple signal writes into a single notification pass:
from opentui import Batch
with Batch():
x.set(1)
y.set(2) # subscribers only fire once, after the block
Control Flow
Conditional and list rendering with Show, Switch, Match, and For:
from opentui import Show, Switch, Match, For, Signal
visible = Signal(True, name="visible")
mode = Signal("home", name="mode")
items = Signal(["a", "b", "c"], name="items")
# Conditional rendering
Show(Text("Visible!"), when=visible)
Show(Text("Visible!"), when=visible, fallback=Text("Hidden"))
# Multi-branch conditional
Switch(
Match(HomePage(), when=mode.map(lambda m: m == "home")),
Match(Settings(), when=mode.map(lambda m: m == "settings")),
fallback=Text("Not found"),
)
# Signal-keyed switch (fast path — no re-subscription on change)
Switch(on=mode, cases={
"home": HomePage(),
"settings": Settings(),
})
# List rendering
For(lambda item, i: Text(f"{i}: {item}"), each=items)
Components
Use @component to define reusable components. Each invocation gets its own reactive scope:
from opentui import component, Signal, Box, Text
@component
def Counter(label: str = "Count"):
count = Signal(0, name="count")
return Box(
Text(count.map(lambda v: f"{label}: {v}")),
border=True,
)
For lower-level control, use Mount directly:
from opentui import Mount, Signal, Text
counter = Mount(lambda: Text(Signal(0, name="n").map(str)))
Layout
| Component | Description |
|---|---|
Box |
Flexbox container with border, padding, background |
ScrollBox |
Scrollable container with mouse wheel support |
Text
| Component | Description |
|---|---|
Text |
Styled text with wrapping, selection, and inline modifiers |
Bold, Italic, Underline |
Inline text style modifiers |
Span |
Colored inline text spans |
Link |
Clickable terminal hyperlinks |
Input
| Component | Description |
|---|---|
Input |
Single-line text input |
Textarea |
Multi-line editor with native buffer, undo/redo, and syntax highlighting |
Select |
Dropdown selection list |
Advanced
| Component | Description |
|---|---|
Code |
Syntax-highlighted code block via Tree-sitter |
Diff |
Side-by-side and unified diff viewer |
Markdown |
Rendered markdown with headings, lists, tables, code blocks |
LineNumberRenderable |
Line number gutter (pairs with Code or Textarea) |
Slider |
Numeric value slider |
TabSelect |
Tab selection bar |
TextTable |
Tabular text layout with borders |
Control Flow
| Component | Description |
|---|---|
For |
Keyed list rendering with efficient reconciliation |
Show |
Conditional rendering |
Switch / Match |
Multi-branch conditional rendering |
Lazy |
Deferred child construction (built on first render) |
Portal |
Render children into a different mount point |
Dynamic / MemoBlock |
Dynamic node selection and memoized subtrees |
Signals
from opentui import Signal, computed, effect
name = Signal("world", name="name")
greeting = computed(lambda: f"Hello, {name()}!")
effect(lambda: print(greeting())) # prints "Hello, world!"
name.set("Python") # prints "Hello, Python!"
Hooks
from opentui import use_keyboard, use_mouse, use_paste, use_on_resize, use_timeline
use_keyboard(lambda event: print(event.name))
use_mouse(lambda event: print(event.type, event.x, event.y))
use_paste(lambda event: print(event.text))
use_on_resize(lambda cols, rows: print(f"{cols}x{rows}"))
timeline = use_timeline()
timeline.add(target, {"opacity": 1.0}, duration=300)
Development
git clone https://github.com/banditburai/opentui-python.git
cd opentui-python
uv sync --all-extras
# Run tests
uv run pytest tests/ -v
# Lint & type checking
uv run ruff check
uv run ruff format --check
uv run ty check
Test coverage
The test suite includes 4,700+ tests: a comprehensive 1:1 port of the OpenTUI core test suite plus Python-specific tests for signals, FFI bindings, and the reconciler.
Architecture
The package is a hybrid: the OpenTUI Zig core handles rendering, text buffers, and layout at native speed, while the Python layer implements the component model, signals runtime, reconciler, and public API. Performance-critical paths are additionally accelerated with nanobind C++ extensions.
OpenTUI Core (Zig) → libopentui.so/dylib
↓
nanobind C++ bindings (opentui_bindings)
↓
Python API (opentui)
├── signals — Signal, computed, effect, Expr operators
├── components/ — Box, Text, Input, ScrollBox, Code, Diff, ...
├── hooks — use_keyboard, use_mouse, use_paste, use_on_resize
├── renderer — CliRenderer, Buffer, TerminalCapabilities
├── reconciler — Component tree diffing (idiomorph-inspired)
└── layout — Yoga flexbox integration via yoga-python
What's native vs. Python:
- Native (Zig via nanobind): text buffers, edit buffers, editor views, hit testing, graphics encoding, buffer rendering, syntax styling
- C++ extensions: signal→prop bindings, reconciler patching, render tree dispatch
- Python: signals runtime, component tree, event loop, input parsing, all public API
Pre-built wheels are provided for Linux (x86_64, aarch64), macOS (x86_64, arm64), and Windows (x64) on Python 3.12+.
License
MIT — see LICENSE.
OpenTUI core is also MIT licensed. yoga-python is MIT licensed.
Metadata
Release files for opentui 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| opentui-0.1.2.tar.gz | 804.4 kB | Details |
Built distributions (wheels)
Total release size: 17.4 MB
Release files / opentui-0.1.2.tar.gz
| Download URL | opentui-0.1.2.tar.gz |
|---|---|
| Size | 804.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7f3035dabf92b115c62b4a5e53806af1cf528a172406035c7344ab69656ed0ac
|
|
BLAKE2b-256 checksum How to use checksums |
dc98c061d65ce35b48ce4e72a064bca29beb361a39d1a1dd47c56d8ef0297f1c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp313-cp313-win_amd64.whl
| Download URL | opentui-0.1.2-cp313-cp313-win_amd64.whl |
|---|---|
| Size | 827.5 kB |
| Tags | CPython 3.13 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
c9ec59c0e8b0c49401b816f4fa7d9e9f6389f5c575b61643b01b98c013deb7a8
|
|
BLAKE2b-256 checksum How to use checksums |
9a6d49d985d413b319e7fffcc655764f781c5701aaab5cd4be1f57cd29dcfd33
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp313-cp313-manylinux_2_28_x86_64.whl
| Download URL | opentui-0.1.2-cp313-cp313-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.0 MB |
| Tags | CPython 3.13 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
b2b74edce084d0decd430f7c7ab3f0b8d2869ff2afe64ac177dc63daf91463ad
|
|
BLAKE2b-256 checksum How to use checksums |
4455f31ec925663dcffc4c303acbd29c2ba80055f6870ec1b24091f00f08f336
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp313-cp313-manylinux_2_28_aarch64.whl
| Download URL | opentui-0.1.2-cp313-cp313-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.13 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
4a32829220e450316b3bfca2a08c5752c3d24fc02df8e2866e49bc6e2909eb74
|
|
BLAKE2b-256 checksum How to use checksums |
b8001a22b74143f4a9475dffae35ffa3313ddaeefd0eecf33e7b22d07c375e1d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp313-cp313-macosx_13_0_x86_64.whl
| Download URL | opentui-0.1.2-cp313-cp313-macosx_13_0_x86_64.whl |
|---|---|
| Size | 781.9 kB |
| Tags | CPython 3.13 macOS 13.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
b922add2291067eb9c6c08c1bfc05a1a86b93c7ff1de110cd4a56bed647410ce
|
|
BLAKE2b-256 checksum How to use checksums |
fb998a61e75fe193620d3eb7cfc47377f8c1392cc68e98720ccc3d8292a0f0a8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp313-cp313-macosx_13_0_arm64.whl
| Download URL | opentui-0.1.2-cp313-cp313-macosx_13_0_arm64.whl |
|---|---|
| Size | 756.6 kB |
| Tags | CPython 3.13 macOS 13.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
769e92eba6d21dda77eb048577bd8a36882e4af090ae0bfeceda7b53cbbfbb04
|
|
BLAKE2b-256 checksum How to use checksums |
ad6333c1ef02c01e0dd535644bdd503049c1d7d7015ace1fad0bbec434c6a30d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp312-cp312-win_amd64.whl
| Download URL | opentui-0.1.2-cp312-cp312-win_amd64.whl |
|---|---|
| Size | 827.5 kB |
| Tags | CPython 3.12 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
40dbcf11a28ad40d8de69e98a1c6527b501e8f43d1e9a2dd14705b51bc0d94d1
|
|
BLAKE2b-256 checksum How to use checksums |
98c5691929f908dcc5e064c77779794c6afd2de2b43a88279db51bb6cadb39a5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp312-cp312-manylinux_2_28_x86_64.whl
| Download URL | opentui-0.1.2-cp312-cp312-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 3.0 MB |
| Tags | CPython 3.12 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
f844fe714a166a9c712634c1de363a69ffdf9a407890f7a5330dbc3bbaaaebda
|
|
BLAKE2b-256 checksum How to use checksums |
0aea82ab48bd93250d5ee8266bac5f437dd4ad08f4e5b9230cb5321ab521563b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp312-cp312-manylinux_2_28_aarch64.whl
| Download URL | opentui-0.1.2-cp312-cp312-manylinux_2_28_aarch64.whl |
|---|---|
| Size | 2.9 MB |
| Tags | CPython 3.12 Linux glibc 2.28+ ARM64 |
|
SHA-256 checksum How to use checksums |
24d726d0ba359ad95587519f02fccc33f8d1d376fac02741dd58f89f9e971d5a
|
|
BLAKE2b-256 checksum How to use checksums |
0538f8a4f23d96bd4d5ecdc9fcfb904844e5c46950a6e2b388e1a5b210fd37d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp312-cp312-macosx_13_0_x86_64.whl
| Download URL | opentui-0.1.2-cp312-cp312-macosx_13_0_x86_64.whl |
|---|---|
| Size | 782.0 kB |
| Tags | CPython 3.12 macOS 13.0+ x86-64 |
|
SHA-256 checksum How to use checksums |
ac96ed80ddcceff2d50c70096194df46c096837bcda84c31b2d8779259281842
|
|
BLAKE2b-256 checksum How to use checksums |
ab4016b06e058fd53e85921b5fa771bf354f507d24be31384ab0ce24541892c7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency logRelease files / opentui-0.1.2-cp312-cp312-macosx_13_0_arm64.whl
| Download URL | opentui-0.1.2-cp312-cp312-macosx_13_0_arm64.whl |
|---|---|
| Size | 756.7 kB |
| Tags | CPython 3.12 macOS 13.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
a738a9b10b7842645daad32a4e0d60a3cda1aec9cbb4021f86c5a6e541b246c0
|
|
BLAKE2b-256 checksum How to use checksums |
b511e79227d5dd7053e5a8c9948e43caedb7156471e84f27808fd97c38545754
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Mar 30, 2026.
Transparency log