Skip to content

Widget Catalog

Rezi provides a comprehensive set of widgets for building terminal UIs. Widgets are plain TypeScript functions that return VNode objects.

app.view((state) =>
  ui.column({ gap: 1 }, [
    ui.text("Hello, World!"),
    ui.button({ id: "ok", label: "OK" }),
  ])
);

Widget Categories

Primitives

Foundation widgets for layout and content:

Widget Description Focusable
Text Display text with optional styling No
Box Container with border, padding, and title No
Row / Column Horizontal and vertical stack layouts No
Spacer Fixed-size or flexible spacing No
Divider Visual separator line No

Indicators

Visual feedback and status display:

Widget Description Focusable
Icon Single-character icon from registry No
Spinner Animated loading indicator No
Progress Progress bar with variants No
Skeleton Loading placeholder No
RichText Multi-styled text spans No
Kbd Keyboard shortcut display No
Badge Small status indicator No
Status Online/offline status dot No
Tag Inline label with background No

Form Inputs

Interactive form controls:

Widget Description Focusable
Button Clickable button with label Yes
Input Single-line text input Yes
Checkbox Toggle checkbox Yes
Radio Group Single-select options Yes
Select Dropdown selection Yes
Field Form field wrapper with label/error No

Data Display

Tables, lists, and trees:

Widget Description Focusable
Table Tabular data with sorting and selection Yes
Virtual List Efficiently render large lists Yes
Tree Hierarchical data with expand/collapse Yes

Overlays

Modal and popup interfaces:

Widget Description Focusable
Layers Layer stack container No
Modal Centered modal dialog Yes
Dropdown Positioned dropdown menu Yes
Layer Generic overlay layer Varies
Toast Non-blocking notifications No
Focus Zone Focus group for Tab navigation No
Focus Trap Constrain focus to region No

Layout

Complex layout components:

Widget Description Focusable
Split Pane Resizable split layout Yes
Panel Group Container for resizable panels No
Resizable Panel Panel within group No

Advanced

Rich, specialized widgets:

Widget Description Focusable
Command Palette Quick command search Yes
File Picker File browser with selection Yes
File Tree Explorer File system tree view Yes
Code Editor Multi-line code editing Yes
Diff Viewer Unified/side-by-side diff Yes
Logs Console Streaming log output Yes
Tool Approval Dialog Tool execution review Yes

Charts

Data visualization:

Widget Description Focusable
Gauge Compact progress with label No
Sparkline Inline mini chart No
Bar Chart Horizontal/vertical bars No
Mini Chart Compact multi-value display No

Feedback

User feedback and states:

Widget Description Focusable
Callout Alert/info message box No
Error Display Error message with retry Yes
Empty Empty state placeholder No

Common Patterns

Widget Props

All widgets accept a props object. Common properties include:

// Unique key for reconciliation (required for dynamic lists)
key?: string

// Interactive widget ID (required for focusable widgets)
id: string

// Visual styling
style?: TextStyle

Layout Props

Container widgets support layout properties:

// Padding (all sides, or specific)
p?: SpacingValue    // All sides
px?: SpacingValue   // Horizontal
py?: SpacingValue   // Vertical
pt?: SpacingValue   // Top
pb?: SpacingValue   // Bottom
pl?: SpacingValue   // Left
pr?: SpacingValue   // Right

// Gap between children
gap?: SpacingValue

// Alignment
align?: "start" | "center" | "end" | "stretch"
justify?: "start" | "end" | "center" | "between" | "around" | "evenly"

Spacing Values

Spacing accepts numbers (cells) or named keys:

Key Value
"none" 0
"xs" 1
"sm" 1
"md" 2
"lg" 3
"xl" 4
"2xl" 6
ui.box({ p: "md" }, [
  ui.column({ gap: "sm" }, [...]),
])
ui.column({ p: 2, gap: 1 }, [...])

Conditional Rendering

Use JavaScript expressions for conditional widgets:

ui.column({}, [
  ui.text("Always visible"),
  state.showDetails && ui.text("Conditional"),
  state.items.length === 0 && ui.text("No items"),
])

Falsy values (false, null, undefined) are filtered from children.

Dynamic Lists

When rendering lists, provide a key prop for efficient reconciliation:

ui.column(
  {},
  state.items.map((item) => ui.text(item.name, { key: item.id }))
)

Event Handlers

Interactive widgets support event callbacks:

ui.button({
  id: "submit",
  label: "Submit",
  onPress: () => handleSubmit(),
})

ui.input({
  id: "name",
  value: state.name,
  onInput: (value) => app.update({ ...state, name: value }),
  onBlur: () => validateField("name"),
})

API Reference

For complete type definitions, see the API Reference.