OpenTUI/React Quick Reference
OpenTUI is a React renderer for terminal UIs using Yoga layout (like React Native). NOT React DOM or Ink.
Version Info
- Current: 0.1.69 (updated), Latest: 0.1.69
- Context repo:
.context/repos/opentui (run bun run sync-context if missing)
Core Imports
import { useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/react";
import type { ScrollBoxRenderable, KeyEvent } from "@opentui/core";
JSX Elements (Lowercase!)
// CORRECT - OpenTUI intrinsics
<box style={{ flexDirection: "column" }}>
<text fg="#ffffff">Hello</text>
<scrollbox ref={scrollRef} focused />
</box>
// WRONG - Not OpenTUI
<div>, <span>, <Box>, <Text>
| Element |
Purpose |
Key Props |
<box> |
Container/layout |
style, id, onMouse |
<text> |
Text content (strings only!) |
fg, bg, selectable |
<scrollbox> |
Scrollable container |
ref, focused |
<a> |
Hyperlink (OSC8) |
href, fg |
<input> |
Text input |
focused, onInput, onSubmit |
<textarea> |
Multi-line input |
ref, focused, placeholder |
Critical Rules
1. Text Only Accepts Strings
// WRONG - Cannot nest elements in <text>
<text>Hello <text fg="red">world</text></text>
// CORRECT - Use row box for inline styling
<box style={{ flexDirection: "row" }}>
<text>Hello </text>
<text fg="red">world</text>
</box>
2. Always Check focused in Keyboard Handlers
useKeyboard((key) => {
if (!focused) return; // MUST check first!
if (key.name === "j") moveDown();
});
3. Save Scroll Position Synchronously
// WRONG - useEffect runs after render, scroll already reset
useEffect(() => { if (!focused) savedScroll.current = scrollRef.current?.scrollTop; }, [focused]);
// CORRECT - Save before state change
const handleSelect = () => {
savedScroll.current = scrollRef.current?.scrollTop; // Save first!
onSelect(item);
};
Hyperlinks (New in 0.1.64+)
<text>
Visit <a href="https://example.com">example.com</a> for more
</text>
Renders clickable links in terminals supporting OSC8 (iTerm2, Kitty, etc.).
Key Names
| Key |
key.name |
|
Key |
key.name |
| Enter |
"return" |
|
Arrows |
"up", "down", "left", "right" |
| Escape |
"escape" |
|
Letters |
"a", "b", "j", "k" |
| Tab |
"tab" |
|
Shift+Letter |
"A", "B", "G" |
Scrollbox API
const scrollbox = scrollRef.current;
scrollbox.scrollTop // Current position
scrollbox.scrollHeight // Total content height
scrollbox.viewport.height // Visible area
scrollbox.scrollTo(pos) // Absolute scroll
scrollbox.scrollBy(delta) // Relative scroll
scrollbox.getChildren() // Find elements by ID
Common Layout Patterns
// Full-height with fixed header/footer
<box style={{ flexDirection: "column", height: "100%" }}>
<box style={{ flexShrink: 0 }}>{/* Header */}</box>
<scrollbox style={{ flexGrow: 1 }}>{/* Content */}</scrollbox>
<box style={{ flexShrink: 0 }}>{/* Footer */}</box>
</box>
// Prevent unwanted spacing (Yoga quirk)
<box style={{ justifyContent: "flex-start", marginBottom: 0, paddingBottom: 0 }}>
React DevTools (Optional)
bun add --dev react-devtools-core@7
npx react-devtools@7 # Start standalone devtools
DEV=true bun run start # Run app with devtools enabled
Detailed References
- COMPONENTS.md - JSX elements, styling, text nesting
- KEYBOARD.md - Keyboard handling, key names, focus patterns
- SCROLLBOX.md - Scrollbox API, scroll preservation, windowed lists
- LAYOUT.md - Flex layout, Yoga engine, spacing issues
- PATTERNS.md - Screen navigation, state preservation, library compatibility
xfeed Reference Files
src/app.tsx - Screen routing, navigation history
src/components/PostList.tsx - Scrollbox with preservation
src/components/PostCard.tsx - Component styling, mouse handling
src/modals/FolderPicker.tsx - Windowed list pattern
src/hooks/useListNavigation.ts - Vim-style navigation
1---2name: opentui3description: Build terminal UIs with OpenTUI/React. Use when creating screens, components, handling keyboard input, managing scroll, or navigating between views. Covers JSX intrinsics, useKeyboard, scrollbox patterns, and state preservation.4---56# OpenTUI/React Quick Reference78OpenTUI is a React renderer for terminal UIs using Yoga layout (like React Native). **NOT React DOM or Ink.**910## Version Info1112- **Current:** 0.1.69 (updated), **Latest:** 0.1.6913- **Context repo:** `.context/repos/opentui` (run `bun run sync-context` if missing)1415## Core Imports1617```typescript18import { useKeyboard, useRenderer, useTerminalDimensions } from "@opentui/react";19import type { ScrollBoxRenderable, KeyEvent } from "@opentui/core";20```2122## JSX Elements (Lowercase!)2324```tsx25// CORRECT - OpenTUI intrinsics26<box style={{ flexDirection: "column" }}>27 <text fg="#ffffff">Hello</text>28 <scrollbox ref={scrollRef} focused />29</box>3031// WRONG - Not OpenTUI32<div>, <span>, <Box>, <Text>33```3435| Element | Purpose | Key Props |36|---------|---------|-----------|37| `<box>` | Container/layout | `style`, `id`, `onMouse` |38| `<text>` | Text content (strings only!) | `fg`, `bg`, `selectable` |39| `<scrollbox>` | Scrollable container | `ref`, `focused` |40| `<a>` | Hyperlink (OSC8) | `href`, `fg` |41| `<input>` | Text input | `focused`, `onInput`, `onSubmit` |42| `<textarea>` | Multi-line input | `ref`, `focused`, `placeholder` |4344## Critical Rules4546### 1. Text Only Accepts Strings4748```tsx49// WRONG - Cannot nest elements in <text>50<text>Hello <text fg="red">world</text></text>5152// CORRECT - Use row box for inline styling53<box style={{ flexDirection: "row" }}>54 <text>Hello </text>55 <text fg="red">world</text>56</box>57```5859### 2. Always Check `focused` in Keyboard Handlers6061```tsx62useKeyboard((key) => {63 if (!focused) return; // MUST check first!64 if (key.name === "j") moveDown();65});66```6768### 3. Save Scroll Position Synchronously6970```tsx71// WRONG - useEffect runs after render, scroll already reset72useEffect(() => { if (!focused) savedScroll.current = scrollRef.current?.scrollTop; }, [focused]);7374// CORRECT - Save before state change75const handleSelect = () => {76 savedScroll.current = scrollRef.current?.scrollTop; // Save first!77 onSelect(item);78};79```8081## Hyperlinks (New in 0.1.64+)8283```tsx84<text>85 Visit <a href="https://example.com">example.com</a> for more86</text>87```8889Renders clickable links in terminals supporting OSC8 (iTerm2, Kitty, etc.).9091## Key Names9293| Key | `key.name` | | Key | `key.name` |94|-----|------------|--|-----|------------|95| Enter | `"return"` | | Arrows | `"up"`, `"down"`, `"left"`, `"right"` |96| Escape | `"escape"` | | Letters | `"a"`, `"b"`, `"j"`, `"k"` |97| Tab | `"tab"` | | Shift+Letter | `"A"`, `"B"`, `"G"` |9899## Scrollbox API100101```typescript102const scrollbox = scrollRef.current;103scrollbox.scrollTop // Current position104scrollbox.scrollHeight // Total content height105scrollbox.viewport.height // Visible area106scrollbox.scrollTo(pos) // Absolute scroll107scrollbox.scrollBy(delta) // Relative scroll108scrollbox.getChildren() // Find elements by ID109```110111## Common Layout Patterns112113```tsx114// Full-height with fixed header/footer115<box style={{ flexDirection: "column", height: "100%" }}>116 <box style={{ flexShrink: 0 }}>{/* Header */}</box>117 <scrollbox style={{ flexGrow: 1 }}>{/* Content */}</scrollbox>118 <box style={{ flexShrink: 0 }}>{/* Footer */}</box>119</box>120121// Prevent unwanted spacing (Yoga quirk)122<box style={{ justifyContent: "flex-start", marginBottom: 0, paddingBottom: 0 }}>123```124125## React DevTools (Optional)126127```bash128bun add --dev react-devtools-core@7129npx react-devtools@7 # Start standalone devtools130DEV=true bun run start # Run app with devtools enabled131```132133## Detailed References134135- [COMPONENTS.md](COMPONENTS.md) - JSX elements, styling, text nesting136- [KEYBOARD.md](KEYBOARD.md) - Keyboard handling, key names, focus patterns137- [SCROLLBOX.md](SCROLLBOX.md) - Scrollbox API, scroll preservation, windowed lists138- [LAYOUT.md](LAYOUT.md) - Flex layout, Yoga engine, spacing issues139- [PATTERNS.md](PATTERNS.md) - Screen navigation, state preservation, library compatibility140141## xfeed Reference Files142143- `src/app.tsx` - Screen routing, navigation history144- `src/components/PostList.tsx` - Scrollbox with preservation145- `src/components/PostCard.tsx` - Component styling, mouse handling146- `src/modals/FolderPicker.tsx` - Windowed list pattern147- `src/hooks/useListNavigation.ts` - Vim-style navigation