web/components/ui

Buttons

The bezel Button — the app's unified interactive primitive. `primary` is reserved for the dominant affordance on a surface (at most one per region); `ghost` is the header/panel default; IconButton is the icon-only form.

Variants
States
kit/components

Rail navigation

Compact destinations shared by Zo app rails. Icons stay regular at rest and switch to their duotone twin only for the active destination.

kit/components

Segmented control

Mutually exclusive options with a flat selected fill and border. Options can include a leading icon.

Icon + label
Sizes
view: list · range: week
kit/components

Badges

Badge is the larger pill chip for cards and tabs; StatusBadge is the tiny inline pill for row-level state (Public, Connected, Installed, …).

Badge
DefaultSecondaryOutlineDestructive
StatusBadge tones
neutralaccentaccentSolidwarningsuccesscaution
kit/components

Persona avatars

One avatar path for uploaded images, the built-in Zo Pegasus, and custom-persona initials. Image failures fall back without shifting the surrounding row.

Default Zo
RCustom persona
Uploaded personaUploaded image
kit/patterns

Activity time

One live timestamp policy for activity surfaces: seconds, minutes, hours, and days ago, then abbreviated month and day after a week.

kit/tokens

Status color recipes

The semantic status vocabulary — success, warning, info, and destructive (error). The tokens are mode-aware, so never pair them with dark: variants; raw palette classes (text-emerald-600, …) are banned by the local/no-raw-palette ESLint rule. Three recipes: plain text/icon, tinted chip, solid fill.

Text — text-{token}
Deployed successfullyCertificate expiringUpdate availableBuild failed
Tinted chip — bg-{token}/10 text-{token} border-{token}/30
successwarninginfodestructive
Solid fill — bg-{token} text-{token}-foreground
successwarninginfodestructive
web/components/ui

Tooltips

Radix tooltip with the app's delays and elevation; keyboardHint renders the shortcut chips inline. The first one is pinned open for reference — hover the second.

kit/components

Context menus

The right-click menu — same item anatomy as the dropdown menu, anchored to the pointer. Right-click (or long-press) the surface below.

Right-click here
last action: —
kit/components

Popovers

The click-to-open anchored panel behind filters, pickers, and inline help. Modal on touch devices; dismisses on outside press or Esc.

kit/components

Modals

Dialog is the general modal shell (scrolling body, built-in close button); AlertDialog is the confirm shape — its footer pairs an outline cancel with a primary action on the same bezel chassis.

kit/components

Drawers

The sheet used as the mobile stand-in for popovers and dialogs; slides from a viewport edge with a drag handle on the bottom variant.

web/components/ui · kit/components

Indicators

Progress for determinate work; KeyHint renders keyboard shortcuts as key chips in the regular UI face (mono glyphs are hard to read).

Progress
x
x
KeyHint
⌘K⌘Shift.CtrlShiftP
kit/components

Form fields

Input and Textarea use one flat field boundary and a visible focus ring. Textarea grows with its content inside a ScrollArea; invalid fields show a destructive border.

Input
Textarea
kit/components

Selects

A single-choice picker with a flat trigger. Pass `items` when labels differ from values; the closed trigger renders the mapped label.

value: gpt
kit/components

Selection controls

Checkbox, Switch, and RadioGroup use flat surfaces with explicit checked states. Label identifies each field; Separator divides the groups.

Checkbox
Switch
notifications: on
Radio group
kit/components

Sliders

The range slider used by the video player's volume control; thumbTooltipLabel shows a hover hint above the thumb.

Volume
Volume 65%
value: 65
kit/components

Toggle groups

