# Unseen UI: full component reference
Install: `npm install @stackunseen/ui`. Import `@stackunseen/ui/styles.css` once; optional entries name their own stylesheet (for example `@stackunseen/ui/chat.css`). React 19.3 is a peer.
## Field
A shared label, description and validation message around a form control.
- Group: Forms
- Import: `import { Field } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/field/
- Inputs: label · description? · error? · required? · disabled? · invalid? · labelAs? · children
- Host responsibility: The application owns the value and validation result. Field associates the visible label, description and error with its control; a rendered error is not server validation.
- Keyboard: Tab focuses the native control. Labels are associated with their inputs; disabled controls leave the tab order. Error text remains available through aria-describedby.
- Documented states: Default, Required, Invalid, Disabled
```tsx
setName(event.target.value)} />
```
## Input
A text input that works with Field and your own validation.
- Group: Forms
- Import: `import { Input } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/input/
- Inputs: Native input props/ref · value · onChange · disabled? · readOnly?
- Host responsibility: The application owns the value and validation result. Field associates the visible label, description and error with its control; a rendered error is not server validation.
- Keyboard: Tab focuses the native control. Labels are associated with their inputs; disabled controls leave the tab order. Error text remains available through aria-describedby.
- Documented states: Default, Invalid, Disabled, Read-only, Long value
```tsx
setName(event.target.value)} />
```
## Textarea
A native multiline field for descriptions and longer written content.
- Group: Forms
- Import: `import { Textarea } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/textarea/
- Inputs: Native textarea props/ref · value · onChange · rows? · disabled? · readOnly?
- Host responsibility: The application owns the value and validation result. Field associates the visible label, description and error with its control; a rendered error is not server validation.
- Keyboard: Tab moves to the next control; Enter inserts a new line. Native selection, editing and resizing remain available.
- Documented states: Default, Invalid, Disabled, Read-only, Long value
```tsx
```
## Checkbox
A checkbox, including a mixed state for partly selected groups.
- Group: Forms
- Import: `import { Checkbox } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/checkbox/
- Inputs: checked? · onCheckedChange? · indeterminate? · native checkbox props/ref
- Host responsibility: Keep checked and the mixed state separately in your app, and update the mixed state when the selection changes.
- Keyboard: Tab focuses the checkbox; Space toggles it. Its associated label can also activate it.
- Documented states: Default, Checked, Indeterminate, Invalid, Disabled
```tsx
```
## Switch
An on/off setting with a label.
- Group: Forms
- Import: `import { Switch } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/switch/
- Inputs: checked? · onCheckedChange? · native input props/ref
- Host responsibility: Keep the label the same whether it’s on or off. Whether it’s on comes from your app, not from a guess about what the server did.
- Keyboard: Tab focuses the switch; Space toggles it. Disabled switches leave the tab order.
- Documented states: Default, Checked, Invalid, Disabled
```tsx
```
## RadioGroup
A labeled set of options where only one can be picked.
- Group: Forms
- Import: `import { RadioGroup } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/radio-group/
- Inputs: options · value? · onValueChange? · name? · orientation? · disabled? · emptyMessage?
- Host responsibility: Supply stable option values and use Field labelAs="span" for the group label. If there are no options, say why.
- Keyboard: Tab enters the selected radio; arrow keys move and select within the native group. Space selects the focused option.
- Documented states: Default, Horizontal, Invalid, Disabled, Empty
```tsx
```
## TonePad
Two choices on one square: drag the handle between Formal and Casual, Brief and Detailed.
- Group: Forms
- Import: `import { TonePad } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tone-pad/
- Inputs: value: { x, y } (0–1) · onValueChange · axes: { x: [left, right], y: [bottom, top] } · step? · label? · disabled?
- Host responsibility: Name both axes with the real words your model uses. The pad is made of two native sliders, one per axis, so keyboard and screen-reader users set the same two numbers.
- Keyboard: Tab visits the two sliders; arrow keys move one step, Home and End to the ends. The square itself takes pointer input.
- Documented states: Default, Disabled
```tsx
```
## Slider
Pick a number or a range by dragging or with the arrow keys.
- Group: Forms
- Import: `import { Slider } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/slider/
- Inputs: value: number[] · onValueChange? · onValueCommit? · min? · max? · step? · thumbLabels? · getValueLabel?
- Host responsibility: Give it real units and limits, and name each handle in a range. Save the value from your own callback.
- Keyboard: Arrow keys adjust by one step; Home and End move to bounds. Tab visits each available thumb.
- Documented states: Default, Range, Disabled
```tsx
`${value}%`} />
```
## Popover
A small panel that opens from a button and can hold controls.
- Group: Overlays
- Import: `import { Popover } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/popover/
- Inputs: Root: open? · onOpenChange? · Content: title · description? · headingLevel? · Trigger/Close asChild?
- Host responsibility: Keep whether it’s open, and any draft, in your app. Use it for short tasks; move longer ones into a dialog or a page.
- Keyboard: Enter or Space opens the trigger. Focus moves into the panel; Escape closes it and returns focus.
- Documented states: Default, Form, Long content
```tsx
setName(event.target.value)} />
```
## Tooltip
A short hint that appears on hover and keyboard focus.
- Group: Overlays
- Import: `import { Tooltip } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tooltip/
- Inputs: Root: open? · onOpenChange? · Provider: delayDuration? · Trigger/Content
- Host responsibility: Keep important labels visible on the page. A tooltip is only extra help and can’t hold buttons or links.
- Keyboard: Focusing the trigger reveals the hint; Escape dismisses it without moving focus.
- Documented states: Default, Long content
```tsx
Changes are kept in this local example.
```
## AlertDialog
A confirmation dialog that stays open until your app confirms the action worked.
- Group: Overlays
- Import: `import { AlertDialog } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/alert-dialog/
- Inputs: Root: open · onOpenChange · busy? · Content: error? · Action: onAction · Title/Description/Cancel
- Host responsibility: A click only asks. Keep the dialog open while your server handles the request, and close it once it confirms. The example here only changes sample data.
- Keyboard: Opening focuses Cancel. Tab remains inside; Escape or Cancel dismisses. Busy prevents repeated action requests while cancellation remains available.
- Documented states: Default, Pending, Error
```tsx
Archive project?You can restore it from the archive.CancelArchive project
```
## DropdownMenu
A menu of actions behind a button, with checkable and disabled items.
- Group: Navigation
- Import: `import { DropdownMenu } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/dropdown-menu/
- Inputs: Root/Trigger/Content/Item · Item: onSelect · CheckboxItem: checked/onCheckedChange · RadioGroup: value/onValueChange
- Host responsibility: Use menu items for actions and links for going somewhere. Picking an item asks your app to act; it doesn’t mean it worked.
- Keyboard: Enter, Space or ArrowDown opens the menu. Arrow keys and typeahead move between items; Enter selects, Escape returns focus.
- Documented states: Default, Selection, Disabled item
```tsx
Project actionsRename projectArchive project
```
## ContextMenu
Actions for an item, opened by right-click or the menu key.
- Group: Navigation
- Import: `import { ContextMenu } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/context-menu/
- Inputs: Root: onOpenChange? · Trigger · Content · Item: onSelect/disabled?
- Host responsibility: Tell people the menu is there, and make important actions reachable without it too.
- Keyboard: Focus the trigger and press Shift+F10 or the Context Menu key. Arrow keys navigate; Escape returns to the trigger.
- Documented states: Default, Disabled item
```tsx
Project preview. Right-click or press Shift+F10Rename project
```
## NavigationMenu
Website navigation with links and dropdown groups.
- Group: Navigation
- Import: `import { NavigationMenu } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/navigation-menu/
- Inputs: Root: value?/onValueChange? · List/Item/Trigger/Content/Link · Link: href/active?
- Host responsibility: Pass real links and a label for the navigation. The example here links to pages on this site.
- Keyboard: Tab visits links and triggers. Arrow keys move within the navigation; Escape dismisses open destination content.
- Documented states: Default, Disabled trigger
```tsx
FoundationsFormsInput
```
## Alert
A message that stays on the page, with a tone, optional actions and a choice of how urgently screen readers hear it.
- Group: Feedback
- Import: `import { Alert } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/alert/
- Inputs: tone?: neutral | info | success | warning | danger · icon? · native div props · Title/Description/Actions
- Host responsibility: The color only supports what the words say. A message already on the page isn’t announced; use status or alert only for messages that appear later.
- Keyboard: The message is read in document order. Only nested actions enter the tab sequence.
- Documented states: Default, Success, Warning, Error, With action
```tsx
Preview environmentChanges here affect the local example only.
```
## EmptyState
Explains why there’s nothing here and what to do next.
- Group: Feedback
- Import: `import { EmptyState } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/empty-state/
- Inputs: align?: start | center · native div props · EmptyStateTitle/Description/Actions/Icon
- Host responsibility: Say whether there’s no content yet, no results for a filter, or no access, and offer the action that fixes that reason.
- Keyboard: The heading and description remain ordinary content. A recovery action follows native button behavior.
- Documented states: Default, No results, With action
```tsx
No projects yetYour projects will appear here when you add one.
```
## Progress
Progress as a bar or a ring, for work you can measure or with an honestly unknown total.
- Group: Feedback
- Import: `import { Progress } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/progress/
- Inputs: label: string · value?: number | null · max?: number · valueText? · labelVisibility?: visible | hidden · showReading? · variant?: bar | ring · size?: sm | default | lg
- Host responsibility: Show a number only when you know both how much is done and the total. The example counts sample steps; it isn’t real upload or AI progress.
- Keyboard: The native progress element is named but is not an extra tab stop. Nearby controls remain available while work advances.
- Documented states: Default, Indeterminate, Complete, Hidden label
```tsx
```
## Toast
A short-lived notification people can dismiss, with its action also available elsewhere.
- Group: Feedback
- Import: `import { Toast } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/toast/
- Inputs: ToastProvider · Toast: open/onOpenChange/tone/type/duration · ToastAction: altText · ToastClose · ToastViewport
- Host responsibility: Keep each notification in your app. Show important results somewhere that lasts, and offer the action another way once the toast is gone. Use one provider and viewport per notification area.
- Keyboard: F8 moves focus into the notification area. Hover or focus pauses expiry; Escape dismisses a focused notification.
- Documented states: Default, With action, Error
```tsx
Local sample updatedThe notification can be dismissed.
```
## Breadcrumb
The path to the current page, with links back up.
- Group: Navigation
- Import: `import { Breadcrumb } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/breadcrumb/
- Inputs: items: {id,label,href?,onClick?}[] · currentId? · label? · separator?
- Host responsibility: Use real links for the pages above. The last item is the current page and isn’t a link.
- Keyboard: Tab visits ancestor links. The current page is readable text with aria-current="page".
- Documented states: Default, Long labels, Single item
```tsx
```
## Pagination
Move between pages of results, even when the total isn’t known.
- Group: Navigation
- Import: `import { Pagination } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/pagination/
- Inputs: page: number (1-based) · pageCount OR hasNextPage · onPageChange OR getPageHref · disabled?
- Host responsibility: Keep the page and the results in step. When the total isn’t known, enable Next only with hasNextPage, and never make up a total.
- Keyboard: Native buttons or links follow Tab order. Unavailable boundaries are disabled. Current page is identified with aria-current.
- Documented states: Default, Unknown total, Empty, Disabled
```tsx
```
## Sidebar
App navigation in groups, marking the current page.
- Group: Navigation
- Import: `import { Sidebar } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/sidebar/
- Inputs: Sidebar: label?/as? · Group: label? · Link: href/current?/disabled?/icon?/badge?
- Host responsibility: Keep the labels visible. Put Sidebar inside a Sidecar for a mobile drawer; Sidebar itself doesn’t open or close.
- Keyboard: Tab visits available links in document order. Current links use aria-current; disabled destinations are removed from the tab sequence.
- Documented states: Default, Disabled link, Long labels
```tsx
FoundationsNavigation
```
## Card
A box with a header (title, description and actions), a body and a footer, or a card that is one big link.
- Group: Data Display
- Import: `import { Card } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/card/
- Inputs: Native section props · href? · external? · Card.Header icon? actions? actionsLabel? · Card.Title as?: h2–h6 · Card.Description/Content/Section/Footer
- Host responsibility: Pick a heading level that fits the page. Add aria-labelledby only when the card should be a named region. With href the whole card is one link, so keep buttons and other links out of it.
- Keyboard: The card itself isn’t a tab stop; links and actions inside it follow the normal page order.
- Documented states: Default, Header actions, With icon, Sections, With action, Link, External link, Long content
```tsx
Component libraryReusable website and AI controls.Explore the available components.
```
## Table
A plain table in a labeled area you can scroll with the keyboard.
- Group: Data Display
- Import: `import { Table } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/table/
- Inputs: label: string · scrollLabel? · native table props/ref · Caption/Header/Body/Footer/Row/Head/Cell
- Host responsibility: Give it a caption and clear headers. Sorting, loading and selection are up to you; use DataTable when it fits your data.
- Keyboard: Tab reaches the scroll region when needed; arrow keys scroll wide content. Column and row headers preserve native table semantics.
- Documented states: Default, Empty, Wide content
```tsx
```
## ToggleGroup
Choose one or several options shown at once: filter pills with counts, or joined segments, as buttons or links.
- Group: Actions
- Import: `import { ToggleGroup } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/toggle-group/
- Inputs: label · options: { value, label, count?, description?, href?, disabled? }[] · type?: single | multiple · value · onValueChange? · allowEmpty? · mode?: buttons | links · variant?: pills | segmented · size?: default | sm · disabled?
- Host responsibility: Your app owns the selection and the counts. One choice works like radio buttons and several like toggle buttons. Links mode uses real links for views kept in the URL, so it works before scripts load.
- Keyboard: Tab reaches the group once. Arrow keys, Home and End move between enabled options; in single mode they also select. Space or Enter toggles an option in multiple mode. In links mode every link is in the tab order.
- Documented states: Default, Multiple, With counts, Links, Disabled option, Small
```tsx
```
## Tag
A neutral label for categories and levels, with tones and two sizes.
- Group: Data Display
- Import: `import { Tag } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tag/
- Inputs: Native span props · children · tone?: neutral | primary | accent | success | warning · hue? · size?: default | sm · mono? · icon?
- Host responsibility: A tag is only a label; it doesn’t mean a status. Use StatusBadge for run and approval status.
- Keyboard: Inert content; it adds no tab stop.
- Documented states: Default, Tones, Small, With icon, Custom hue, Mono
```tsx
Advanced
```
## DiffStat
Lines added and removed for a change, with optional file count and blocks.
- Group: Data Display
- Import: `import { DiffStat } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/diff-stat/
- Inputs: added · removed · files? · blocks? · native span props
- Host responsibility: Pass the counts your diff or code server reports. The signs are in the text, so it reads without color, and screen readers hear the counts in words.
- Keyboard: Inert content; it adds no tab stop.
- Documented states: Default, With files, Blocks, No changes
```tsx
```
## ElapsedTime
Time spent on a run or turn, ticking while it runs and fixed once it ends.
- Group: Data Display
- Import: `import { ElapsedTime } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/elapsed-time/
- Inputs: startedAt · endedAt? · durationMs? · native time props
- Host responsibility: Pass endedAt or durationMs when the work stops. Prefer durationMs from the server when the browser clock should not decide the figure.
- Keyboard: Inert content. It is not a live region, so it never interrupts a screen reader.
- Documented states: Running, Finished, Measured by server
```tsx
```
## Numeric
A figure in the numeric face with its qualifier in words, so numbers line up across a screen.
- Group: Data Display
- Import: `import { Numeric } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/numeric/
- Inputs: value · qualifier? · size?: lg | md | sm · tone?: neutral | up | down | primary
- Host responsibility: Format the figure and its sign in the application. Tone only backs up a sign that is already in the text. Stat, ElapsedTime and ToolCall durations use the same face, set with --ai-font-numeric.
- Keyboard: Inert content; it adds no tab stop.
- Documented states: Headline, Row, Meta, Trend
```tsx
```
## Kbd
One key cap, for shortcut hints beside actions and in menus.
- Group: Data Display
- Import: `import { Kbd } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/kbd/
- Inputs: size?: default | sm · native kbd props
- Host responsibility: Put each key in its own Kbd and the "+" as text between them, so the keys are read as words. Keep the real shortcut in your app; the cap is a hint.
- Keyboard: Inert content.
- Documented states: Default, Combination, Small
```tsx
Shift + Enter
```
## DotRing
A ring of dotted spokes, one per hour or step, denser where the value is higher, with a figure in the centre.
- Group: Data Display
- Import: `import { DotRing } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/dot-ring/
- Inputs: label · data: { label, value }[] · max? · depth? · value? · caption? · ticks? · unit?
- Host responsibility: Pass measured counts in order, clockwise from the top. The centre figure is formatted by your app. The same values are in a hidden table, so nothing is said by dots alone.
- Keyboard: Inert content; the hidden table is read in order.
- Documented states: Default, Sparse, Empty
```tsx
```
## DotBars
A histogram built from dots, one column per day or step, with a highlighted range and an accent outlier.
- Group: Data Display
- Import: `import { DotBars } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/dot-bars/
- Inputs: label · data: { label, value }[] · max? · rows? · range?: { start, end } · rangeLabel? · outliers?: number[] · axis?: [start, end] · unit?
- Host responsibility: The range only highlights; your app picks it and sums its figures for rangeLabel. Pass the axis labels as text. Every value is in a hidden table.
- Keyboard: Inert content; the hidden table is read in order.
- Documented states: Default, Range, Outlier, Empty
```tsx
```
## WeekStrip
Seven columns with the series stacked inside each and the current day in bold, for a week at a glance.
- Group: Data Display
- Import: `import { WeekStrip } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/week-strip/
- Inputs: label · days: { label, values: Record }[] · series: { id, label, swatch? }[] · max? · current? · unit? · legend?
- Host responsibility: Pass counts by series id per day. max sets the column that reads full; use it for a goal so the empty part of each column shows what is left. Every count is in a hidden table.
- Keyboard: Inert content; the hidden table is read in order.
- Documented states: Default, Single series, Goal
```tsx
```
## HeatKeys
A grid of cells shaded in four steps by their value, laid out like a keyboard or any grid, with the label kept on every cell.
- Group: Data Display
- Import: `import { HeatKeys } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/heat-keys/
- Inputs: label · rows: { keys: { id, label, value, span? }[], offset? }[] · max? · scale?: [low, high] · unit?
- Host responsibility: Lay the rows out yourself with offsets in cell units. Shading backs up the printed label; every count is in a hidden table. For counts across two named axes, use Matrix.
- Keyboard: Inert content; the hidden table is read in order.
- Documented states: Default, Grid, Empty
```tsx
```
## Sparkline
A word-sized trend for a stat card or a table cell, as a line, an area or bars, with gaps left open.
- Group: Data Display
- Import: `import { Sparkline } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/sparkline/
- Inputs: label · data: { label, value: number | null }[] · variant?: line | area | bar · tone?: neutral | positive | negative · markLast? · unit?
- Host responsibility: Print the number it belongs to beside it; the line has no axis. Pass null for a sample you did not get, so the line breaks instead of joining across it. Every sample is in a hidden table.
- Keyboard: Inert content; the hidden table is read in order.
- Documented states: Default, Area, Bars, Gap, In a stat
```tsx
```
## BarList
Ranked rows with a bar behind each name, for tokens by tool, spend by agent or calls by model.
- Group: Data Display
- Import: `import { BarList } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/bar-list/
- Inputs: label · items: { id, label, value, display? }[] · max? · headings?: [name, value]
- Host responsibility: Sort the rows and format each value in your app; the bar repeats the printed value and never replaces it.
- Keyboard: Inert content; the list is read in order.
- Documented states: Default, Headings, Empty
```tsx
```
## Tracker
A strip of blocks, one per day or run, coloured by how it went, for nightly evals, uptime or a run history.
- Group: Data Display
- Import: `import { Tracker } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tracker/
- Inputs: label · segments: { label, status: ok | degraded | failed | unknown, detail? }[] · summary? · axis?: [start, end]
- Host responsibility: Pass what your server recorded; a period with nothing recorded is unknown, never ok. Each block names its status in words, and every block is in a hidden table.
- Keyboard: Inert content; the hidden table is read in order.
- Documented states: Default, No data
```tsx
```
## DonutChart
Shares of one total as a ring, with the total in the centre and every share printed in the legend.
- Group: Data Display
- Import: `import { DonutChart } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/donut-chart/
- Inputs: label · data: { id, label, value, swatch? }[] · value? · caption? · legend? · unit?
- Host responsibility: Use it for a few parts of one whole. Format the centre figure in your app. Shares are printed in the legend and the hidden table, so no slice is read by colour alone.
- Keyboard: Inert content; the hidden table is read in order.
- Documented states: Default, Single slice, No legend
```tsx
```
## Avatar
An image or initials for a person or team, decorative unless given a name.
- Group: Data Display
- Import: `import { Avatar } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/avatar/
- Inputs: name? · initials? · src? · size?: sm | default | lg · native span props
- Host responsibility: Pass name when the avatar is the only sign of who is shown; otherwise leave it decorative beside visible text. Supply accessible, licensed image URLs.
- Keyboard: Inert content; it adds no tab stop.
- Documented states: Default, With image, Image failed, Sizes, No name
```tsx
```
## Stat
A formatted number with its label, optional change and note, for rows of metrics.
- Group: Data Display
- Import: `import { Stat } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/stat/
- Inputs: label · value · delta? · trend?: up | down | neutral · note? · variant?: card | plain | inset · StatGroup: native div props
- Host responsibility: Format numbers, units and signs in the application. Trend color only backs up text that already shows the sign. Renders on the server.
- Keyboard: Inert content; it adds no tab stop.
- Documented states: Default, With trend, Group
```tsx
```
## Chip
A compact label that links or can be removed, with a group that wraps or scrolls. For choices, use ToggleGroup.
- Group: Actions
- Import: `import { Chip } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/chip/
- Inputs: children · href/active/current? + anchor props | onRemove/removeLabel · swatch? · size?: default | sm · disabled? · ChipGroup: label · overflow?: wrap | scroll
- Host responsibility: Chips only ask; your app applies the filter. Link chips render the LinkProvider link when one is set. Active fills use --ai-chip-active-background and --ai-chip-active-color so labels keep their contrast.
- Keyboard: Link chips are links; the remove control is a button. Backspace or Delete on a removable chip removes it.
- Documented states: Default, Removable, Scrolling group
```tsx
setLens("agents")}>Agents
```
## Stepper
A step indicator for series and multi-step paths, as dots or a list, with optional links.
- Group: Navigation
- Import: `import { Stepper } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/stepper/
- Inputs: label · steps: { id, label, href?, state?: done | current | upcoming | planned | available }[] · presentation?: dots | list | segments · previous? · next? · reading? · tooltip? · as?: nav | div
- Host responsibility: Pass the current step from your route or app state. Planned steps have no destination; the reading prints "Step 2 of 9" from the current step.
- Keyboard: Steps with destinations are ordinary links in a navigation landmark; dots carry their labels for assistive technology.
- Documented states: Default, List, Segments, With navigation, Tooltips
```tsx
```
## Matrix
A heatmap table of counts with a single-hue fill, linked headers and linked cells.
- Group: Data Display
- Import: `import { Matrix } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/matrix/
- Inputs: label · rows: { id, label, href?, swatch? }[] · columns · value?(row, column) | values · href?(row, column) | hrefs · cellLabel?(row, column, value) | cellLabels · max? · format? · caption? · scrollLabel? · columnHeader?: horizontal | angled · zero? · totals?: rows | columns | both · totalsLabel?
- Host responsibility: Every cell shows its number. The fill only backs it up, and the text switches color where the theme needs it to for contrast. Pass the counts and links from your app.
- Keyboard: A real table with scoped headers inside a focusable, labeled scroll region; header and cell links are ordinary links.
- Documented states: Default, Linked cells, Angled headers, Totals, Plain data
```tsx
```
## CopyButton
Copies a value and reports the real outcome.
- Group: Actions
- Import: `import { CopyButton } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/copy-button/
- Inputs: value · label? · copiedLabel? · failedLabel? · iconOnly? · onCopy?(ok) · resetMs? · variant? · size?
- Host responsibility: The outcome is announced in a polite live region and shown by the icon; the accessible name never changes mid-press. A failed copy says to copy by hand. Snippet uses it, so the library has one copy behavior.
- Keyboard: A button: Enter or Space copies. The icon-only form has a tooltip and an accessible name.
- Documented states: Default, Icon only, Primary
```tsx
track(ok)} />
```
## InputGroup
One bordered control that holds an input and its action.
- Group: Forms
- Import: `import { InputGroup } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/input-group/
- Inputs: attach?: flush | inset · size?: default | touch · shape?: control | pill · invalid? · disabled? · InputGroupAddon · InputGroupButton
- Host responsibility: The group draws the one border, radius and focus ring through :focus-within; the input gives up its own, and the button keeps an inner keyboard ring. Field supplies the label, description, error and disabled state; it works in a native form.
- Keyboard: Tab moves from the input to the button; Enter in the input submits the form.
- Documented states: Default, Inset, Search, Invalid
```tsx
Subscribe
```
## AppearanceToggle
Lets people choose light, dark or the system setting.
- Group: Actions
- Import: `import { AppearanceToggle } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/appearance-toggle/
- Inputs: value · onValueChange · variant?: cycle | segmented | switch | subtle · labels? · label? · size? · useStoredAppearance({ storageKey }) · useResolvedAppearance(value) · appearanceInitScript({ storageKey })
- Host responsibility: Pass the value to AITheme. useStoredAppearance keeps it in this browser and follows other tabs; appearanceInitScript applies it before paint through a root attribute your stylesheet reads. Until the page’s scripts load, the cycle button shows a neutral mark.
- Keyboard: The cycle button names the current mode and what a press switches to. Switch and segmented are radiogroups (arrow keys move and select); subtle is one "Dark mode" button with a pressed state.
- Documented states: Default, Switch, Subtle, Segmented, Stored
```tsx
```
## CommandPalette
A Ctrl/Cmd+K menu for jumping to places and searching, with results in groups.
- Group: Navigation
- Import: `import { CommandPalette } from '@stackunseen/ui/navigation';` and `import '@stackunseen/ui/navigation.css';`
- Page: https://unseenui.com/components/command-palette/
- Inputs: open? · defaultOpen? · onOpenChange? · items · search?(query, signal) · debounceMs? · onSelect · shortcut?: "mod+k" | false · label? · placeholder? · emptyState? · footerHints? · trailingAction?(query) · highlight?(text, query) | false · cancelLabel? · useCommandPalette() · markMatches(text, query)
- Host responsibility: Static items filter locally by every word; async results are debounced, canceled through the signal and never shown for an older query. With a LinkProvider, items with an href are that router link. Excerpts are plain text; markMatches marks them safely.
- Keyboard: Up and Down move and wrap, Home and End jump, Enter selects, Escape and the backdrop close. Enter does nothing during IME composition. Focus returns to the opener.
- Documented states: Default, Async results
```tsx
router.push(item.href)} />
```
## TableOfContents
An "On this page" rail that marks the section being read.
- Group: Navigation
- Import: `import { TableOfContents } from '@stackunseen/ui/navigation';` and `import '@stackunseen/ui/navigation.css';`
- Page: https://unseenui.com/components/table-of-contents/
- Inputs: items: { id, title, items? }[] · variant?: list | track | ticks · label? · numbered? · showReading? · collapsible?: narrow | never | always · readingLine? · minItems? · activeId? · onActiveChange? · useActiveHeading(ids)
- Host responsibility: Links are plain in-page anchors; nothing hijacks scrolling. The active heading is the last one past the reading line, tracked with an IntersectionObserver and a passive scroll listener. Track lists every level on a line that steps in per level and darkens for the sections on screen. Ticks is a slim rail for long reads that opens into the titles. Below minItems it renders nothing.
- Keyboard: Ordinary links in a navigation landmark; the active one carries aria-current="location". The ticks rail is a button with aria-expanded; focus inside opens the titles and Escape closes them.
- Documented states: Default, Track, Ticks, Collapsible, Plain
```tsx
```
## ShareMenu
Copy link, the device share sheet when there is one, and configurable targets.
- Group: Navigation
- Import: `import { ShareMenu } from '@stackunseen/ui/navigation';` and `import '@stackunseen/ui/navigation.css';`
- Page: https://unseenui.com/components/share-menu/
- Inputs: url · title · text? · targets?: (copy | native | linkedin | x | email | { id, label, href })[] · presentation?: inline | menu · label? · onShare?(target)
- Host responsibility: Native share support is decided on the client only, so server and first client render agree. A dismissed share is not an error. External targets open in a new tab with rel="noopener noreferrer"; no tracking parameters are added. Custom targets must be http(s), mailto or relative links; others are dropped. For "open in another chat", build each href from the query.
- Keyboard: Buttons and links in a labeled group, or a menu with arrow keys.
- Documented states: Default, Menu, Custom targets, Open in chat
```tsx
```
## DataGrid
A table with sorting, paging, row selection and column toggles.
- Group: Data Display
- Import: `import { DataGrid } from '@stackunseen/ui/application';` and `import '@stackunseen/ui/application.css';`
- Page: https://unseenui.com/components/data-grid/
- Inputs: caption · captionVisibility? · columns · rows · getRowId · sort? · pagination? · selectedRowIds?
- Host responsibility: Selecting a row never grants permission to act on it.
- Keyboard: Tab reaches sort buttons, selection, column controls and paging. Wide tables scroll within their labeled region.
- Documented states: Default, Loading, Empty, Error
```tsx
row.id}
sort={sort} onSortChange={setSort} pagination={pagination} onPageChange={setPage}
selectedRowIds={selectedIds} onSelectionChange={setSelectedIds} />
```
## Combobox
Search a list and choose one value, or several with type="multiple", with clear loading and error messages.
- Group: Forms
- Import: `import { Combobox } from '@stackunseen/ui/application';` and `import '@stackunseen/ui/application.css';`
- Page: https://unseenui.com/components/combobox/
- Inputs: label · options · type?: single | multiple · value · onValueChange · query · onQueryChange
- Host responsibility: Keep the selected value and search query in your app. Use filterOption={false} for options already filtered by your server.
- Keyboard: Arrow keys move through options. Enter selects, Escape closes, and Tab leaves the field. Focus stays in the input.
- Documented states: Default, Multiple, Disabled, Loading, Error, Empty
```tsx
```
## Calendar
Pick a date or a range, in any language, limited to the dates you allow.
- Group: Forms
- Import: `import { Calendar } from '@stackunseen/ui/application';` and `import '@stackunseen/ui/application.css';`
- Page: https://unseenui.com/components/calendar/
- Inputs: value · onValueChange? · month · onMonthChange · locale · mode?
- Host responsibility: Pass dates as YYYY-MM-DD, plus the month to show and today’s date from your app. locale formats the dates; labels translates the rest of the text.
- Keyboard: Arrow keys move by day or week, Home/End by week and Page Up/Down by month. Enter or Space selects an available day.
- Documented states: Default, Range, Disabled, Loading, Error
```tsx
```
## DateRangePicker
A date range field with a pop-up calendar that works from the keyboard.
- Group: Forms
- Import: `import { DateRangePicker } from '@stackunseen/ui/application';` and `import '@stackunseen/ui/application.css';`
- Page: https://unseenui.com/components/date-range-picker/
- Inputs: value · onValueChange? · month · onMonthChange · open · onOpenChange · locale
- Host responsibility: Keep the range, and whether the calendar is open, in your app. A range can’t include disabled dates; check your date rules again when the form is submitted.
- Keyboard: Opening focuses the calendar. Escape closes and returns to the trigger; Clear and Done are labeled actions.
- Documented states: Default, Disabled, Loading, Error
```tsx
```
## Reasoning
A quiet, collapsible public reasoning summary that follows the stream.
- Group: Conversation
- Import: `import { Reasoning } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/reasoning/
- Inputs: summary · state · durationMs? · open? · onOpenChange?
- Host responsibility: Pass only a public summary, never private reasoning. The duration shows only if your server measured it.
- Documented states: Complete, Streaming, Unknown duration
```tsx
```
## SuggestTextarea
A text area that shows an AI completion as ghost text; Tab accepts it.
- Group: Conversation
- Import: `import { SuggestTextarea } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/suggest-textarea/
- Inputs: value · onValueChange · suggestion? · onAccept? · onDismiss? · Textarea props
- Host responsibility: Fetch suggestions yourself, for the current text only, and clear them when the text changes or after Escape. The component never calls a model.
- Keyboard: Tab accepts and Escape dismisses only while a suggestion shows at the end of the text; otherwise both keep their usual behavior. Screen readers hear the suggestion as a description.
- Documented states: Suggesting, No suggestion
```tsx
```
## WorkSummary
The steps of one agent turn, open while it works and collapsed to "Worked for 15s" after.
- Group: Tools & execution
- Import: `import { WorkSummary } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/work-summary/
- Inputs: steps · state: running | done | stopped | failed · startedAt · endedAt? · durationMs? · children? · open? · onOpenChange?
- Host responsibility: Steps and times come from your server. Pass endedAt or durationMs when the turn ends; otherwise the clock stops when the state changes.
- Documented states: Running, Done, Stopped, Failed
```tsx
```
## ChainOfThought
The public steps a run took, each with its sources or files.
- Group: Tools & execution
- Import: `import { ChainOfThought } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/chain-of-thought/
- Inputs: steps · title? · open? · onOpenChange?
- Host responsibility: Report only steps that really happened. Source links show only for http and https addresses.
- Documented states: Default, Active step, Task log, Failed step, Empty
```tsx
```
## Plan
A proposed plan with collapsible steps and a button to run it.
- Group: Tools & execution
- Import: `import { Plan } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/plan/
- Inputs: title · description? · steps? · streaming? · actions?
- Host responsibility: Showing a plan doesn’t approve or start it. Run it only after your server has checked it.
- Documented states: Default, Streaming, Without steps
```tsx
Build} />
```
## Checkpoint
A divider marking a restorable point in a conversation.
- Group: Conversation
- Import: `import { Checkpoint } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/checkpoint/
- Inputs: label? · createdAt? · onRestore? · restoring?
- Host responsibility: Restore asks your app to go back to this point; your app does it and reports what happened.
- Documented states: Default, Restoring
```tsx
```
## Sources
A "Used N sources" disclosure with safe links.
- Group: Sources & evidence
- Import: `import { Sources } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/sources/
- Inputs: sources · open? · onOpenChange?
- Host responsibility: Listing a source does not claim it supports the answer.
- Documented states: Collapsed, Expanded, Empty
```tsx
```
## ModelSelector
A compact model picker: each model with its description, and a check on the current one.
- Group: Model settings
- Import: `import { ModelSelector } from '@stackunseen/ui/assistant';`
- Page: https://unseenui.com/components/model-selector/
- Inputs: models · value · onValueChange · label? · disabled?
- Host responsibility: Check the chosen model on your server when the request runs.
- Keyboard: Enter opens the list; arrow keys move between models; Escape closes.
- Documented states: Default, Unavailable model
- Good to know: The search field shows only for more than seven models; pass `searchable` to choose.
- Good to know: Provider headings show only when the models come from more than one provider.
- Good to know: The current model has a check, not a radio circle; arrow keys still move between models.
```tsx
```
## CodeTabs
A code viewer for the files of one example, with optional numbered tour stops.
- Group: Coding & artifacts
- Import: `import { CodeTabs } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/code-tabs/
- Inputs: files: { file, language, code, label? }[] · label · value? · onValueChange? · tour?: { file, start, end, title, note }[] · stop? · onStopChange? · hashLinks? · copy? · codeBlock?
- Host responsibility: Files are keyed by name. A stop selects its file, marks its lines and scrolls the first one into view inside the pane, never the page; #tour-n links open their stop. Pass HighlightedCodeBlock as codeBlock for tokens; the plain block is the default.
- Keyboard: The file list is a tablist with arrow keys, Home and End. Stop buttons carry aria-current="step" and the open stop is announced in a polite live region.
- Documented states: Default, With tour, Single file
- Good to know: With `copy`, the file has one Copy button: the code block inside hides its own.
```tsx
```
## Snippet
A single command with a copy button.
- Group: Coding & artifacts
- Import: `import { Snippet } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/snippet/
- Inputs: code · prefix? · label?
- Host responsibility: Shown as text; it never runs.
- Documented states: Default
```tsx
```
## Commit
A commit with its subject, author and changed files.
- Group: Coding & artifacts
- Import: `import { Commit } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/commit/
- Inputs: hash · message · author? · committedAt? · files?
- Host responsibility: Shows the commit data you pass in; it never runs git.
- Documented states: Default, Files open
```tsx
```
## EnvironmentVariables
Environment variables with masked secret values.
- Group: Coding & artifacts
- Import: `import { EnvironmentVariables } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/environment-variables/
- Inputs: variables · title?
- Host responsibility: Leave secret values out when you can. Reveal only shows what you passed in; it never fetches anything.
- Documented states: Default, Empty
```tsx
```
## PackageInfo
A package change with versions and dependencies.
- Group: Coding & artifacts
- Import: `import { PackageInfo } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/package-info/
- Inputs: name · currentVersion? · newVersion? · changeType? · dependencies?
- Host responsibility: It doesn’t install or check anything.
- Documented states: Major, Added
```tsx
```
## SchemaDisplay
An API operation with parameters and nested bodies.
- Group: Coding & artifacts
- Import: `import { SchemaDisplay } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/schema-display/
- Inputs: method · path · parameters? · requestBody? · responseBody?
- Host responsibility: Read-only; it never sends a request.
- Documented states: Default
```tsx
```
## StackTrace
A readable error with internal frames collapsed.
- Group: Coding & artifacts
- Import: `import { StackTrace } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/stack-trace/
- Inputs: name · message · frames · onOpenFrame?
- Host responsibility: Opening a frame asks your app to jump to that line in an editor.
- Documented states: Default
```tsx
```
## WebPreview
A sandboxed preview of a web page, with an address bar.
- Group: Coding & artifacts
- Import: `import { WebPreview } from '@stackunseen/ui/devtools';`
- Page: https://unseenui.com/components/web-preview/
- Inputs: url · title? · onNavigate?
- Host responsibility: The page never gets access to your site, and you decide which addresses may load.
- Documented states: Default, Unsafe address
```tsx
```
## AudioPlayer
A compact player for generated or recorded audio.
- Group: Voice
- Import: `import { AudioPlayer } from '@stackunseen/ui/media';`
- Page: https://unseenui.com/components/audio-player/
- Inputs: src · label
- Host responsibility: Pass audio the person is allowed to play. Unsafe sources are refused.
- Documented states: Default, Unavailable
```tsx
```
## Transcription
A timed transcript that follows playback and can seek.
- Group: Voice
- Import: `import { Transcription } from '@stackunseen/ui/media';`
- Page: https://unseenui.com/components/transcription/
- Inputs: segments · currentTime? · onSeek?
- Host responsibility: Timings and text come from the transcription provider.
- Documented states: Default, Empty
```tsx
```
## VoiceSelector
Choose a speech voice and preview samples.
- Group: Voice
- Import: `import { VoiceSelector } from '@stackunseen/ui/media';`
- Page: https://unseenui.com/components/voice-selector/
- Inputs: voices · value · onValueChange · onPreview?
- Host responsibility: Your app plays the samples and applies the chosen voice.
- Documented states: Default
```tsx
```
## Persona
An animated presence for voice agents.
- Group: Voice
- Import: `import { Persona } from '@stackunseen/ui/media';`
- Page: https://unseenui.com/components/persona/
- Inputs: state · name? · size? · showLabel?
- Host responsibility: Pass what your voice agent is doing. Motion follows the reduced-motion setting.
- Documented states: Idle, Listening, Thinking, Speaking, Asleep
```tsx
```
## Image
A generated or attached image, with what to show while it loads or if it fails.
- Group: Coding & artifacts
- Import: `import { Image } from '@stackunseen/ui/media';`
- Page: https://unseenui.com/components/image/
- Inputs: src | base64 + mediaType · alt · caption? · state?: queued | loading | ready | failed · progress? · preview? · error? · onRetry?
- Host responsibility: Alt text is required. Progress shows only if your server measured it, and a partial preview is treated as decoration. SVG data and unsafe links are refused.
- Documented states: Ready, Queued, Loading, Generating with progress, Failed, Unavailable
```tsx
```
## Button
A labeled action in a few sizes and levels of emphasis.
- Group: Actions
- Import: `import { Button } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/button/
- Inputs: variant?: primary | secondary | outline | ghost | danger | link · size?: default | sm · href? target? rel? (renders a link) · native button props
- Host responsibility: Use a label that says what happens, and match the emphasis to how important the action is. Your app decides when it’s busy or disabled.
- Keyboard: Tab focuses an available button; Enter or Space activates it. Native disabled buttons are not focusable. This component defaults to type="button"; opt into type="submit" for forms.
- Documented states: Default, Disabled, Busy, Small, Long label, Link
```tsx
```
## IconButton
An icon-only button with a required label, shown as a hint on hover and focus.
- Group: Actions
- Import: `import { IconButton } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/icon-button/
- Inputs: label: string · icon: IconName · Button props except children, aria-label and size
- Host responsibility: Use familiar icons for secondary actions and give each a clear label. Important actions deserve a visible word.
- Keyboard: Tab reveals the label hint. Enter or Space activates the button; Escape dismisses the hint. A toggle should expose aria-pressed.
- Documented states: Default, Disabled, Toggle, Long label
- Good to know: The hint opens on hover and on keyboard focus, not when focus arrives from a click or a script.
```tsx
```
## Modal
A dialog, side sheet or full-screen panel for a focused task.
- Group: Overlays
- Import: `import { Modal } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/modal/
- Inputs: open · onOpenChange · title · description · trigger · children · layout? · header? · footer? · className? · style?
- Host responsibility: Keep whether it’s open, and any draft, in your app. Sheet and fullscreen are layouts of Modal, not separate components.
- Keyboard: Opening moves focus into the dialog. Tab remains inside; Escape closes it and returns focus to the trigger. The title and description name the task.
- Documented states: Default, Form, Long content, Custom header and footer
```tsx
Open details} footer={}>{content}
```
## Sidecar
A drawer, sheet or inspector panel: docked beside content, floating over it, and a modal drawer or bottom sheet on small screens.
- Group: Layout
- Import: `import { Sidecar } from '@stackunseen/ui/sidecar';`
- Page: https://unseenui.com/components/sidecar/
- Inputs: open · onOpenChange · title · children · trigger? · presentation? · side? · mobileBreakpoint? · initialFocusRef? · returnFocusRef? · closeOnEscape? · inset?
- Host responsibility: Keep whether it’s open, and any drafts, in your app. Docked and floating panels turn into drawers on small screens, which can reset what’s inside, so keep drafts above it.
- Keyboard: The trigger opens the inspector. Modal drawers contain focus and Escape returns it to the opener. An overlay inspector takes focus when it opens and closes on Escape from anywhere; docked panels allow working elsewhere.
- Documented states: Default, Start side, Long content, Beside a canvas
```tsx
Inspect document}>{details}
```
## SplitPane
Two panes side by side that you can resize, also from the keyboard, stacking on small screens.
- Group: Layout
- Import: `import { SplitPane } from '@stackunseen/ui/layout';`
- Page: https://unseenui.com/components/split-pane/
- Inputs: label · primary · secondary · sizes: readonly [number, number] · onSizesChange? · presentation? · orientation? · disabled?
- Host responsibility: Keep the sizes in your app and give it a container with a set height. Collapsing a pane removes its content, so keep drafts above it.
- Keyboard: Tab reaches the named separator. Arrow keys resize along its orientation; keyboard resizing requests controlled sizes just like pointer resizing.
- Documented states: Default, Read-only, Collapsed secondary, Long content
```tsx
```
## WorkspaceShell
A full app frame with header, navigation, content, inspector and footer areas that adapts to screen size.
- Group: Layout
- Import: `import { WorkspaceShell } from '@stackunseen/ui/workspace';`
- Page: https://unseenui.com/components/workspace-shell/
- Inputs: main · header? · navigation? · inspector? · footer? · mainAs? · scrollMode? · variant? · navigationMode?: inline | responsive · navigationOpen? · onNavigationOpenChange? · navigationBreakpoint? · headerPlacement?: span | main
- Host responsibility: Pass your real navigation and control which panels show. Use mainAs="section" when it sits inside another main region.
- Keyboard: Slot controls retain document Tab order. Flow mode shares page scrolling; panes mode requires a bounded height and named reading regions. In responsive mode the toggle reports aria-expanded; a narrow drawer takes focus, closes on Escape, the scrim or a followed link, and returns focus to the toggle.
- Documented states: Default, Responsive navigation, With inspector, Minimal, Long content
- Good to know: Scrolling panes keep 4px of padding and room for a scrollbar. When a pane’s content scrolls itself (a chat, a sidebar list), set `--ai-workspace-pane-padding: 0` and `--ai-workspace-pane-gutter: auto`.
```tsx
```
## SlashCommandMenu
Find and run your app’s slash commands from the keyboard.
- Group: Conversation
- Import: `import { SlashCommandMenu } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/slash-command-menu/
- Inputs: items · query · onQueryChange · onSelect · status?
- Host responsibility: Give each command an ID, and check it’s allowed when your app runs it.
- Documented states: Default, Empty, Loading, Error, Unavailable
```tsx
```
## MentionPicker
Type @ to add files, symbols, people or sources.
- Group: Context & memory
- Import: `import { MentionPicker } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/mention-picker/
- Inputs: items · query · onQueryChange · onSelect
- Host responsibility: Check permissions and versions in your app. Picking something doesn’t guarantee the model sees it.
- Documented states: Default, Empty, Loading, Error, Unavailable
```tsx
```
## AccessModeSelector
Ask for a different access level while keeping current permissions in view.
- Group: Review & permissions
- Import: `import { AccessModeSelector } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/access-mode-selector/
- Inputs: modes · value · scope · version · status · onRequest
- Host responsibility: Your server authorizes the request and confirms it; the component never grants access.
- Documented states: Default, Pending, Stale, Error
```tsx
```
## VoiceControl
Pick a microphone, record, watch the input level and follow the transcription.
- Group: Voice
- Import: `import { VoiceControl } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/voice-control/
- Inputs: capture / legacy state · transcription · status · connection · submission · scoped start/stop/cancel/device requests · devices?
- Host responsibility: Your app handles microphone permission, recording, releasing the device and transcription. The examples here only pretend to record.
- Documented states: Default, Listening, Processing, Permission denied, Unsupported, Error, Requesting, Stopping, Complete, Cancelled, Interrupted, Unknown capture, Loading, Denied, Unavailable, Unknown availability, Stale, Disconnected, Pending, Unknown action, Muted, Unknown level, Partial transcript, Complete transcript, Obsolete transcript, Long transcript, Missing device, Device limit, Invalid context, Read-only, Live versions, Idle transcript, Transcription error, Unknown transcript, Transcript limit, Invalid level, Duplicate devices, Cancelled permission request
```tsx
```
## FileExplorer
Browse files as folders, a detailed list or a directory tree.
- Group: Coding & artifacts
- Import: `import { FileExplorer } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/file-explorer/
- Inputs: files · context? · selection? · onRequestOpen? · expandedPaths · query? · pagination? · status
- Host responsibility: Pass the files to show, a page at a time, with their versions and who may open them, and confirm each open request. The component never reads a filesystem.
- Documented states: Default, Changed files, Selected file, Selection pending, Obsolete selection, File version changed, Missing selection, Workspace changed, Access revoked, Unknown file access, Empty, Filtered, No matches, Known pages, Unknown total, Unknown next, Invalid page, Long paths, Deep folders, Root directory collision, Denied, Loading, Unavailable, Error, Unknown, Stale, Refreshing, Invalid paths, Duplicate IDs, Window limit, Bounds, Read-only, Missing scope, Icon overrides
- Good to know: Only the metadata the server supplies is shown; nothing is inferred from the name.
```tsx
```
## CodeDiff
Code changes, inline or side by side, with line numbers and clear size limits.
- Group: Coding & artifacts
- Import: `import { CodeDiff } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/code-diff/
- Inputs: path · before · after · baseVersion · nextVersion · status? · error? · copyable? · renderLine?
- Host responsibility: Pass the before and after text and whether it can be read. Copying never changes files; applying a patch is up to your app. For syntax colors, use HighlightedCodeDiff from the /highlight entry.
- Documented states: Default, No changes, Conflict, Denied, Loading, Error, Unavailable, Large diff, Highlighted, Multiline, Replacements, CRLF source, Unsupported language, Highlight limit, Untrusted HTML, Invalid version, Live versions
```tsx
```
## TerminalOutput
Process output that follows new lines (unless you’re selecting text), with a stop button.
- Group: Coding & artifacts
- Import: `import { TerminalOutput } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/terminal-output/
- Inputs: output · state · context? · status? · connection? · submission? · scoped stop/clear · optional /terminal input/resize
- Host responsibility: Your app runs the process, streams the output and authorizes stops. The main entry shows plain output; /terminal adds a full xterm view. Nothing here runs a shell.
- Documented states: Default, Running, Failed, Empty, Long output, Unknown, ANSI, Cursor updates, Terminal input, Blocked controls, Disconnected, Reconnecting, Denied, Loading, Unavailable, Error, Stale, Action pending, Unknown action, Live versions, Invalid context, Truncated ANSI
```tsx
```
## TestResults
Test outcomes, timings, diagnostics and file navigation.
- Group: Coding & artifacts
- Import: `import { TestResults } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/test-results/
- Inputs: results · onOpenFile? · loading?
- Host responsibility: Pass the results and durations from your test runner. Skipped or waiting tests never count as passed.
- Documented states: Default, Failed, Running, Empty, Loading
```tsx
```
## ThreadList
Search, open, rename and archive conversations.
- Group: Conversation
- Import: `import { ThreadList } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/thread-list/
- Inputs: threads · query · context? · status? · pagination? · actions? · groupBy?: none | date · now? · rowActions? · scoped requests or legacy callbacks
- Host responsibility: Save edits on your server and confirm them, and load the list a page at a time.
- Documented states: Default, Date groups, Empty, Loading, Error, Long titles, Pending, Read-only, Denied, Unavailable, Unknown, Stale, Disconnected, Paged, Unknown total, Outcome unknown, Obsolete request, Invalid window
- Good to know: Compact rows are 36px with 1px between them, and showing their actions never changes a row’s height.
- Good to know: In a sidebar that scrolls, set `--ai-navigation-height: none` and `--ai-navigation-gutter: auto` so the list grows instead of scrolling inside it; `--ai-list-inset` lines rows up with your navigation.
```tsx
```
## BranchSwitcher
Move between versions of a conversation created by edits and retries.
- Group: Conversation
- Import: `import { BranchSwitcher } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/branch-switcher/
- Inputs: branches · value · context? · changeGuard? · scoped request or onValueChange
- Host responsibility: Keep branches on your server, and save any unsent draft before switching.
- Documented states: Default, Missing, Disabled, Empty, Draft guard, Loading, Denied, Unavailable, Unknown, Stale, Disconnected, Outcome unknown, Obsolete request, Invalid window
```tsx
```
## MessageQueue
Review, reorder and remove messages waiting to send.
- Group: Conversation
- Import: `import { MessageQueue } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/message-queue/
- Inputs: items · context? · status? · pagination? · scoped requests or legacy callbacks
- Host responsibility: Confirm each change against the item’s version, and keep showing results you aren’t sure of yet.
- Documented states: Default, Sending, Failed, Pending, Empty, Long drafts, Cancelled, No reorder, Sent, Send unknown, Loading, Denied, Unavailable, Unknown, Stale, Disconnected, Paged, Unknown total, Outcome unknown, Obsolete request, Invalid window
- Good to know: Rows that are simply queued carry no tag; sending, failed and unknown outcomes do.
```tsx
```
## AgentHandoff
Hand work from one agent or person to another, with accept and decline.
- Group: Agents & governance
- Import: `import { AgentHandoff } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/agent-handoff/
- Inputs: value: HandoffSnapshot · commandId · submission · onDecision · onReconcile?
- Host responsibility: Check who the recipient is on your server and confirm exactly what is being handed over. Accepting a request doesn’t move the work until your server confirms it.
- Documented states: Default, Pending, Accepted, Declined, Expired, Denied, Revoked, Stale, Unknown owner, Unknown outcome, Context changed
```tsx
```
## ReviewChanges
Pick which proposed changes to keep and send one review decision.
- Group: Review & permissions
- Import: `import { ReviewChanges } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/review-changes/
- Inputs: changes · baseVersion · proposalVersion · selectedIds · onSelectionChange · state · onDecision
- Host responsibility: Recheck the starting version and the selection on your server, then confirm whether the changes were applied or rejected.
- Documented states: Default, Pending, Stale, Conflict, Accepted, Empty
```tsx
```
## AIForm
Forms with fields that appear as needed, validation and confirmed submission.
- Group: Forms & generated UI
- Import: `import { AIForm } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/ai-form/
- Inputs: fields · values · arrays? · arrayValues? · onArrayChange? · steps? · step? · onStepChange? · identity? · status? · receipt?
- Host responsibility: Save drafts with a version, keep row IDs stable, validate on your server, control the steps and confirm each submission.
- Documented states: Default, Validation, Pending, Complete, Error, Repeated fields, Multistep, Restored draft, Empty array, Array limits, Invalid schema, Invalid rows, Denied, Loading, Stale, Unavailable, Live versions, Long labels
```tsx
```
## GeneratedUI
Screens a model describes, such as forms, charts, tables, lists and steps, checked before they render.
- Group: Forms & generated UI
- Import: `import { GeneratedUI } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/generated-ui/
- Inputs: surface: unknown · state · forms / onFormChange · actionStates / onAction · problems? · imageOrigins?
- Host responsibility: Authorize every action on your server, keep form drafts and their confirmations, and check unclear results before retrying. Generated data can never supply code to run.
- Documented states: Default, Streaming, Pending, Stale, Unsupported, Empty, Sections, Generated form, Loading, Denied, Unavailable, Error, Action completed, Action error, Unknown outcome, Action rail, Denied form, Pending with denied form, Invalid schema, Bounds, Live versions, Long labels, Streamed program, Vocabulary
```tsx
```
## Chart
Bar, line and area charts with a matching data table, and gaps where data is missing.
- Group: Forms & generated UI
- Import: `import { Chart } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/chart/
- Inputs: title · points or series · unit · source · state · hiddenSeries · onSeriesVisibilityChange
- Host responsibility: Pass measured data with its units and where it came from, and null for missing points. Up to four series of 60 points each; the data table always lists every value.
- Documented states: Default, Empty, Negative values, Invalid data, Multiple series, Missing values, All missing, Hidden series, All hidden, Selection pending, Streaming, Stale, Loading, Denied, Unavailable, Error, Currency, Scientific, Long labels, Many categories, Invalid alignment, Invalid selection, Unknown
```tsx
```
## MemoryControls
See what the assistant remembers, and ask to correct or delete it.
- Group: Context & memory
- Import: `import { MemoryControls } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/memory-controls/
- Inputs: items · onRequest
- Host responsibility: Your server authorizes, saves and confirms each correction or deletion.
- Documented states: Default, Pending, Revoked, Error, Empty
```tsx
```
## ArtifactDiff
Compare two versions of a document, with a fallback when one can’t be opened.
- Group: Coding & artifacts
- Import: `import { ArtifactDiff } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/artifact-diff/
- Inputs: path · versions · beforeId · afterId · onVersionsChange
- Host responsibility: Load the two chosen versions, and never quietly swap in a different one.
- Documented states: Default, Missing version, Revoked, No changes
```tsx
```
## WorkflowGraph
See a workflow’s branches, loops and joins as a graph, a list or an outline.
- Group: Tools & execution
- Import: `import { WorkflowGraph } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/workflow-graph/
- Inputs: nodes · edges · selection? · onSelect? · onEdgeSelect? · state · source · version · detail?
- Host responsibility: Pass the steps, their positions and where each one stands. Compact is an outline that marks loops and shared steps; list shows what connects to what. Nothing runs from the graph.
- Documented states: Default, Branches and join, Self-loop, Return loop, Parallel edges, Obstacle routing, Host route, Unroutable, Disconnected, Cyclic component, Selected node, Selected connection, Selection pending, Obsolete selection, Overlapping nodes, Long labels, Window limit, Bounds, Empty, Invalid graph, Loading, Denied, Unavailable, Error, Unknown, Stale, Streaming
```tsx
```
## AuditTrail
A searchable history of actions and their outcomes, with sensitive fields hidden.
- Group: Agents & governance
- Import: `import { AuditTrail } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/audit-trail/
- Inputs: records · query · onQueryChange · onLoadMore? · loading?
- Host responsibility: Pass verified records with protected fields already removed. It shows history; it doesn’t store it securely.
- Documented states: Default, Redacted, Empty, Loading
```tsx
```
## RunInspector
Look inside a run: each model, tool and agent step, with measured usage.
- Group: Tools & execution
- Import: `import { RunInspector } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/run-inspector/
- Inputs: runId · spans · usage? · onSelect? · detail?
- Host responsibility: Pass public summaries and measured costs. Never pass private reasoning.
- Documented states: Default, Running, Failed, Unknown usage, Empty
```tsx
```
## MarkdownResponse
Formatted replies as they stream: headings, lists, tables, code, links and footnotes.
- Group: Rich Content
- Import: `import { MarkdownResponse } from '@stackunseen/ui/markdown';`
- Page: https://unseenui.com/components/markdown-response/
- Inputs: text · state · headingLevel? · variant · citations?: Source[]
- Host responsibility: From the /markdown entry. Raw HTML stays as text, and images from other sites never load on their own.
- Documented states: Markdown, Code, Table, Footnotes, Inline citations, Incomplete Markdown, Live stream, Unsafe content
```tsx
```
## MarkdownCodeBlock
Code with a copy button, optional syntax colors and line numbers.
- Group: Rich Content
- Import: `import { MarkdownCodeBlock } from '@stackunseen/ui/code';`
- Page: https://unseenui.com/components/markdown-code-block/
- Inputs: code · language? · streaming? · variant
- Host responsibility: Plain from /code, or colored with Shiki from /highlight. It’s text only; nothing runs or edits it.
- Documented states: Default, Streaming, Long code, Empty, Highlighted, JSX, Python, Unsupported language, Highlight limit, Untrusted HTML, CRLF source
```tsx
```
## RichMarkdownResponse
Markdown that also renders math and Mermaid diagrams.
- Group: Rich Content
- Import: `import { RichMarkdownResponse } from '@stackunseen/ui/rich-markdown';`
- Page: https://unseenui.com/components/rich-markdown-response/
- Inputs: text · state · headingLevel? · variant
- Host responsibility: Install the math and diagram packages and load the KaTeX styles. Diagrams draw once the reply is complete.
- Documented states: Default, Streaming, Invalid formula, Unsafe diagram
```tsx
```
## MathFormula
LaTeX formulas, rendered with KaTeX and readable by screen readers.
- Group: Rich Content
- Import: `import { MathFormula } from '@stackunseen/ui/math';`
- Page: https://unseenui.com/components/math-formula/
- Inputs: formula · label? · variant
- Host responsibility: Load the KaTeX CSS. Formulas can’t run commands, and their size is capped.
- Documented states: Default, Matrix, Integral, Invalid, Oversized
```tsx
```
## MermaidDiagram
Mermaid diagrams with zoom and a source view, and a clear message when one can’t be drawn.
- Group: Rich Content
- Import: `import { MermaidDiagram } from '@stackunseen/ui/mermaid';`
- Page: https://unseenui.com/components/mermaid-diagram/
- Inputs: code · title? · description? · state? · variant
- Host responsibility: Needs the Mermaid package. Diagrams can’t change settings, add click actions or load anything from other sites.
- Documented states: Default, Sequence, Class, State, Entity relationship, Gantt, Pie, Mindmap, Timeline, Git graph, Math labels, Sequence math, Streaming, Invalid, Restricted, Blocked resource
```tsx
```
## ConnectionStatus
Whether you’re connected, with the reconnect and catch-up actions your app supports.
- Group: Tools & execution
- Import: `import { ConnectionStatus } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/connection-status/
- Inputs: value: ConnectionInfo · submission? · onResume? · onRefresh?
- Host responsibility: Only offer the recovery actions your connection really supports. Asking to reconnect isn’t the same as being reconnected, and it never starts a new run.
- Documented states: Disconnected, Connected, Reconnecting, Resumed, Incompatible, No replay, Unknown outcome, Connected stale, Connected unknown, Snapshot unavailable, Error
```tsx
```
## ModelControls
Model capabilities, settings and usage, each showing where the value came from.
- Group: Model settings
- Import: `import { ModelControls } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/model-controls/
- Inputs: capabilities · value: ModelSettings · onValueChange · status? · stale? · usage?
- Host responsibility: Look up what each model supports on your server, save the draft settings, and check settings and access when the request runs. Usage numbers need a source and a time.
- Documented states: Default, Loading, Unavailable, Stale, Unsupported, Error, Usage unknown
```tsx
```
## ContextInspector
Lists what a request selected, included, excluded or truncated.
- Group: Context & memory
- Import: `import { ContextInspector } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/context-inspector/
- Inputs: value: ContextInspection · loading? · error? · onRefresh?
- Host responsibility: Pass a versioned snapshot of the context, and say whether token counts are measured or estimated. Picking an item doesn’t guarantee it was included.
- Documented states: Default, Stale, Unknown usage, Over limit, Empty, Loading, Error
```tsx
```
## PolicyStatus
Policy check results, with who checked, when, what they covered and which version.
- Group: Agents & governance
- Import: `import { PolicyStatus } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/policy-status/
- Inputs: checks: PolicyCheck[] · classification? · loading? · error? · onRefresh?
- Host responsibility: The system that runs the checks supplies and refreshes the results. Missing details never count as a pass, and the component never authorizes anything.
- Documented states: Default, Passed, Blocked, Stale, Unknown, Loading, Empty, Error
```tsx
```
## Select
A dropdown for picking one option, with full keyboard support.
- Group: Forms
- Import: `import { Select } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/select/
- Inputs: value · onValueChange · options · disabled?
- Host responsibility: Give it a label, and mark choices that aren’t available as disabled.
- Documented states: Default, Disabled, Long labels
- Good to know: The empty value a form’s hidden native select reports is ignored, so a choice never resets to the placeholder.
```tsx
```
## Accordion
Sections people can open and close.
- Group: Data Display
- Import: `import { Accordion } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/accordion/
- Inputs: items · type · value? · onValueChange? · headingLevel?
- Host responsibility: Keep anything people need to make a decision outside the collapsed sections.
- Documented states: Default, Single, Long labels
```tsx
```
## Tabs
Switch between related views of the same thing.
- Group: Navigation
- Import: `import { Tabs } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tabs/
- Inputs: value · onValueChange · items · label · orientation?: horizontal | vertical
- Host responsibility: Give each tab a stable ID and a clear label. A tab opens as soon as it gets focus.
- Documented states: Default, Long labels, Vertical
```tsx
```
## LoadingIndicator
Shows that something is happening, without pretending to know how far along it is.
- Group: Feedback
- Import: `import { LoadingIndicator } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/loading-indicator/
- Inputs: variant · label · size
- Host responsibility: Show it while the work is in progress. It never shows a percentage.
- Documented states: Default, Small, Large, Long labels
```tsx
```
## Skeleton
Placeholders that hold space while real content loads.
- Group: Feedback
- Import: `import { Skeleton } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/skeleton/
- Inputs: variant · label · lines · shape
- Host responsibility: Swap the placeholders for real content when it arrives, and keep a loading label for screen readers.
- Documented states: Default, Card, Avatar
```tsx
```
## PromptInput
The composer for sending a prompt, with attachments, a toolbar and a way to stop.
- Group: Conversation
- Import: `import { PromptInput } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/prompt-input/
- Inputs: value · onValueChange · onSubmit · busy · onCancel · attachments? · toolbar? · submitDisabled? · allowEmptySubmit? · limit? · variables? onInsertVariable? · assist?
- Host responsibility: Your server takes the prompt, and confirms when a stop has worked.
- Documented states: Default, Busy, Disabled, Attachments, Toolbar, Long toolbar, Send unavailable, Too long, Variables, Counter
```tsx
```
## Message
One user, assistant or system message with its parts and references.
- Group: Conversation
- Import: `import { Message } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/message/
- Inputs: value: MessageData · sources? · tools? · attachments? · renderTextPart? · renderContent? · children
- Host responsibility: Give each message a stable ID, its role and a revision number.
- Documented states: Default, Streaming, Interrupted, Markdown, Code, Table, Footnotes, Long code, Unsafe content, Live stream, Mixed parts, Streaming parts, Failed parts, Interrupted parts, Missing parts, Revoked source, Changed source, Unsupported part, Empty parts, Live parts, Long parts, Long single
- Good to know: In the chat variant a Markdown reply reads at the message size (16px), not the interface size.
- Good to know: Earlier replies keep their actions hidden until hovered or focused; the last reply always shows them.
```tsx
```
## MessageActions
Copy, retry, edit and feedback buttons for a message, each showing whether it worked.
- Group: Conversation
- Import: `import { MessageActions } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/message-actions/
- Inputs: text · onRetry? · onEdit? · onFeedback?
- Host responsibility: Only show actions your app supports.
- Documented states: Default
```tsx
```
## StreamingResponse
Shows an answer as it streams in, and says clearly if it was cut off or failed.
- Group: Conversation
- Import: `import { StreamingResponse } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/streaming-response/
- Inputs: text · state · error? · renderContent? · progress? onStop? · followUps? onFollowUp?; optional MarkdownResponse from /markdown
- Host responsibility: The main entry shows plain text. Import the Markdown entry for formatted replies, including half-finished ones. Your app owns the message state and decides which links to trust.
- Documented states: Live stream, Streaming, Default, Waiting, Interrupted, Markdown, Code, Table, Incomplete Markdown, Unsafe content, Footnotes, Long code, Large content, Long labels, Progress, Follow-ups
```tsx
```
## Suggestions
Follow-up prompts the user can send with one click.
- Group: Conversation
- Import: `import { Suggestions } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/suggestions/
- Inputs: items · onSelect · mode: fill | send
- Host responsibility: Choose whether picking a suggestion fills the composer or sends it.
- Documented states: Default, Disabled
```tsx
```
## FollowUps
Short next steps after a response, as chips with a lead word: "Then: Shorter · Add numbers".
- Group: Conversation
- Import: `import { FollowUps } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/follow-ups/
- Inputs: items: { id, label }[] · onSelect(item) · lead? · label? · disabled?
- Host responsibility: A chip only asks. Your app sends the follow-up, shows what it did and decides when the chips go away. StreamingResponse renders these itself once the answer is complete.
- Documented states: Default, Disabled, Custom lead
```tsx
```
## Attachment
Files attached to a message, with real upload progress and previews.
- Group: Conversation
- Import: `import { Attachment } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/attachment/
- Inputs: name · state · mediaType? · sizeBytes? · progress? · access? · preview? · onRemove? · onRetry? · onOpen? · Root / Preview / Info / Actions / Progress
- Host responsibility: Your server checks, uploads and stores the files, and confirms each change. The checks in the browser don’t look inside a file.
- Documented states: Default, Selected, Uploading, Unknown progress, Awaiting confirmation, Unknown outcome, Failed, Removing, Cancelled, Removed, Upload checkpoint, Lost upload receipt, Resume unsupported, Resume unknown, Stale upload, Upload revoked, Long filename, Image, Text, Audio, Video, Revoked, Expired, Missing, Broken preview, Blocked URL, Collection
- Good to know: Media types show as short names such as CSV, PDF or "PNG image".
- Good to know: Ready is announced to screen readers but not shown; other upload states are shown.
```tsx
```
## FileDropzone
A drop target for local files with a browse button and type, size and slot checks.
- Group: Conversation
- Import: `import { FileDropzone } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/file-dropzone/
- Inputs: onFilesSelected · onReject? · accept? · maxFileBytes? · remainingSlots? · multiple? · disabled? · label? · browseLabel? · hint?
- Host responsibility: Dropped or chosen files stay in the browser as File objects. Your app checks what’s in them, uploads and stores them.
- Keyboard: Tab reaches the browse button; Enter or Space opens the file chooser.
- Documented states: Default, Single file, Rejected, Disabled, Full
```tsx
```
## AgentSteps
The steps of a run in order, with where each one stands, its details and anything it depends on.
- Group: Tools & execution
- Import: `import { AgentSteps } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/agent-steps/
- Inputs: steps: Step[] · label? · dependencies? · selectedId? · onSelect?(id)
- Host responsibility: Supply public summaries, not private model reasoning.
- Documented states: Default, Failed, Dependencies, Empty
- Good to know: A finished step shows only its check; running, failed and blocked steps add a badge. The words stay available to screen readers.
```tsx
```
## ExecutionTimeline
A timed record of what happened during a run, as a list, a table or a waterfall with tokens and cost per step.
- Group: Tools & execution
- Import: `import { ExecutionTimeline } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/execution-timeline/
- Inputs: entries: { id, label, state, timestamp, durationMs?, detail?, cost?, tokens?, parentId? }[] · filter · onFilterChange? · detail?
- Host responsibility: Times, durations, tokens and cost come from your server, already formatted. The waterfall folds steps under their parentId and marks the slowest measured step.
- Documented states: Default, Waterfall, Empty
```tsx
```
## RunBoard
All your runs on one board, grouped by what they need, with live clocks, the newest steps, filters and actions.
- Group: Tools & execution
- Import: `import { RunBoard } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/run-board/
- Inputs: runs: RunCard[] (steps?, model?, startedAt?, cost?) · filter? · onFilterChange? · selectedId? · onSelect? · onAction? · receipts? · staleAfterMs? · now? · label? · renderCardTrailing?
- Host responsibility: Status, times and heartbeats come from your server. A run that has gone quiet is flagged, never assumed finished. An action counts as done only once your server confirms it.
- Keyboard: Arrow keys move between cards and columns; Home and End jump within a column; Enter opens a run.
- Documented states: Default, Live steps, Stale heartbeat, Failed, Filtered, Empty
```tsx
```
## AgentLanes
Where every agent is right now: a lane per agent on one time axis, with the hand-offs drawn between lanes.
- Group: Tools & execution
- Import: `import { AgentLanes } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/agent-lanes/
- Inputs: lanes: { agent, tasks: { id, title, state, startedAt, endedAt?, handoffTo?, cost? }[] }[] · now? · window? · selectedId? · onSelect? · label?
- Host responsibility: Start and end times come from your server; a task without an end reaches the host clock. A hand-off is drawn only when both tasks are on the board. The same tasks are in a hidden table.
- Keyboard: Each block is a button in reading order; Enter selects it.
- Documented states: Default, Hand-offs, Single lane, Empty
```tsx
```
## AttentionQueue
The ordered list of approvals, questions, handoffs and failures waiting on a person.
- Group: Tools & execution
- Import: `import { AttentionQueue } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/attention-queue/
- Inputs: items: AttentionItem[] · count? · onOpen · onDismiss? · label?
- Host responsibility: It lists items; opening one shows the right control to act on it. The count comes from your server and says so when it isn’t known.
- Keyboard: Arrow keys move between items; Enter opens; Dismiss is a separate button.
- Documented states: Default, Unknown count, Empty
```tsx
```
## RunSummaryCard
What a run did, for reading afterwards: the goal, the outcome, what it changed and what was left undone.
- Group: Tools & execution
- Import: `import { RunSummaryCard } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/run-summary-card/
- Inputs: summary: RunSummary · receipts? · onOpenEffect? · actions?
- Host responsibility: A change counts as done only when your server has confirmed it. Outcomes you don’t know are shown as unknown, not hidden. Time and cost say how they were measured.
- Documented states: Succeeded, Partial, Failed, Unknown outcome
```tsx
```
## BackgroundStatus
A small persistent indicator for runs still going while the person is elsewhere.
- Group: Tools & execution
- Import: `import { BackgroundStatus } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/background-status/
- Inputs: running · waiting · lastHeartbeatAt? · staleAfterMs? · now? · onOpen?
- Host responsibility: Your app updates the counts; the indicator never polls. If updates stop arriving, it says so.
- Documented states: Running, Waiting, Stale, Idle
- Good to know: Zero counts are hidden and an idle status reads "Nothing running". An unknown count still shows, as "?".
```tsx
```
## RunCompare
Two runs or checkpoints side by side: outcome, measurements, effects and timelines.
- Group: Tools & execution
- Import: `import { RunCompare } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/run-compare/
- Inputs: left · right: { label, summary, timeline?, receipts? } · onlyDifferences? · onOnlyDifferencesChange? · artifacts?
- Host responsibility: Rows compare server data only. An effect is confirmed on a side only by that side's acknowledged receipt. Artifact comparison is supplied by the server.
- Documented states: Default, Only differences, With timelines, Identical
```tsx
```
## SubagentTree
Parent and child runs as a tree with the message that spawned each child, and the cost of each branch.
- Group: Tools & execution
- Import: `import { SubagentTree } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/subagent-tree/
- Inputs: root: RunNode (cost?) · selectedId? · onSelect? · onLoadMore? · maxDepth? · expandedIds? · onExpandedChange? · now? · locale?
- Host responsibility: Your app sends the tree and loads more children when asked. Very deep trees show a count and load the rest on request. A branch total is only shown when every run in it reports a cost in one currency.
- Keyboard: Arrow keys move and expand or collapse; Home and End jump; typing a letter jumps to the next matching run; Enter selects.
- Documented states: Default, Costs, Stale child, Depth limit, More to load
```tsx
```
## AgentSteering
Queue a note for a running agent’s next step without stopping it, and see whether each note was applied.
- Group: Tools & execution
- Import: `import { AgentSteering } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/agent-steering/
- Inputs: run: Run · notes: SteeringNote[] · onSubmit({ runId, runVersion, text }) · submission? · disabledReason? · maxLength?
- Host responsibility: A note carries the run version it was written against; your server applies, holds or rejects it and reports which. The draft stays until the server has the note, and a finished run takes none.
- Keyboard: Tab to the field; Enter in the form sends; the button is disabled while sending.
- Documented states: Default, Sending, Acknowledged, Failed, Finished run
```tsx
```
## CostLedger
Where the money went, run by run, with measured and estimated costs kept apart and never added together.
- Group: Tools & execution
- Import: `import { CostLedger } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/cost-ledger/
- Inputs: rows: CostLedgerRow[] · total? · period? · onOpen? · locale?
- Host responsibility: The footer adds only measured rows and counts the estimated and unknown ones, unless your billing supplies the total. Rows in two currencies get no sum.
- Documented states: Default, Host total, Mixed currencies, Empty
```tsx
```
## ToolCall
A tool request with its input, result, failure and duration.
- Group: Tools & execution
- Import: `import { ToolCall } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tool-call/
- Inputs: value: ToolCallData · Root / Summary / Input / Result · detail?
- Host responsibility: Your server runs the tools and reports what actually happened.
- Documented states: Default, Running, Failed, Unknown, Queued, Receiving input, Needs approval, Cancelled, Denied, No output, Failed without details
```tsx
```
## ToolResult
Tool output, size-limited, with a safe fallback for content it can’t show.
- Group: Tools & execution
- Import: `import { ToolResult } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tool-result/
- Inputs: text? · result? · partial? · error? · maxCharacters? · onRetry? · ToolResultRegistryProvider
- Host responsibility: Remove secrets before passing content to any UI. Custom renderers are your own code, picked by your match function, and partial counts come from your server.
- Documented states: Default, Failed, Empty, Partial, Host renderer
```tsx
```
## ToolGroup
Several tool calls grouped together, keeping each failure visible.
- Group: Tools & execution
- Import: `import { ToolGroup } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/tool-group/
- Inputs: tools: ToolCallData[] · detail?
- Host responsibility: A group summary does not erase a failed call.
- Documented states: Default, Failed, Empty
```tsx
```
## ApprovalCard
A review card for approving or rejecting a proposed action.
- Group: Review & permissions
- Import: `import { ApprovalCard } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/approval-card/
- Inputs: proposal · submission · stale? · expired? · onDecision · onReconcile?
- Host responsibility: On your server: check who is asking, recheck the scope, version and expiry, ignore duplicates, then run the action.
- Documented states: Default, Pending, Expired, Changed, Unknown
```tsx
```
## PermissionRequest
A request for specific access, with its scope and version shown.
- Group: Review & permissions
- Import: `import { PermissionRequest } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/permission-request/
- Inputs: value: PermissionSnapshot · commandId · submission · onDecision · onReconcile?
- Host responsibility: Authorize the exact scope on your server, keep the original request and confirm it back. Granting access is separate from approving an action, and reconnecting must never resend a decision.
- Documented states: Default, Pending, Granted, Denied, Revoked, Missing scope, Missing resource, Expired, Stale, Unknown outcome, Scope changed
```tsx
```
## ScopeGrant
Permissions that stay in place, with their scope, expiry, how often they were used, and a way to revoke them.
- Group: Review & permissions
- Import: `import { ScopeGrantList } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/scope-grant/
- Inputs: grants: ScopeGrant[] · onRevoke? · receipts? · now? · label?
- Host responsibility: Grants live on your server, and expiry uses your server’s clock. A revoke counts as done once your server confirms it.
- Documented states: Default, Empty
- Good to know: An expired grant says so in its badge only.
- Good to know: Uses the server does not count read "Uses not counted", with the reason.
```tsx
```
## DryRunPreview
The agent's declared effects before anything runs, with a veto per line and one versioned decision.
- Group: Review & permissions
- Import: `import { DryRunPreview } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/dry-run-preview/
- Inputs: plan: DryRunPlan · skippedIds · onSkippedChange · onDecision · submission? · receipt? · stale?
- Host responsibility: Nothing runs in the browser. The decision says which plan version it covers and which changes to skip; your server re-plans and runs it.
- Keyboard: Each effect is a checkbox; Run and Cancel are buttons.
- Documented states: Default, Some skipped, Sending, Acknowledged, Plan changed
```tsx
```
## ApprovalBatch
Approve several similar proposals at once, and still leave any of them out.
- Group: Review & permissions
- Import: `import { ApprovalBatch } from '@stackunseen/ui/conversation-flow';` and `import '@stackunseen/ui/conversation-flow.css';`
- Page: https://unseenui.com/components/approval-batch/
- Inputs: proposals · excludedIds · onExcludedChange · onDecision · submission? · receipt? · now?
- Host responsibility: One decision covers only proposals that are pending, unexpired, included and share a target and scope. It names each one exactly, and your server’s reply says which ones it applied.
- Documented states: Default, One superseded, Mixed scopes, Acknowledged
```tsx
```
## UsageMeter
How much context or money has been used, with what the number means. A percentage shows only when there’s a known limit.
- Group: Tools & execution
- Import: `import { UsageMeter } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/usage-meter/
- Inputs: label · value: Measurement<{ used, limit? }> · unit? · currency? · warnAt? · locale?
- Host responsibility: Measured, estimated and unknown numbers look different. Without a limit there’s no percentage, and an unknown amount shows the reason instead of zero.
- Documented states: Default, Near limit, No limit, Cost, Unknown
```tsx
```
## ContextWindowMeter
How full the model’s context window is and what fills it, drawn to scale from the numbers your server supplies.
- Group: Tools & execution
- Import: `import { ContextWindowMeter } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/context-window-meter/
- Inputs: value: Measurement<{ segments, limit? }> · warnAt? · label? · locale?
- Host responsibility: Segments come from your server, not from counting in the browser. A percentage shows only with a limit; an estimate says what it was estimated from; an unknown window shows the reason.
- Documented states: Default, Near limit, No limit, Estimated, Unknown
```tsx
```
## ProvenanceBadge
Where content came from (a model, a tool, a person or an import), marked Signed only when your server verified it.
- Group: Sources & evidence
- Import: `import { ProvenanceBadge } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/provenance-badge/
- Inputs: origin · source? · manifest? ({ issuer, verifiedBy: host, at })
- Host responsibility: The badge itself never verifies anything; whatever your server didn’t verify shows as unverified.
- Documented states: Default, Signed, Tool, Person, Imported
```tsx
```
## ConfidenceNote
A confidence score with what it covers, how it was worked out and when, or nothing at all. Never a bare number.
- Group: Sources & evidence
- Import: `import { ConfidenceNote } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/confidence-note/
- Inputs: score: Measurement · scope · method · at? · locale?
- Host responsibility: Shows nothing for an unknown or invalid score, so a page never claims confidence it doesn’t have.
- Documented states: Default, Estimated, Unknown
```tsx
```
## FeedbackCapture
Thumbs up or down, reasons and a correction for one specific reply, saved once your server confirms.
- Group: Conversation
- Import: `import { FeedbackCapture } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/feedback-capture/
- Inputs: target · value: FeedbackDraft · onValueChange · onSubmit · reasons? · submission? · receipt? · maxLength?
- Host responsibility: Feedback names the exact version of the reply it’s about. The form waits while your server answers; if saving fails or the result is unclear, the draft stays and the form says what to do.
- Keyboard: Helpful and Not helpful are toggle buttons; reasons are checkboxes; Enter in the form sends.
- Documented states: Default, Not helpful, Sending, Acknowledged, Failed, Outcome unknown
```tsx
```
## ChatLauncher
A floating chat bubble for a website that opens a chat panel, full screen on phones.
- Group: Conversation
- Import: `import { ChatLauncher } from '@stackunseen/ui/chat';` and `import '@stackunseen/ui/chat.css';`
- Page: https://unseenui.com/components/chat-launcher/
- Inputs: open · onOpenChange · title · children · label? · placement?: bottom-end | bottom-start · unread?
- Host responsibility: Put a Chat inside. The panel stays mounted while closed so the conversation and draft survive; count unread replies on your side.
- Keyboard: The bubble reports aria-expanded. Opening focuses the composer; Escape or Close returns focus to the bubble. The panel is non-modal, so the page stays usable.
- Documented states: Closed, Open, Unread
```tsx
```
## Chat
A complete chat: messages, streaming replies, tool cards, suggestions, stop, retry and the composer. Connect it to your server or drive it with props.
- Group: Conversation
- Import: `import { Chat } from '@stackunseen/ui/chat';` and `import '@stackunseen/ui/chat.css';`
- Page: https://unseenui.com/components/chat/
- Inputs: server: ChatHost · or messages · tools? · status · suggestions? · draft · onDraftChange · onSend · onCancel? · onRetry? · title? · starters? · toolbar? · attachments?
- Host responsibility: Your server owns the conversation and handles send, stop and retry; the chat only keeps the unsent draft. useLocalHost gives you a stand-in server for prototypes that never calls a model.
- Keyboard: Enter sends and Shift+Enter adds a line; the transcript is a focusable log; suggestions and Retry are buttons.
- Documented states: Default, Empty, Mid conversation, Failed, AI SDK approval
```tsx
const host = useLocalHost();
return ;
```
## ClarificationRequest
A question the assistant asks before it continues.
- Group: Forms & generated UI
- Import: `import { ClarificationRequest } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/clarification-request/
- Inputs: question · value · onValueChange · onSubmit · choices? · state?
- Host responsibility: Check the answer on your server and confirm you got it.
- Documented states: Default, Text, Pending, Error, Resolved, Cancelled
```tsx
```
## AgentCard
The identity, capabilities and current activity of one agent.
- Group: Agents & governance
- Import: `import { AgentCard } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/agent-card/
- Inputs: name · description · state · activity? · selected? · onSelect?
- Host responsibility: Who the agent is stays separate from how any one run is going.
- Documented states: Default, Idle, Failed, Long labels, Read-only
```tsx
```
## SourceCard
A source behind an answer, with its access state and excerpt.
- Group: Sources & evidence
- Import: `import { SourceCard } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/source-card/
- Inputs: source: Source · onOpen?
- Host responsibility: Check who may see each source, and give each one a stable link to the right version.
- Documented states: Default, Revoked, Missing, Host open, Long labels
```tsx
```
## Citation
An inline reference that links a passage to its source.
- Group: Sources & evidence
- Import: `import { Citation } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/citation/
- Inputs: source: Source · number
- Host responsibility: The number shown is just a label, not the source’s ID.
- Documented states: Default, Revoked
```tsx
```
## EvidenceGroup
A claim with the sources that support it.
- Group: Sources & evidence
- Import: `import { EvidenceGroup } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/evidence-group/
- Inputs: sources · claim · relationships?
- Host responsibility: Say honestly whether each source supports the claim, contradicts it or is only related.
- Documented states: Default, Empty
```tsx
```
## GroundingStatus
How well an answer is backed by sources, with what that measure means and its limits.
- Group: Sources & evidence
- Import: `import { GroundingStatus } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/grounding-status/
- Inputs: value: Grounding
- Host responsibility: Being covered by sources isn’t the same as being confident the answer is right.
- Documented states: Default, Unknown, Long labels
```tsx
```
## MCPServerCard
Whether an MCP server is connected, as your app reports it.
- Group: MCP connections & tools
- Import: `import { MCPServerCard } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/mcp-server-card/
- Inputs: name · status · toolCount? · onConnect? · onDisconnect?
- Host responsibility: Your app owns the connection, the credentials and the permissions.
- Documented states: Default, Disconnected, Unknown, Long labels, Pending, Authorization
- Good to know: `auth-required` reads "Sign-in required"; other states show as words.
```tsx
```
## MCPToolList
The tools an MCP server offers and the permissions they need.
- Group: MCP connections & tools
- Import: `import { MCPToolList } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/mcp-tool-list/
- Inputs: tools · query · onQueryChange
- Host responsibility: Your app says which tools are available; anything unknown is shown as unknown.
- Documented states: Default
```tsx
```
## MCPAppFrame
A sandboxed frame for an MCP App view, talking to your app only through a bridge you control.
- Group: MCP connections & tools
- Import: `import { MCPAppFrame } from '@stackunseen/ui/mcp-apps';` and `import '@stackunseen/ui/mcp-apps.css';`
- Page: https://unseenui.com/components/mcp-app-frame/
- Inputs: server · resource · state · reason? · toolInput? · toolResult? · hostCapabilities? · hostContext? · grantedPermissions? · allowForms? · maxHeight? · onRequest? · onNotification? · onClose? · fallback?
- Host responsibility: Your app fetches the view, decides whether the server may show it, declares what it supports and answers every request. The frame grants no permissions and runs nothing outside its sandbox.
- Keyboard: Tab moves into the view and back out; the Close button is a normal button.
- Documented states: Default, Nothing granted, Fetching, Blocked, Failed, Not an app
```tsx
```
## ContextBar
What the current request includes, with removable items.
- Group: Context & memory
- Import: `import { ContextBar } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/context-bar/
- Inputs: items · usage? · onRemove?
- Host responsibility: Connected, selected and actually included are shown as different things.
- Documented states: Default, Unknown, Long labels, Read-only
```tsx
```
## MemoryPanel
What the assistant remembers, with where each memory came from, how far it reaches and whether it was used just now.
- Group: Context & memory
- Import: `import { MemoryPanel } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/memory-panel/
- Inputs: entries: MemoryEntry[] · query · onQueryChange · onRequest({ entryId, action }) · receipts? · locale?
- Host responsibility: Pin, unpin and forget ask your server; a row shows the pending receipt and changes only when the server’s entries change. Provenance is shown, never inferred.
- Documented states: Default, Pending request, Rejected request, Filtered, Empty
```tsx
```
## ArtifactPanel
A panel for generated documents and other artifacts.
- Group: Coding & artifacts
- Import: `import { ArtifactPanel } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/artifact-panel/
- Inputs: artifact · open · onOpenChange · loading? · error?
- Host responsibility: Your app picks the version to show and checks who may see it.
- Documented states: Default, Loading, Empty, Failed
```tsx
```
## ArtifactPreview
Read-only previews of documents and bounded tables.
- Group: Coding & artifacts
- Import: `import { ArtifactPreview } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/artifact-preview/
- Inputs: artifact: Artifact · tableLabel?
- Host responsibility: In this alpha, only text and small JSON tables are shown.
- Documented states: Default, Table, Unsupported
```tsx
```
## StatusBadge
A status label with a matching icon and color.
- Group: Feedback
- Import: `import { StatusBadge } from '@stackunseen/ui';`
- Page: https://unseenui.com/components/status-badge/
- Inputs: state · label? · native span props
- Host responsibility: A status it doesn’t recognize is never shown as success.
- Documented states: Default, Unknown
```tsx
```