From tui-design
Design functional, readable terminal UIs with proper visual hierarchy, semantic color, and responsive layout. Use when building CLI tools, interactive prompts, dashboards, or any terminal output with Rich, Textual, Questionary, or Click. Triggers on "terminal UI", "TUI", "Rich table", "CLI output", "terminal dashboard", "questionary prompt", "make this look better in the terminal".
How this skill is triggered — by the user, by Claude, or both
Slash command
/tui-design:tui-designThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Design functional, readable, responsive terminal interfaces. Terminal UIs have hard constraints that require different design thinking than web: monospace fonts, limited color palette, fixed viewport width, no CSS layout engine. This skill ensures Claude generates TUI code that works at any terminal width, communicates hierarchy through typography weight rather than decoration, and uses color s...
Design functional, readable, responsive terminal interfaces. Terminal UIs have hard constraints that require different design thinking than web: monospace fonts, limited color palette, fixed viewport width, no CSS layout engine. This skill ensures Claude generates TUI code that works at any terminal width, communicates hierarchy through typography weight rather than decoration, and uses color semantically.
Before writing any TUI code, answer five questions:
Data shape. List, table, tree, key-value pairs, progress indicator, or selection menu? The shape determines which Rich component to use. Do not choose a component and then force data into it.
Information hierarchy. What is the primary data the user needs? What is secondary context? What is metadata they rarely need? Primary data gets normal weight. Secondary gets dim. Metadata gets hidden behind a --verbose flag or revealed on selection.
Terminal constraints. What is the minimum width you must support? (80 columns is the safe default.) Does the output need to work when piped to a file or another program? Does the user's terminal support color? Always detect these -- never assume.
Interaction model. Is this read-only output (Rich), interactive selection (Questionary), or live-updating (Rich Live/Textual)? Each model has different component rules. Do not mix Rich print statements with Questionary prompts without clear visual separation.
Density target. Dashboards need high information density (multiple panels, compact tables). Wizards need low density (one question at a time, generous whitespace). Match the density to the task, not the amount of data.
Color means something or it means nothing. Every color in your palette must map to a meaning.
Rules:
NO_COLOR=1 -- the output must still be readable without any color.Palette (16-color safe):
| Semantic Role | Color | Rich Style | Usage |
|---|---|---|---|
| Primary data | white/default | "" | Main content, values, names |
| Secondary info | dim | dim | Timestamps, IDs, metadata |
| Success/active | green | green | Status OK, active items, counts |
| Error/danger | red | red | Errors, failures, critical |
| Warning/pending | yellow | yellow | Warnings, pending, stale |
| Accent/header | bold | bold | Headers, titles, emphasis |
Wrong: Different color for every column in a table (rainbow syndrome). Right: All data in default color, status column colored by value, headers bold.
Terminal width varies from 80 to 300+ columns. Your layout must handle all of them.
Rules:
ratio parameter for proportional columns.min_width on critical columns, let others flex.overflow="ellipsis" or overflow="fold" -- never manually truncate with [:N].COLUMNS=80 python your_script.py.not console.is_terminal), output plain text with no styling.Column sizing pattern:
from rich.table import Table
table = Table(expand=True) # fills terminal width
table.add_column("Name", ratio=3, min_width=12, no_wrap=True)
table.add_column("Status", ratio=1, min_width=6)
table.add_column("Details", ratio=4) # gets remaining space
Wrong: table.add_column("Name", width=22) -- breaks at narrow terminals, wastes space at wide ones.
Right: table.add_column("Name", ratio=3, min_width=12) -- proportional with a floor.
Rich has many components. Choosing the wrong one forces you into manual formatting to compensate.
Decision tree:
| Data Shape | Component | When to Use |
|---|---|---|
| Rows x Columns | Table | Comparing items across attributes |
| Key: Value pairs | Table (2-col, no header) or Panel | Config display, detail views |
| Hierarchical | Tree | File systems, dependency trees, nested categories |
| Sequential items | Table (1 data col + index) | Ordered lists, search results |
| Long text | Panel or Markdown | Help text, descriptions, error details |
| Multiple sections | Columns or Layout | Dashboards, side-by-side comparison |
| Progress | Progress | Long operations with known/estimated completion |
Wrong: Using print() with f"{'name':<20} {'value':>10}" when Rich Table exists.
Wrong: Using a full Table for a single key-value pair.
Right: Match the component to the data shape, then configure it.
Terminal typography is limited to: bold, dim, underline, and normal. Use these consistently.
Rules:
box.ROUNDED, box.HEAVY, and box.SIMPLE.Wrong: Bold values, colored headers, underlined labels, italic descriptions -- all in one view. Right: Bold headers, normal data, dim metadata. One border style throughout.
Show the minimum useful information by default. Let the user request more.
Rules:
--verbose / -v adds secondary columns, timestamps, IDs.--json outputs machine-readable format (no styling, no tables).Wrong: Showing 15 columns by default because the data has 15 fields.
Right: Showing 4 columns by default, adding the rest with -v.
When implementing a terminal UI:
Pick the component from the decision tree in Principle 3. If the data doesn't fit any component cleanly, reconsider the data shape.
Define hierarchy. Label every field as primary, secondary, or metadata. Primary fields show by default. Secondary shows with -v. Metadata shows on selection or --debug.
Assign max 4 semantic colors. Map each to a meaning using the palette from Principle 1. If you need a 5th color, you have too many concerns in one view -- split it.
Build with Rich's layout engine. Use ratio and min_width for columns. Use Table(expand=True). Never use ljust(), rjust(), f"{val:>14s}", or manual padding.
Test at 80, 120, 200 columns. Run with COLUMNS=80, COLUMNS=120, COLUMNS=200. All three must be readable.
Test piped output. Run with | cat or | head. Verify no ANSI escape codes leak and data is still parseable.
Test edge cases. Empty data, one row, 1000 rows, very long strings, Unicode. Every case must produce readable output.
See references/anti_patterns.md for detailed examples with before/after code.
Summary of what to avoid:
ljust(), f"{val:>14s}", string concatenation)Provides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.
Fetches up-to-date documentation from Context7 for libraries and frameworks like React, Next.js, Prisma. Use for setup questions, API references, and code examples.
npx claudepluginhub fblissjr/fb-claude-skills --plugin tui-design