Single-select ToggleGroup — the connected-segments pattern (service create panel's HTTP/TCP/Process picker). The pressed item takes the accent paint.

Outline, single select
protocol: http
kit/components

Tabs

A flat tab strip with a tinted active tab and fine border. Arrow keys move between tabs; panels swap below.

1,204 requests this cycle.
tab: requests
kit/components

Tables

The data table used by billing, usage, and the SQLite viewer. Borders live on the cells (not rows) so they survive sticky headers; the container scrolls horizontally on overflow.

InvoiceDateAmountStatus
INV-0041Jun 01, 2026$20.00Paid
INV-0040May 01, 2026$20.00Paid
INV-0039Apr 01, 2026$18.50Refunded
kit/components

Collapsible

The disclosure primitive behind settings sections, thinking blocks, and tool-call groups in chat. The chevron rotates with the open state; the panel height animates via the global collapsible keyframes.

Retries: 3 · Timeout: 30s · Region: auto

These options only apply to scheduled runs.

open
kit/components

Accordion

Base UI disclosures with unique accessible labels and standard keyboard behavior. Opening one closes the rest unless multiple panels are enabled.

Your files, agents, and sites — one computer in the cloud.

kit/components

Command

The cmdk-backed command palette list: fuzzy input, grouped items, empty state. CommandDialog wraps it in the kit Dialog for the ⌘K pattern.

kit/components

Calendar

react-day-picker themed to the token system; nav chevrons and day cells reuse the flat-button variants. Single, range, and multi-select come from DayPicker's own mode prop.

October 2026
kit/components

Resizable

react-resizable-panels wrappers: Group + Panel + Separator (withHandle shows the grip). Web's workspace split panes are built on these.

Sidebar
Content
kit/components/flat-button

Flat button

The shadcn-shaped CVA button that predates the bezel system — variant/size/rounded recipes plus a built-in loading spinner. Deep-import only: the kit barrel's Button is the bezel system's. Prefer the bezel Button for new surfaces.

Variants
States
kit/components

Hover cards

The rich-preview popover used for persona cards, usage summaries, and credit alerts. Opens on hover after a short delay; content portals above everything else.

kit/components

Searchable list

SearchableListContainer pairs the app's SearchInput with a fixed-height ScrollArea viewport — the search/filter/scroll pattern used by pickers and settings lists. Esc clears; zero matches hand off to the shared EmptyState.

web/components/layout/collection

Empty states

Collection.EmptyState is the shared shape for the “no rows right now” slot. Three kinds: intro (first-run, invitational CTA), no-results (a filter matched nothing), and error (load failed, retry).

No chats yet

Start a conversation and it shows up here.

No matches

Nothing matches the current filter.

Couldn't load files

Something went wrong on our end.

www/components/docs

Code block

The docs code block: card chrome, a horizontal ScrollArea, and a hover copy button. The fenced code arrives pre-highlighted by Shiki (in the docs via @shikijs/rehype at build time, here via codeToHast on the server).

Unified diff

kit/components

Surfaces

RaisedSurface is reserved for content cards and callouts. Buttons, selectors, icon tiles, and tabs use flat treatments.

muted
background
subtle
accent
kit/components

Skeleton

The pulsing placeholder block for loading states — size it with width/height utilities to match the content it stands in for.

kit/components

Spinners & shimmer

CharSpinner cycles braille glyphs for loading states (the `z` variant is the app default); TextShimmer sweeps a highlight across streaming or pending labels.

CharSpinner variants
⠃z⣿opus⢕rune⢕spell
TextShimmerThinking about it…
www/components/ui

Chips

BrandedChip is the inline link chip used in marketing prose — brand-tinted for Discord and GitHub, neutral otherwise.

DiscordGitHubNeutral chip
kit/components

Visually hidden

VisuallyHidden keeps text in the DOM for screen readers and SEO while a decorative element supplies the visible rendering. It hides with inline styles instead of the sr-only utility, so hidden duplicates of visible content can never leak into view if utility CSS goes missing (see the Tailwind CSS generation gotcha in www's AGENTS.md). Use it whenever the hidden text has a visible twin — an icon label, a video-filled word, an SEO copy of on-screen content.

Icon with a hidden label
SitesThe icon is the visible rendering; “Sites” is in the accessibility tree but never paints.