--- name: opentui-react description: Expert assistance for OpenTUI with React. Use for React components, hooks (useKeyboard, useRenderer, useTimeline), JSX patterns, state management, forms, and testing. --- # OpenTUI React Integration Expert assistance for building terminal UIs with OpenTUI and React. ## Quick Start ```bash # Install dependencies bun install @opentui/core @opentui/react react ``` ## Basic Setup ```tsx import { createCliRenderer } from "@opentui/core" import { createRoot } from "@opentui/react" function App() { return Hello, OpenTUI React! } async function main() { const renderer = await createCliRenderer() createRoot(renderer).render() } main() ``` ## React Hooks ### useKeyboard Handle keyboard events in React components. ```tsx import { useKeyboard } from "@opentui/react" function App() { useKeyboard((key) => { if (key.name === "c" && key.ctrl) { process.exit(0) } if (key.name === "q") { process.exit(0) } }) return Press Ctrl+C or q to exit } ``` ### useRenderer Access the renderer instance. ```tsx import { useRenderer } from "@opentui/react" function Component() { const renderer = useRenderer() const handleClick = () => { console.log("Renderer available:", !!renderer) } return Click me } ``` ### useTerminalDimensions Get terminal size changes. ```tsx import { useTerminalDimensions } from "@opentui/react" function Responsive() { const { width, height } = useTerminalDimensions() return ( Terminal: {width}x{height} ) } ``` ### useTimeline Create animations in React. ```tsx import { useTimeline } from "@opentui/react" import { useRef } from "react" function AnimatedBox() { const boxRef = useRef(null) const timeline = useTimeline({ duration: 1000, easing: (t) => t * (2 - t), // easeOutQuad }) const animate = () => { if (boxRef.current) { timeline.to(boxRef.current, { backgroundColor: { r: 255, g: 0, b: 0 }, }) timeline.play() } } return ( Click to animate ) } ``` ## React Components All OpenTUI components are available as JSX elements: ```tsx import { text, box, input, select, scrollbox, code, } from "@opentui/react" function Form() { return ( User Information {errors.email && ( {errors.email} )} {errors.password && ( {errors.password} )} Submit ) } ``` ### External State Management #### Redux Integration ```tsx import { Provider, useSelector, useDispatch } from "react-redux" function Counter() { const count = useSelector((state: any) => state.count) const dispatch = useDispatch() useKeyboard((key) => { if (key.name === "up") dispatch({ type: "INCREMENT" }) if (key.name === "down") dispatch({ type: "DECREMENT" }) }) return Count: {count} } ``` #### Zustand Integration ```tsx import { create } from "zustand" const useStore = create((set) => ({ count: 0, increment: () => set((state: any) => ({ count: state.count + 1 })), decrement: () => set((state: any) => ({ count: state.count - 1 })), })) function Counter() { const { count, increment, decrement } = useStore() useKeyboard((key) => { if (key.name === "up") increment() if (key.name === "down") decrement() }) return Count: {count} } ``` ## Common Patterns ### List with Selection ```tsx function SelectList({ items }: { items: string[] }) { const [selectedIndex, setSelectedIndex] = useState(0) useKeyboard((key) => { if (key.name === "down" || (key.name === "tab" && !key.shift)) { setSelectedIndex(i => Math.min(i + 1, items.length - 1)) } if (key.name === "up" || (key.name === "tab" && key.shift)) { setSelectedIndex(i => Math.max(i - 1, 0)) } if (key.name === "enter") { console.log("Selected:", items[selectedIndex]) } }) return ( {items.map((item, index) => ( {index === selectedIndex ? "> " : " "}{item} ))} ) } ``` ### Tabs ```tsx function Tabs({ tabs }: { tabs: Array<{ id: string, label: string, content: any }> }) { const [activeTab, setActiveTab] = useState(tabs[0].id) return ( {/* Tab headers */} {tabs.map(tab => ( setActiveTab(tab.id)} borderStyle={activeTab === tab.id ? "single" : "none"} backgroundColor={ activeTab === tab.id ? { r: 100, g: 149, b: 237 } : { r: 50, g: 50, b: 50 } } padding={1} > {tab.label} ))} {/* Tab content */} {tabs.find(t => t.id === activeTab)?.content} ) } ``` ### Modal/Dialog ```tsx function Modal({ isOpen, onClose, children }: any) { if (!isOpen) return null return ( e.stopPropagation()} > {children} ) } ``` ## When to Use This Skill Use `/opentui-react` for: - Building TUIs with React - Using hooks (useKeyboard, useRenderer, etc.) - JSX-style component development - Integrating with React state management - Testing React OpenTUI components For vanilla TypeScript/JavaScript, use `/opentui` For SolidJS development, use `/opentui-solid` For project scaffolding, use `/opentui-projects` ## Resources - [Hooks Reference](references/HOOKS.md) - Complete hook documentation - [Component Props](references/PROPS.md) - React component props - [Patterns](references/PATTERNS.md) - Common React patterns - [State Management](references/STATE.md) - React state integration - [Testing](references/TESTING.md) - Testing React components ## Key Knowledge Sources - OpenTUI React GitHub: https://github.com/sst/opentui/tree/main/packages/react - Context7: `/sst/opentui` - React integration queries - Research: `.search-data/research/opentui/`