Claude Code Plugins

Community-maintained marketplace

Feedback

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.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name opentui
description 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.

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