control/uialpha
Create app
ComponentsBlocksPrimitivesPractices
Setup promptAgent skillMachine docs
  • Action Bar
  • Activity
  • Audio Recorder
  • Audio VisualizerBetaBeta — the props contract is close to final, but small breaking changes can still land.
  • Chat Composer
  • Chat Composer Attachment
  • Chat Layout
  • Chat Message
  • Code Block Editor
  • ContextBetaBeta — the props contract is close to final, but small breaking changes can still land.
  • Dynamic NotificationExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.
  • EmailExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.
  • Environment VariablesExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.
  • Inline AttachmentBetaBeta — the props contract is close to final, but small breaking changes can still land.
  • Inline CitationBetaBeta — the props contract is close to final, but small breaking changes can still land.
  • Markdown Block
  • Source Badge
  • Task List
  • Thread Rail
  • Transcript Divider
  • User Ask
  • GitHub12

by Damien Schneider

Guide

Setup prompt

One prompt that makes the agent already open in your project read the repository, install from the registry, wire the CSS, run the doctor, and design the theme with you.

The prompt

Paste it into the agent already open in your project. Nothing else to configure: the prompt carries the catalog URL, the wiring rules, and the checks it has to pass before it reports back.

Agent setup prompt
You are setting up Control UI in this repository, then designing its skin with me.
Read the project first
- Every command here and in the catalog is written for npm. Read the lockfile and run mine instead — pnpm → pnpm dlx shadcn@latest, yarn → yarn dlx shadcn@latest, bun → bunx --bun shadcn@latest — and the same for npm run: the scripts you add later are written with my runner too.
- If this directory has no package.json, scaffold a new app instead: `npx shadcn@latest init --template next --defaults --name my-app --no-monorepo --force https://control-ui.dev/r/next-app.json && cd my-app && npm run dev` — replace my-app with the name I give you.
- Otherwise read package.json, the framework and its version, the Tailwind version, the CSS entry, and components.json if one already exists.
- In a workspace, one app is the target: run every command from that app's directory and read that app's manifest and CSS entry, not the root's. If more than one app could be the target and I did not name one, ask which before touching anything.
- A second Control UI install in the same workspace is an architecture decision, so ask me once before making it: per app, where each app owns its source and skin and they drift apart on purpose — the layout everything here is tested against — or one shared workspace package, which locks every consumer to the same skin and needs each consumer's CSS entry to @source the package, since Tailwind never scans past its own app. Recommend per app and wait for my answer: moving later means rewriting every call site.
- Tell me what you found and what you will install, then continue directly to Install. This is a status update, not an approval checkpoint; pause only if a required choice or destructive conflict blocks safe installation.
Install
- The catalog is https://control-ui.dev/r/agent-index.json and every item carries its own install command. https://control-ui.dev/llms.txt indexes the documentation.
- Install the complete set and its skin in one command: `npx shadcn@latest add https://control-ui.dev/r/all-flat.json`. Picking components one by one leaves the skin we write next with almost no surface to be checked against, and forces the update scripts below to track a bespoke list.
- Flat is the neutral reset: an empty skin.css and no adornments, so the theme we write later owns every value. Every other pack re-values component knobs and can install adornments and layout defaults that a theme cannot undo, which is why a pack is a choice I make, not a resemblance you pick for me.
- The pack re-themes every existing screen that reads these token names the moment it lands, and flat is deliberately the blank slate: squared corners, hairline borders. Between this install and the theme below, the app looks rougher than before — say so when you report the install, and carry the theme through in this same run. The reset is scaffolding, never the state you leave me in.
- Install item by item only if I ask for a lean install, and say that the update scripts then have to name each item.
- Installed files are source I own, so take them from the registry and never hand-copy them out of the documentation.
- Installing moves this app's own dependency versions. List every package it added or changed, and revert any change no installed item required.
Wire it
- Every item appends its own imports to the CSS entry named in components.json. The registry cannot know this app's layout, so it writes every one of them as `../components/control-ui/…` — right only when the entry sits one directory under the components alias. Resolve each appended import against the entry's own directory, and where it points at no file, rewrite the whole block to the real relative path from the entry to the directory the install actually wrote to. Check every line resolves before moving on; one wrong prefix silently unstyles everything below it.
- Never edit or reorder the imported stylesheets themselves. Layering and scope decide precedence, not their position in the entry.
- Stamp data-skin on the root element with the installed pack's id. It is the scope every token is declared under, not a multi-skin switch, so one skin still needs it: a missing or misspelled id leaves the whole contract undeclared, and every portalled surface — popover, dialog, menu, tooltip — renders with no tokens at all.
- The core token names are shadcn's, and an app that used shadcn declares them in two places with two different fates. At :root and .dark, the skin out-specifies that block on purpose and wins, so those declarations go dead — except the names the skin never declares, --chart-* and friends, which keep painting a second palette beside the skin. In an @theme or @theme inline block nothing goes dead: Tailwind merges every @theme in the build and the last declaration wins, so an app block sitting after the Control UI imports silently rewires utilities away from the skin — shadcn's additive radius scale seeded by the skin's --radius collapses every corner, and a hardcoded font family splits the app into two typefaces. Delete the dead :root declarations, reduce the app's @theme to keys Control UI does not map, and re-point the surviving app-specific names at skin tokens instead of keeping a parallel value; each deletion is a change to source I own, so show me the sweep as one diff.
- Run `node <installed control-ui directory>/scripts/control-ui-doctor.mjs` and settle what it reports before styling anything. It is read-only and checks exactly the wiring above: imports that resolve, the theme import last, app @theme blocks redeclaring Control UI keys, dead or hybrid :root palettes, and the data-skin stamp. Errors block; warnings are the deletion offers above, brought to me with file and token names.
- Start the dev server and confirm that a control paints and that one portalled surface opens with its tokens. Do not move on until both do.
- Do that on a throwaway route, then delete the route and its directory. Do not leave a verification page, an empty folder, or a screenshot behind in my app.
- Stay inside the app you are installing into. In a workspace the install writes the shared lockfile itself — that is the install doing its job, so let it, and report what moved with the rest of the version changes. Hand-editing a shared file is the other thing: a root package.json, a workspace catalog, a pinned override is mine to change, so propose the edit and wait, however small it looks.
Leave an update path
- Add two package.json scripts against `https://control-ui.dev/r/update.json`, the complete component set with no skin: control-ui:diff adds it with --diff, control-ui:update adds it with --overwrite.
- Chain `&& node <installed control-ui directory>/scripts/fix-css-imports.mjs` onto control-ui:update, with the real path. The overwrite re-appends the CSS import block under the canonical prefix the registry assumes, and the script folds those lines onto this app's real paths, drops the duplicates, and keeps the theme import last. In the canonical layout it is a no-op; leave it chained anyway.
- Add a third script, control-ui:doctor, running `node <installed control-ui directory>/scripts/control-ui-doctor.mjs` with the same real path. It is the read-only audit from Wire it, kept runnable so any later session — or I — can check the wiring after an update or a migration without this prompt.
- After a lean install those scripts must name the items I installed instead, since update.json would pull in the rest of the set.
- Say that the diff comes first and the overwrite wants a clean tree, because it rewrites source I own. The three skin files are never touched by either.
- The install already wrote .claude/skills/control-ui/SKILL.md: the Control UI skill rides every all pack and every update, so control-ui:update keeps it current and hand-edits there do not survive. It carries the token contract and the working rules, so later sessions in this repository build with the library without this prompt — tell me it landed. Only a lean install skips it; add https://control-ui.dev/r/control-ui-skill.json to the items those scripts name to bring it along.
Where shadcn/ui already sits
- Only when this app imports its own components/ui/*: inventory that directory, look every component up in the catalog index, and show me the mapping — the Control UI counterpart, or none. A tree or a scroll area counts as much as a button or a dialog; the inventory exists so nothing gets skipped for looking unusual. Then ask me once which mapped call sites to move. Never migrate without my answer.
- Both libraries write to different directories and run side by side, so leaving them is a real answer, not a half-measure.
- The props are not drop-in. Before you rewrite a call site, read the exported prop types of the installed Control UI component and tell me the mapping you derived: shadcn's variant and size collapse onto variant, tone, size and iconOnly, asChild becomes render, and a shadcn variant with no counterpart is a question for me, not a guess.
- A migrated call site keeps its layout classes — width, flex, grid, gap — and sheds its styling ones. The border, radius, background and padding utilities the old component needed now fight the recipe underneath, and carrying them over is what reads as a broken install afterwards.
- Move one component at a time and confirm the app still paints between each.
- Migrating the call sites without migrating the token plumbing is what leaves the app looking broken afterwards: the old system's :root palette and @theme mappings keep fighting the skin from the entry stylesheet. When the last agreed call site has moved, sweep them under the same rule as in Wire it, and run control-ui:doctor until it reports no errors — a migration I said yes to ends clean, not hybrid.
- Leave the shadcn source in place. Tell me when nothing imports it any more; deleting it is my call.
Discovery
- Do not start discovery until every Install and Wire it step above has completed successfully.
- Then ask me this, and wait for my answer:
"Should Control UI match this app's existing look, or do you want a new direction?
A — Match: I read your current styles and build a skin that sits beside them.
B — New: tell me the style you want, and attach reference images if you have any."
- If this project had no interface, skip the question, treat it as B, and ask me for the style and any references.
- On A, read the existing theme tokens, CSS, typography, spacing, components, and representative screens. Tell me what you found and use it as the visual brief; do not ask me to describe what the code already shows.
- On B, work from my description and my reference images, covering color, typography, density, corners, elevation, and motion.
- Stay on the neutral reset pack and let the theme carry the direction. Only when I name a stock pack for its own character do you install it with --overwrite and update data-skin.
- Resemblance is not a reason to switch packs: a pack's knob overrides and adornments outlive any theme written on top of it.
- Ask one focused question at a time, with at most four questions total.
- If I have attached no reference images yet, ask for them in this coding-agent conversation. If I have none, continue from the description.
- Use reference images for their visual language, not their literal content.
- Do not ask me to choose individual CSS variables. Infer a coherent system from my answers.
- Once the direction is clear, create the theme without asking me to restate the brief.
Implementation
- Read the canonical contract from https://control-ui.dev/r/theme-contract.json. The registry that served the install serves this list too.
- Write exactly one file named <short-name>.control-ui-theme.json in the current working directory.
- Application source stays untouched until the artifact is finished; Apply it below names the only writes beyond the artifact itself.
- Set baseSkin to the id of the skin pack you installed.
- Use format "control-ui-theme/v1".
- Choose a concise human name, 60 characters or fewer.
- Put color-valued tokens in both light and dark. Put every other token in shared.
- Prefer oklch() for authored colors and preserve accessible foreground/background contrast.
- Output only variables from the canonical theme contract.
- Omit tokens that should inherit from the base skin.
Accessibility gate
- Treat contrast as a required part of the theme, not a follow-up.
- Calculate resolved foreground/background contrast after alpha compositing in both light and dark. Sample gradients across every stop and interpolation, not one convenient point.
- Keep normal and small text at 4.5:1 or higher for body, muted fills, cards, popovers, popup highlights, semantic text, filled controls, selected tabs, and filled or outline badge states.
- Check focus indicators and control boundaries at 3:1 or higher against adjacent surfaces. A boundary is advisory when it is not required to identify the control.
- If a saturated fill needs light text, darken the fill until the pair clears 4.5:1; do not swap text color by visual guesswork alone.
- Do not claim the theme passes without checking the ratios.
What the components actually paint
- Every painted knob with what the browser actually paints behind it, one file per paint family: `https://control-ui.dev/r/contract/<family>.contrast.json`, harvested from rendered components and verified against the browser. `https://control-ui.dev/r/contract/index.json` names the families and how many probes each has.
- A probe's `anatomy` indexes into the file's `anatomies`: the paint stack under the part, back to front, its ancestors but also a sibling indicator that slides beneath it. The last node is the part itself.
- A part's contrast is decided by the knob it paints from **and** by every knob in that stack, never by theme tokens alone: re-valuing a surface knob changes the contrast of text you did not touch.
- For each probe: rebuild `anatomy` as nested elements, resolve `knobs.text` on the last one, composite the stack's fills behind it, and clear `rendersText ? 4.5 : 3`:1.
- `state: true` means the paint waits on an interaction, so force `knobs.fill` onto the part instead of expecting it to paint itself.
- A knob you leave alone still paints — it keeps its recipe default and still has to clear the ratio under your surfaces.
- The family's `/r/contract/<family>.json` slice lists `uncovered`: the knobs no documented route renders. Nothing measured them, so treat them as unverified rather than passing.
- After importing a theme, run `node <install>/scripts/control-ui-doctor.mjs --contrast`: it resolves every required pair that theme tokens alone decide, offline, and exits non-zero on a failure. Pairs a recipe paints are only measured by the rendered audit at `/theme-accessibility`.
Artifact shape
{
"format": "control-ui-theme/v1",
"name": "Theme name",
"baseSkin": "<installed skin id>",
"reduceMotion": false,
"tokens": {
"shared": {},
"light": {},
"dark": {}
}
}
Apply it
- The artifact is the source of record; each app consumes it as one derived CSS file.
- Run `node <install>/scripts/control-ui-doctor.mjs --emit-css <short-name>.control-ui-theme.json` to write <short-name>.control-ui-theme.css beside the artifact — that exact suffix is how the update tooling recognises the theme import. Never hand-write the selectors: the emitted `[data-skin="<baseSkin>"][data-skin]` doubles the attribute to match the pack's own weight, which is what hands the win to source order.
- Import that file on the last line of the entry's import block, after every Control UI import. Being last is what makes it win.
- If reduceMotion is true, stamp data-motion="reduced" on the root element beside data-skin; remove the attribute when a later theme turns it back off.
- Every app this run installed into gets the same theme this same way. One app themed while another rests on the raw reset is the bug, not a smaller scope.
- Reload and confirm a changed token paints — a radius, the primary — before you call it applied.
When finished, tell me the artifact path and where each app imports its CSS. To review the result myself, I import the artifact at https://control-ui.dev/theme-ai-builder and check it at https://control-ui.dev/theme-accessibility.

What it does

Reads the repository first. Package manager, framework, Tailwind version, CSS entry, components.json — and in a workspace, which app is the target.
Installs from the registry, never by hand-copying source out of the documentation, and reports every dependency version it moved.
Wires the CSS entry against this app's real paths, stamps data-skin, and sweeps the token blocks a previous library left behind.
Runs the doctor and settles what it reports before styling anything, then confirms in a browser that a control paints and a portalled surface opens.
Leaves the update path behind: control-ui:diff, control-ui:update, control-ui:doctor, and the agent skill that keeps later sessions building without this prompt.
Designs the theme with you in the same run, and checks its contrast against what the components actually paint.

When to use it

This prompt is for an app that already exists. Starting from nothing, create the app instead — one command scaffolds it with the whole set installed.

It also handles the case where shadcn/ui already sits in the project: it inventories components/ui/*, maps each component to its Control UI counterpart, and asks once which call sites to move. It never migrates without an answer, and leaving both side by side is a real answer.

On this page

  • The prompt
  • What it does
  • When to use it
No results found.
Guides
Create app
Scaffold a Next.js app with every Control UI component installed as source you own, or hand the whole install to the coding agent already open in your project.
Guide
Install
One command installs the complete set and its skin as source you own. The CSS entry is the only wiring you write.
Guide
Verify
The doctor audits what the registry cannot see from inside one install: imports that resolve, theme order, app blocks fighting the skin, and the data-skin stamp.
Guide
Build a screen
Render provider-owned messages with plain props and children. No intermediary message schema, no runtime coupling.
Guide
Theme it
Pick the pack, re-value the token contract in one artifact, and check the contrast the components actually paint.
Guide
Create a skin
Re-value the token contract over an installed pack, or own a full pack of three files, then reach the component knobs beneath.
Guide
Theme AI builder
Create a Control UI theme with Claude Code, Codex, or Mastra Code, then import and test it live.
Guide
Theme accessibility
Audit canonical theme colors plus rendered popup, badge, and active-tab states, then run the same checks from the CLI.
Guide
Update & diff
Updating is a reinstall: the update manifest refreshes every installed source and never touches the three skin-owned files.
Guide
Contract versions
The skin contract is version 8. Crossing a version reinstalls core, the affected items, and the skin together.
Guide
Setup prompt
One prompt that makes the agent already open in your project read the repository, install from the registry, wire the CSS, run the doctor, and design the theme with you.
Guide
Agent skill
The skill installed with every pack: the token contract and the working rules, refreshed by every update, so later sessions build without the prompt.
Guide
Machine docs
Inspect and install registry items through HTTP, shadcn manifests, static metadata, and machine-readable docs.
Guide
Why Control UI
An owned-source registry of primitives, agent surfaces, complete blocks, and swappable skins.
Guide
Architecture
Runtime ownership, skin layering, customization paths, and registry derivation.
Guide
Lock-in
What you own at each layer, what stays proprietary, and what leaving costs — measured, not promised.
Guide
shadcn compatibility
shadcn registry, token, and ownership conventions without writing to components/ui.
Guide
Control UI vs shadcn/ui
Both ship open-source React source through the shadcn CLI. The difference starts after install: a typed knob contract, skins that re-value it wholesale, and 16 skin modes audited against WCAG AA on every commit.
Guide
Best React component libraries for AI interfaces
Eight production options compared by ownership model, theming system, and agent-specific surfaces — from shadcn/ui and AI Elements to MUI to Control UI.
Guide
Reference
Theme guides, the maintenance workflow, and the reasoning behind Control UI — everything beyond the install path.
Guide
Skins
Skinning Control UI
Author complete token-driven Control UI skins with slots, adornments, motion controls, and one shared component source.
Skin
Refined
Compact, calm starting skin with a complete Control UI token contract.
Skin
Windows XP
Windows XP-inspired Luna tokens, bevels, and titlebar details.
Skin
Liquid metal
Polished metal skin with a WebGL shader control surface.
Skin
Rig
Brutalist skin with coral accents, squared corners, and dense typography.
Skin
Flat
Neutral reset skin with square corners, no shadows, and the stock motion tempo.
Skin
Modern Apple
Apple-inspired Liquid Glass skin: WebGL-refraction on floating surfaces, precise directional rims, transparent inputs, and continuous corners.
Skin
Cuicui
Cuicui-inspired shell skin with fixed grain, a docked w-80 sidebar, a neutral main container, and the send-aurora anchored extension on ChatComposer (skin.config fills the chat-composer:send-layer anchor).
Skin
Linear
Linear-inspired skin: indigo brand on a cool neutral ramp, a flat 13px chrome band, 8px controls on 12px panels, hairline borders instead of elevation, and 8px menu rows inset in a 4px gutter.
Skin
Practices
CSS-first interactivity
Model UI reactions with relational selectors, container/style queries, and native platform elements before adding React state, effects, or event handlers.
Skill
CSS-first motion & sizing
Drive sizing, enter/exit motion, and scroll effects from CSS and native attributes — token-driven and progressively enhanced — instead of measuring and animating values in JavaScript.
Skill
Derive, do not duplicate
Avoid second sources of truth in component props, hook parameters, and local state.
Skill
Remount state boundaries
Reset state by changing component identity or loading boundaries, not by syncing with effects.
Skill
Explicit names instead of comments
Encode intent in identifiers and extracted units so the code needs no explanatory comments, and keep the rare justified one telegraphic.
Skill
One responsibility per file
Split domain components and hooks before fetching, filtering, selection, and form state become entangled.
Skill
Keep input and output APIs narrow
Split oversized prop, argument, and return-value APIs into cohesive responsibilities.
Skill
Keep context necessary, narrow, and stable
Use context only across real composition boundaries, with the smallest stable semantic value consumers need.
Skill
Do not query the DOM in React
Keep element identity and collections in React instead of searching rendered markup.
Skill
Real stack tests
Prefer tests that drive production hooks, clients, routing, and cache behavior with only the network mocked.
Skill
Test rendered output, not class names
Prove visual behavior through computed styles, geometry, or browser output instead of Tailwind class strings.
Skill
Cohesive folders
Keep every folder a short, readable table of contents by grouping loose files into named responsibilities.
Skill
Single source of truth
Prevent shared facts from drifting by assigning each one a canonical owner.
Skill
Use existing components first
Start from the local design system or registry primitive before creating a new styled element.
Skill
Token discipline
Use established design tokens and local CSS variables before reaching for one-off values.
Skill
ClassName boundaries
Use component APIs for intended variation instead of overriding design-system internals with className.
Skill
Tailwind v4 CSS configuration
Configure Tailwind through CSS directives and tokens instead of adding new JavaScript config.
Skill
Tailwind v4 migration syntax
Use v4 names and modifiers when replacing or reviewing v3-era Tailwind classes.
Skill
First-class utilities before custom CSS
Prefer Tailwind v4's first-class utility families before arbitrary properties or handwritten CSS.
Skill
Variant-first styling
Check Tailwind variants before adding handwritten selectors, style props, or React state for styling.
Skill
Tailwind v4 capabilities
Reach for new v4 utilities before layout hacks, user-agent checks, or JavaScript measurement.
Skill
Tailwind v4 behavior & motion
Account for v4 behavior changes around transforms, hover, default colors, variant order, spacing, and motion.
Skill
State continuity
Show loading, empty, partial, success, and failure states in the same product language.
Skill
Provenance without noise
Surface source, runtime, and ownership cues only where they help the user trust or act.
Skill
Dense but scannable
Favor compact surfaces that support repeated work without flattening hierarchy.
Skill
Say it once
Cut redundant AI-slop copy so labels, controls, and state carry the obvious meaning.
Skill
Skin authoring
Author a skin as three files with strict roles — theme.css owns shared tokens, skin.css re-values registered component knobs, and skin.config declares behavior and adornments.
Skill
Extension authoring
Author an extension as an optional installable layered on the library — root-mounted for cross-cutting anatomy-attached behavior, anchored for component-scoped fx activated from skin.config.
Skill
Registry-first DX
Keep the registry manifest and installed source as the contract users can inspect.
Skill
Skin completeness
Treat a skin as a complete source recipe, not a partial class override layer.
Skill
Control UI composition
Keep blocks readable by composing public agent components, hooks, and slots explicitly.
Skill
Runtime-agnostic UI
Keep core visual surfaces independent from model runners, stores, and transport lifecycles.
Skill
Compound components DX
Expose named anatomy parts when users need to customize layout or actions.
Skill
Context vs props
Reach for a compound-component context only when props cannot reach the part, and store intent in it, not styling.
Skill
Components
AI components
Explore composable surfaces for messages, input, activity, media, and agent workflows.
Agent
Email
React Email compositions with Control UI colors and typography, image layouts, columns, and HTML or plain-text export.
ExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.Agent
ChatMessage
Composable chat message with typed role, density, and lifecycle state.
Agent
ChatComposer
Prompt composer with controlled text, submit state, and trigger-menu support.
Agent
ChatComposerAttachment
Composer attachment rail with file previews, upload progress, and removal.
Agent
UserAsk
Keyboard-first agent question panel that temporarily replaces the chat composer inside its container.
Agent
TaskList
Floating agent task progress pill above the composer that expands into the full task list.
Agent
AudioRecorder
Voice recorder with realtime waveform, duration, cancel, and submit controls.
Agent
AudioVisualizer
Levels-driven realtime audio visualizer offered in two usage versions - bars and line - sharing one export and one props contract.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Agent
DynamicNotification
Dynamic Island-style AI notification pill with a thinking state that morphs into a reply bubble — token-driven surface, WebGL-enhanced backdrop blur, or real refractive liquid glass.
ExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.Agent
EnvironmentVariables
Composable environment variable editor with .env upload, bulk paste, reveal controls, and submit helpers.
ExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.Agent
Activity
Shared static and collapsible activity anatomy with bounded, scrollable detail content.
Agent
TranscriptDivider
Toned run-boundary separator for transcripts: steering, interruptions, and condensed context.
Agent
Context
Compact context-window usage with an automatically derived token graph and anchored detail inspector.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Agent
InlineCitation
Inline multi-source citation with a keyboard-accessible preview and source navigation.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Agent
SourceBadge
Linked source badge with an automatic same-origin favicon, derived hostname, and resilient fallback.
Agent
ActionBar
Reusable hover actions for message and response controls.
Agent
InlineAttachment
Inline file and media previews for chat turns.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Agent
MarkdownBlock
Assistant markdown output rendered to prose, with a header and copy-source action.
Agent
CodeBlockEditor
Editable code surface with Shiki highlighting and token-based light/dark themes.
Agent
ChatLayout
Layout primitives for full chat threads, turns, and thoughts.
Agent
ThreadRail
Conversation minimap for scanning and jumping between chat turns.
Agent
Primitives
Primitives
Browse every Control UI primitive through the same live examples used in its documentation.
Primitive
Button
Accessible action button with size, variant, and semantic tone support.
Primitive
Collapsible
Accessible disclosure primitive with measured open and close motion.
Primitive
Tabs
Segmented and browser-style navigation with a stable active indicator.
Primitive
Track highlight
Shared fluid hover, keyboard-focus, and selection highlight for custom lists and groups, with CSS anchors and a measured fallback.
Primitive
Sidebar
Responsive app sidebar with animated mobile navigation, collapsible groups, nested menus, and icon collapse.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Scroll area
Scroll container with overlay scrollbars, edge fades, and optional progressive blur.
Primitive
Progressive blur
CSS-driven backdrop blur that grows toward an edge, with masked layers and interruptible staggered transitions.
Primitive
Table of contents
Sticky in-page navigation with scroll-spy range highlighting.
Primitive
Timeline
Static chronological events with independent status, connectors, descriptions, and metadata.
Primitive
Stepper
Static and interactive workflow steps with horizontal and vertical layouts.
Primitive
Skeleton
Loading placeholder with a token-driven shimmer.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Slider
Single-value range control with branded and plain treatments.
Primitive
Select
Single-choice picker with a token-matched trigger and floating list.
Primitive
DropdownMenu
Dropdown menu for actions, resources, labels, separators, and submenus.
Primitive
Context Menu
Pointer-positioned right-click and long-press menu with nested actions and selection controls.
Primitive
Toggle
Pressed-state button and toggle group built on the Button surface.
Primitive
Switch
On/off control with token-driven track, thumb, and press motion.
Primitive
Dialog
Modal dialog for focused tasks, confirmations, and custom panels.
Primitive
Popover
Anchored floating panel for inline settings and contextual content.
Primitive
Tooltip
Hover or focus hint popup with Base UI positioning and Control UI tokens.
Primitive
Rich tooltip
Persistent anchored tip for onboarding tours, walkthroughs, and new-feature announcements — dismissible, with optional media and step counter.
Primitive
Drawer
Swipeable edge panel for mobile sheets and off-canvas surfaces.
Primitive
Responsive dialog
Modal dialog on desktop that becomes a swipeable bottom drawer on mobile.
Primitive
Toast
Transient notifications with a callable toast API and single Toaster mount.
Primitive
Input
Text field primitive sized and styled to match other controls.
Primitive
Input group
Joined input wrapper for addons, icons, and focus-within rings.
Primitive
Dropzone
Composable file intake with validation, managed selection, and drag-activated overlays.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Phone input
International phone field with country search, E.164 values, and Zod validation helpers.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Command
Command palette with token-matched dialog, input, and result rows.
Primitive
Kbd
Keyboard shortcut chip and chord group.
Primitive
Checkbox
Single checkbox control with checked and indeterminate states.
Primitive
Radio group
Single-choice radio set for plans, filters, and option lists.
Primitive
Accordion
Stacked disclosure rows with measured panel animation.
Primitive
Avatar
Profile image with initials fallback and composable overlapping groups.
Primitive
Progress
Determinate task progress with optional label and value rows.
Primitive
Hover card
Hover or focus preview panel for profiles, links, and contextual details.
Primitive
Alert dialog
Modal confirmation dialog for destructive or blocking decisions.
Primitive
Menubar
Desktop command bar with nested menus, shortcuts, and separators.
Primitive
Navigation menu
Site navigation menu with a shared animated viewport.
Primitive
Field
Form field wrapper for labels, descriptions, errors, and validity state.
Primitive
Form
Form wrapper that coordinates field validation and returned errors.
Primitive
Native select
Native select control styled to match the Control UI control family.
Primitive
Textarea
Multiline text field with CSS-first auto-growth.
Primitive
Input OTP
One-time-code field with grouped, focus-aware slots.
Primitive
Combobox
Searchable single-select with input and floating option list.
Primitive
Alert
Inline status panel for callouts, errors, and notices.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Badge
Compact status, label, or count chip.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Card
Content surface for panels, tiles, and settings groups.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Table
Responsive data table for lists, comparisons, and structured records.
Primitive
Aspect ratio
CSS aspect-ratio wrapper for media and previews.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Button group
Joined button group for toolbars, split actions, and segmented controls.
Primitive
Empty
Empty-state layout for blank lists, zero results, and new workspaces.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Item
List row with media, content, and trailing actions.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Pagination
Page navigation for long lists and result sets.
Primitive
Spinner
Accessible loading indicator for pending buttons, panels, and inline waits.
Primitive
Meter
Static range meter for quota, storage, score, or usage values.
Primitive
Tree
Accessible tree view with roving keyboard navigation, single/multi selection, and animated disclosure.
Primitive
Checkbox Group
Multi-select checkbox set with shared state and select-all support.
Primitive
Autocomplete
Free-text input with search-as-you-type suggestions.
Primitive
Number Field
Numeric input with stepper buttons and optional drag-to-change behavior.
Primitive
Trigger Menu
Caret-anchored command or mention menu for text editors.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Toolbar
Roving-focus toolbar for editor controls and compact actions.
Primitive
Dockable Panel
Non-modal workspace panel that moves between two explicit edge slots with a mobile Drawer fallback.
ExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.Primitive
Infinite Canvas
Pan-and-zoom spatial workspace for arranging content without fixed bounds.
ExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.Primitive
Morphing Panel
Accessible disclosure surface that morphs between explicit collapsed and expanded dimensions.
ExpExperimental — the contract and the rendering can change without notice. Own the installed copy before shipping it.Primitive
Color Picker
Color input with picker UI, formats, presets, and contrast helpers.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Gradient Editor
CSS gradient editor with draggable stops and live preview.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Resizable
Accessible resizable panel groups and split layouts with keyboard support.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Primitive
Calendar
Date selection grid built on react-day-picker and themed through tokens.
Primitive
Typography
The token-driven type scale — one --text-* rung per size, named by role. Publish the utilities, not a component.
Primitive
Code
Shared code surface: Shiki-highlighted lines, gutter, clean copy, and virtualization for large files.
Primitive
Code Diff
Unified or split diff from a git patch or a before/after pair, with word-level intra-line highlighting.
Primitive
Markdown
Rendered agent markdown (GFM) whose code fences compose Code, and diff fences compose CodeDiff.
Primitive
Support files
useChatMessage
Typed role, density, and lifecycle state for ChatMessage.
Hook
useChatComposer
Controlled composer text and submit state.
Hook
useUserAsk
Question/option registration, selection, freeform text, and keyboard flow for UserAsk.
Hook
useAudioRecorder
Browser microphone recording state, waveform levels, and Blob completion.
Hook
useEnvironmentVariables
Editable environment variable rows with .env parsing, upload, duplicate detection, and submit helpers.
Hook
useCopyToClipboard
Copy-to-clipboard behavior with success state and fallback support.
Hook
cn
Tailwind class-name merge helper.
Util
skin
Skin slot and adornment resolvers for the Control UI library.
Util
serialize
Bridge a rich editor doc to plain text (and structured mentions) and back — independent of any one component.
Util
Blocks
Blocks
Start from complete workspace templates or focused interaction patterns, then own and adapt the installed source.
Use case
Chat
Controlled chat shell that composes rendered turns and a provider-owned composer.
Use case
Theme toggle
Controlled theme controls with a three-value switch, binary switch, cycle button, and dropdown.
Use case
Coding agent
Desktop coding workspace with project tasks, a focused conversation, and a persistent controlled composer.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Use case
Settings
Searchable multi-page settings shell with responsive navigation and accessible control groups.
Use case
File explorer
Finder-inspired file browser with locations, search, resizable columns, breadcrumbs, and an item preview.
BetaBeta — the props contract is close to final, but small breaking changes can still land.Use case