# helixui components — AI-ready reference

Every component in `@helixui/core` is documented here in a single page, optimized for prompt injection. Each entry shows the import line, props, layout, anatomy, visual description, composition graph, and prompt → JSX examples.

For the full long-form docs see `/llms-full.txt`. For the design tokens see `/tokens-manifest.json`.

---

## Index

### shell
- [AppShell](#app-shell) — A responsive application layout — sticky header, persistent sidebar on desktop, sidebar hidden on mobile (caller composes a Sheet drawer).
- [CollapsingHeader](#collapsing-header) — An iOS-style header that fades from a large hero title at the top to a compact title with actions when the page is scrolled.
- [HelixUIDNAProvider](#dna-provider) — Applies a `DNA` (helixui theme genome) to a wrapping div. Every component inside re-renders under the genome's accent / chroma / radius / density / typography / surface / motion / lightness genes via cascading CSS variables — no JS rerender beyond a style mutation.
- [PageHeader](#page-header) — The top of a page — title, description, breadcrumb, and a right-aligned actions slot.
- [PullToRefresh](#pull-to-refresh) — A scroll container that detects a downward pull at the top of its content and runs an async refresh callback when released past a threshold.
- [SafeArea](#safe-area) — A wrapper that reserves space for the device's safe-area insets — notch, status bar, home indicator. Reads `env(safe-area-inset-*)` and applies the value as padding (default) or margin to the chosen edges.
- [ThemeProvider](#theme-provider) — Sets the current theme. HelixUI tokens are scoped to `[data-theme=\"light\"|\"dark\"]`; ThemeProvider applies that attribute and exposes a `useTheme` hook.

### navigation
- [BottomNav](#bottom-nav) — A fixed bottom tab bar — primary navigation pattern on mobile. Items can be links or buttons; supports an active state, optional icon, and a number/dot badge.
- [Breadcrumb](#breadcrumb) — A trail of pages above the current page. The last item is treated as the current page.
- [NavigationMenu](#navigation-menu) — A vertical navigation list with collapsible sections. Use for app sidebars and side navs.
- [Pagination](#pagination) — Page-by-page navigation with previous/next buttons, page numbers, and ellipses.
- [Sidebar](#sidebar) — A vertical navigation rail with grouped items. Designed for AppShell's sidebar slot, also usable inside a Sheet on mobile.
- [Stepper](#stepper) — A horizontal or vertical sequence of steps with done / current / pending / failed status. Use for onboarding flows, multi-step forms, or check-out funnels.
- [Tabs](#tabs) — Switch between related views without navigating away.

### layout
- [Box](#box) — A neutral container with padding and margin shorthands wired to space tokens.
- [Flex](#flex) — A flexbox container with direction, alignment, and gap as first-class props.
- [Grid](#grid) — A CSS grid container. Pass a number for equal columns, or any raw track string.
- [Stack](#stack) — Arrange children in a column (default) or row, with token-aware gap.

### primitive
- [Text](#text) — Typography primitive — render any element with token-driven size, weight, tone, alignment.

### surface
- [Card](#card) — A surface container with three elevation styles.
- [Collapsible](#collapsible) — A toggleable disclosure panel — show or hide a chunk of content behind a header.

### overlay
- [ActionSheet](#action-sheet) — An iOS-style modal sheet that slides up from the bottom edge with a list of actions. Different from Sheet — Sheet is a side drawer, ActionSheet is a vertical action menu.
- [CommandPalette](#command-palette) — A Cmd+K command palette — searchable list of actions in a modal, with keyboard navigation and grouping.
- [Dialog](#dialog) — A modal that traps focus and dims the page behind it. Use for tasks that require completion before continuing.
- [FAB](#fab) — Floating action button — circular by default, or pill (`extended`) with an icon + label. Fixed-positioned at the bottom-right by default; place yourself with `positioned={false}`.
- [FloatingBar](#floating-bar) — A pinned action bar that floats over content — typically used for bulk actions on selected items.
- [Menu](#menu) — A floating list of commands attached to a trigger.
- [Popover](#popover) — A floating panel anchored to a trigger. Use for ephemeral content that doesn't justify a Dialog.
- [Sheet](#sheet) — A modal panel that slides in from a screen edge. Use for navigation, filters, or longer task flows on mobile.
- [Tooltip](#tooltip) — A short, on-hover/on-focus label for a control. Use for icon-only buttons or to expand abbreviations.

### form
- [Button](#button) — Triggers an action when clicked.
- [Calendar](#calendar) — A month-view date picker. Internationalized via @internationalized/date — supports any calendar system, not just Gregorian.
- [Checkbox](#checkbox) — A binary checkbox with indeterminate state.
- [CodeEditor](#code-editor) — An editable code surface backed by either CodeMirror 6 or Monaco. Pick the engine via a single prop. Both engines lazy-load and are declared as optional peer dependencies — install only what you use.
- [ColorPicker](#color-picker) — An HSB color picker — saturation/brightness area, hue slider, and hex input. Available inline or in a popover.
- [CurrencyInput](#currency-input) — Locale-aware currency input. Formats on blur, parses on the fly. Uses Intl.NumberFormat for symbols, separators, and precision.
- [DateField](#date-field) — Segmented date input — month / day / year (or whatever the user's locale prefers). Built on react-aria-components.
- [DatePicker](#date-picker) — Segmented date input plus a popover calendar. Pick a date by typing, arrow keys, or clicking the grid.
- [DateRangePicker](#date-range-picker) — Two segmented date inputs (start + end) plus a popover range calendar.
- [DateTimePicker](#date-time-picker) — Date + time picker — segmented date input, time field, and a popover calendar. For meeting times, appointment slots, scheduled posts.
- [Field](#field) — A vertical layout for label + control + description + error message. Use with non-RAC controls; RAC inputs (TextInput, Checkbox, etc.) already accept `label`/`description`/`errorMessage` props.
- [FileUpload](#file-upload) — Drag-and-drop file upload with progress, errors, and accept/size filtering. Pair with your own upload pipeline.
- [Form](#form) — A `<form>` wrapper from react-aria-components that surfaces validation errors per-field via the `validationErrors` prop.
- [IconButton](#icon-button) — A square button containing only an icon. Requires an accessible label.
- [InputGroup](#input-group) — A horizontal layout for multiple controls. With `attached`, children share a single rounded border.
- [MultiSelect](#multi-select) — A combobox that accepts multiple values, displayed as removable tags inline.
- [NumberField](#number-field) — A numeric input with locale-aware parsing, optional +/- steppers, min/max/step, and validation.
- [NumericKeypad](#numeric-keypad) — An iOS/Android-style 3×4 numeric keypad with optional letter sub-labels (ABC, DEF, …). Use for PIN entry, banking apps, or custom input flows where the system keyboard is unwanted.
- [PinInput](#pin-input) — A row of single-character cells for PIN / OTP entry. Auto-advances on type, supports paste-to-fill, backspace-to-previous, arrow navigation, and SMS one-time-code autofill.
- [RadioCard](#radio-card) — A radio option styled as a card. Use inside a RadioGroup when each option needs more space (icon, title, description).
- [RadioGroup](#radio-group) — A list of mutually exclusive options. Use Radio components as children.
- [Rating](#rating) — A star rating control. Interactive by default — click or tap to set; supports half-star precision and a read-only display mode.
- [RichTextEditor](#rich-text-editor) — WYSIWYG editor backed by TipTap (built on ProseMirror). Lazy-loads the engine and every extension; declared as optional peer dependencies. Ships a default toolbar but exposes an imperative handle for fully custom UI.
- [SegmentedControl](#segmented-control) — A grouped row of toggle buttons for picking between a small number of mutually exclusive views.
- [Select](#select) — A single-value picker rendered as a popover listbox.
- [Slider](#slider) — A horizontal slider for a single value or a range. Pass an array `value`/`defaultValue` to get a range slider with two thumbs.
- [Switch](#switch) — A two-state toggle. Use when a setting takes effect immediately; use Checkbox in forms.
- [TextInput](#text-input) — A single-line text input with built-in label, description, error, and prefix/suffix slots.
- [Textarea](#textarea) — A multi-line text input with optional label, description, and error.

### data
- [Chart](#chart) — Unified chart surface backed by either Chart.js or Recharts. Both engines accept the same `<ChartData>` shape (labels + datasets); the adapter translates to engine-native formats internally. Both engines lazy-load and are declared as optional peer dependencies — install only what you use.
- [CodeBlock](#code-block) — A fenced code display with language label and copy button. Built-in tokenizer for ts / js / py / json / bash; bring your own highlighter for others.
- [DataTable](#data-table) — A full-featured table primitive — sortable, filterable, selectable, paginated. Works for read-only display and for selection-driven workflows. Zero external dependencies.
- [List](#list) — A denser data list — feed, inbox, settings rows. Each item has media / primary / secondary / trailing slots.
- [Sparkline](#sparkline) — Tiny inline trend visualization rendered as pure SVG. No peer dependencies. Pairs with `<StatCard>` for KPI tiles, with `<List>` cells for per-row trends, or with `<Chart>` for full-size views.
- [StatCard](#stat-card) — A KPI display — label, big value, a delta vs previous period, and an optional description line.
- [SwipeableListItem](#swipeable-list-item) — A list row that reveals leading or trailing actions when the user swipes left or right. Pass the row content as `children`; pass actions for either edge.
- [Table](#table) — An interactive data table with selection, sorting, keyboard navigation, and a screen-reader-friendly grid.

### feedback
- [Badge](#badge) — A small inline label for status, counts, or categories.
- [Banner](#banner) — A persistent page-level alert. Stronger than Callout, less interruptive than Toast or Dialog.
- [Callout](#callout) — An inline message banner — info, success, warning, danger, or neutral.
- [EmptyState](#empty-state) — A centered placeholder for "no data yet" — icon, title, description, and an action.
- [PresenceDot](#presence-dot) — A small status dot — online / away / busy / offline. Use standalone or attached to an Avatar.
- [ProgressBar](#progress-bar) — Linear progress indicator. Determinate when given a `value`; indeterminate (looping shimmer) when `value` is omitted.
- [Skeleton](#skeleton) — A shimmering placeholder for content that's still loading.
- [Spinner](#spinner) — An indeterminate loading indicator.
- [Toast](#toast) — Transient messages that announce a background result. Mount `<ToastProvider />` once; call `toast.success(...)` from anywhere.

### media
- [AttachmentTile](#attachment-tile) — A compact tile for a file attachment — thumbnail or icon + name + size + optional remove or upload progress.
- [Avatar](#avatar) — A user or entity image with text fallback when the image is missing or fails to load.
- [AvatarGroup](#avatar-group) — A row of overlapping avatars with an optional overflow chip — `+N` for hidden members.
- [Carousel](#carousel) — A horizontal scroll-snap row of items. Native scroll on mobile (swipe); hidden arrows on hover for desktop; optional dots showing pagination.

### chat
- [ChatComposer](#chat-composer) — A multi-line message composer with auto-resize, Enter-to-send (Shift+Enter for newline), and slots for attachments and toolbar buttons.
- [ChatHeader](#chat-header) — The top bar of a single conversation — avatar, title, subtitle, right-aligned actions.
- [ChatList](#chat-list) — A scrolling container for ChatMessages with sticky-to-bottom auto-scroll. When the user has scrolled up to read history, new messages do NOT yank them back.
- [ChatMessage](#chat-message) — A single message in a chat — user / assistant / system role, bubble or inline (Slack-style) variant, optional avatar / name / time / footer.
- [PromptSuggestions](#prompt-suggestions) — A row (chips) or grid (cards) of suggested prompts. Used at the start of an empty AI conversation or as follow-up suggestions after a response.
- [StreamingIndicator](#streaming-indicator) — An inline marker placed at the end of streaming LLM text — blinking caret, pulsing block, or three dots.
- [ThinkingBlock](#thinking-block) — A collapsed reasoning / chain-of-thought block. Use to present an LLM's intermediate thought process in a non-distracting way.
- [ToolCall](#tool-call) — A collapsible card representing a single tool / function call from an LLM — name, status, optional summary line, and expandable input / output sections.
- [TypingIndicator](#typing-indicator) — Three bouncing dots inside a pill — shown while a participant is composing a message.

### other
- [PriceTag](#price-tag) — A formatted currency price label with optional strike-through original price and sale-percentage chip.

---

# shell

<a id="app-shell"></a>

# AppShell

A responsive application layout — sticky header, persistent sidebar on desktop, sidebar hidden on mobile (caller composes a Sheet drawer).

> category: shell · status: stable · since: 0.2.0

```ts
import { AppShell } from '@helixui/core'
```

### Tags

`layout`, `shell`, `header`, `sidebar`, `responsive`, `top-level`

### Anatomy

```
┌─ header (sticky top) ────────────────────────────────┐
│ logo  …  search  …  avatar                           │
├──────────┬───────────────────────────────────────────┤
│ sidebar  │ <main>                                    │
│ (≥768px) │   PageHeader                              │
│          │   <page content>                          │
│          │                                           │
│          │                                           │
└──────────┴───────────────────────────────────────────┘
 ↑ sidebar collapses below collapseBreakpoint;
 ↑ caller must render hamburger + Sheet for mobile.
```

### Layout

- display: `grid`
- width: `fill`
- height: `fill`
- intrinsicSize: `fills viewport, sidebar 240px (configurable), header sticky top`
- stackable: `false`
- fullBleed: `true`

### Visual

A desktop-first chrome: a sticky top header (border-bottom by border.default), a fixed-width sidebar on the
left, and a scrolling main column. Below `collapseBreakpoint` the sidebar disappears and main becomes
full-bleed; the caller is responsible for wiring a hamburger + Sheet drawer to expose it again.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `sidebar` | `ReactNode` | — | Left rail content. Shown on desktop, hidden below the breakpoint. |
| `header` | `ReactNode` | — | Sticky top bar. |
| `sidebarWidth` | `number \| string` | `240` | Sidebar width. Number → px. |
| `collapseBreakpoint` | `number` | `768` | Min viewport (px) for sidebar to be visible. |

### Slots

- children — main content area

### Tokens

`color.bg.surface.default`, `color.text.primary`, `color.border.default`

### Accessibility

Notes:
- Sidebar uses `<aside>`; main uses `<main>`. Wrap nav inside the sidebar in `<nav aria-label>` (helixui Sidebar component does this).
- On mobile the sidebar is `display:none`. To expose it, render a hamburger in `header` that opens a `Sheet side="start"` with the same sidebar content.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Sidebar` | `slot` | Fills the `sidebar` prop. |
| `PageHeader` | `child` | Common first child of `children` to title each route. |
| `Sheet` | `sibling` | Pair with Sheet (side='start') for the mobile sidebar drawer. |
| `SafeArea` | `parent` | Wrap AppShell in SafeArea on mobile builds. |

### Prompt examples

**scaffold a logged-in app layout** — _"give me an app layout with a top bar and side nav"_

```tsx
<AppShell
  header={<TopBar />}
  sidebar={<Sidebar><Sidebar.Group><Sidebar.Item href="/" active>Home</Sidebar.Item></Sidebar.Group></Sidebar>}
>
  <PageHeader title="Home" />
  {/* page */}
</AppShell>
```

**responsive — show the sidebar in a drawer on mobile** — _"make the sidebar slide in on mobile"_

```tsx
const [open, setOpen] = useState(false);
<>
  <AppShell
    header={<TopBar onMenu={() => setOpen(true)} />}
    sidebar={<Sidebar>…</Sidebar>}
  >
    {content}
  </AppShell>
  <Sheet side="start" isOpen={open} onOpenChange={setOpen}>
    <Sidebar>…</Sidebar>
  </Sheet>
</>
```

**narrow icon-only sidebar** — _"use a 64px icon-only sidebar"_

```tsx
<AppShell sidebarWidth={64} sidebar={<IconRail />}>
  ...
</AppShell>
```

### Related

- Sidebar
- PageHeader

---

<a id="collapsing-header"></a>

# CollapsingHeader

An iOS-style header that fades from a large hero title at the top to a compact title with actions when the page is scrolled.

> category: shell · status: beta · since: 0.5.0

```ts
import { CollapsingHeader } from '@helixui/core'
```

### Tags

`mobile`, `ios`, `scroll`, `header`, `large-title`

### Anatomy

```
(collapsed top)  Title                    [actions]
(expanded top)
  Hero Title
  ─────────────────────────
  page content scrolls under it
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `expanded ~120px, collapses to ~52px on scroll`
- stackable: `false`
- fullBleed: `true`

### Visual

An iOS-style header that starts as a large hero title at rest and fades into a compact sticky title with right-aligned actions as the page scrolls down.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `ReactNode` | — | Headline shown when the header is at full height. |
| `collapsedTitle` | `ReactNode` | — | Compact title shown when collapsed. Defaults to `title`. |
| `description` | `ReactNode` | — | Lead paragraph below the title. |
| `actions` | `ReactNode` | — | Right-aligned actions (visible in both states). |
| `minHeight` | `number` | `56` | Collapsed height (px). |
| `maxHeight` | `number` | `140` | Expanded height (px). |
| `scrollContainer` | `HTMLElement \| null` | — | Element whose scroll drives the collapse. Defaults to `window`. |

### Tokens

`color.bg.surface.default`, `color.text.primary`, `color.text.secondary`, `color.border.default`, `space.1`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.size.3xl`, `font.weight.semibold`, `font.weight.bold`, `shadow.sm`

### Accessibility

Notes:
- The header includes `padding-top: env(safe-area-inset-top)` so it clears the iOS notch.
- The compact title cross-fades; both are rendered for screen readers.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `PageHeader` | `alternative` | PageHeader is static; CollapsingHeader animates with scroll. |

### Prompt examples

**mobile profile page** — _"large title that shrinks on scroll"_

```tsx
<CollapsingHeader title="Profile" actions={<IconButton aria-label="Edit"><EditIcon /></IconButton>} />
```

### Related

- PageHeader

---

<a id="dna-provider"></a>

# HelixUIDNAProvider

Applies a `DNA` (helixui theme genome) to a wrapping div. Every component inside re-renders under the genome's accent / chroma / radius / density / typography / surface / motion / lightness genes via cascading CSS variables — no JS rerender beyond a style mutation.

> category: shell · status: stable · since: 0.4.0

```ts
import { HelixUIDNAProvider } from '@helixui/core'
```

### Tags

`theme`, `dna`, `genome`, `provider`

### Anatomy

```
<HelixUIDNAProvider dna={...}>
  ⟨all components inside inherit the genome⟩
</HelixUIDNAProvider>
```

### Layout

- display: `block`
- width: `auto`
- height: `auto`
- intrinsicSize: `unstyled wrapper; pure CSS variable scope`
- stackable: `true`
- fullBleed: `false`

### Visual

A presentational wrapper that applies CSS variables for accent / chroma / radius / density / typography / surface / motion / lightness genes. Children re-render visually without React rerender — the gene change is just a style mutation.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `dna` | `DNA` | — | Required. A DNA value from `@helixui/dna` — `wildtype()`, a preset, a mutation, or a bred child. |
| `inline` | `boolean` | `false` | Render the wrapper as `inline-block` (for compact previews). |
| `...rest` | `HTMLAttributes<HTMLDivElement>` | — | Native div attributes. |

### Slots

- children — the subtree that should render under this DNA

### Tokens

`color.bg.surface.default`, `color.text.primary`, `font.family.sans`

### Accessibility

Notes:
- The wrapping div sets `data-theme` only when the DNA's `lightness` gene is fixed (`light` / `dark`). With `auto` the inherited theme is used.
- DNA changes animate the surface color via a CSS `transition` (220ms); respects `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ThemeProvider` | `parent` | ThemeProvider sets light/dark; DNAProvider tunes the genome on top. |

### Prompt examples

**apply a custom theme genome** — _"wrap the app in a DNA with rounder radius"_

```tsx
<HelixUIDNAProvider dna={{ radius: 'round', density: 'cozy' }}>
  <App />
</HelixUIDNAProvider>
```

### Related

- ThemeProvider

---

<a id="page-header"></a>

# PageHeader

The top of a page — title, description, breadcrumb, and a right-aligned actions slot.

> category: shell · status: stable · since: 0.2.0

```ts
import { PageHeader } from '@helixui/core'
```

### Tags

`title`, `breadcrumb`, `actions`, `page-top`

### Anatomy

```
Breadcrumb › path
Title                                    [ Action ] [ ⋮ ]
Description
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, hugs content`
- stackable: `false`
- fullBleed: `false`

### Visual

A header block at the top of a page: optional breadcrumb above, large heading + description on the left, right-aligned actions.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `breadcrumb` | `ReactNode` | — | Optional row above the title — typically `<Breadcrumbs>`. |
| `title` | `ReactNode` | — | Page heading. Rendered as `<h1>`. |
| `description` | `ReactNode` | — | Lead paragraph below the title. |
| `actions` | `ReactNode` | — | Right-aligned action group — primary buttons, IconButtons. |
| `bordered` | `boolean` | `false` | Adds a bottom border + spacing to separate from page content. |

### Tokens

`color.text.primary`, `color.text.secondary`, `color.border.default`, `font.family.sans`, `font.size.md`, `font.size.sm`, `font.size.2xl`, `font.weight.semibold`, `font.lineHeight.tight`, `space.1`, `space.2`, `space.3`, `space.4`, `space.6`

### Accessibility

Notes:
- Renders `<h1>` so there's exactly one per page. Use a different heading inside `actions` if needed.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `AppShell` | `child` | Common first child of the AppShell main area. |
| `Breadcrumb` | `slot` | Goes in the breadcrumb slot. |
| `Button` | `child` | Right-aligned actions. |

### Prompt examples

**page title with action** — _"page header for Users with a New user button"_

```tsx
<PageHeader
  title="Users"
  description="Manage who can access this workspace."
  actions={<Button>New user</Button>}
/>
```

### Related

- Breadcrumb
- AppShell

---

<a id="pull-to-refresh"></a>

# PullToRefresh

A scroll container that detects a downward pull at the top of its content and runs an async refresh callback when released past a threshold.

> category: shell · status: beta · since: 0.5.0

```ts
import { PullToRefresh } from '@helixui/core'
```

### Tags

`mobile`, `gesture`, `refresh`, `scroll`

### Anatomy

```
↓ Pull down to refresh ↓
────────────────────────
[ scrollable content ]
```

### Layout

- display: `block`
- width: `fill`
- height: `fill`
- intrinsicSize: `fills available; intercepts top-edge pull`
- stackable: `false`
- fullBleed: `false`

### Visual

A scroll container that exposes a small spinner when the user drags down past the top. Past a threshold, releasing fires the async refresh and the spinner spins until the promise resolves.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `onRefresh` | `() => void \| Promise<void>` | — | Required. Called when the user releases past `threshold`. While the returned promise is pending, the spinner stays visible and disabled. |
| `threshold` | `number` | `64` | Pixel distance past which release triggers refresh. |
| `maxPull` | `number` | `120` | Soft cap on pull distance (rubber-band beyond this). |

### Slots

- children — the scrollable content

### Tokens

`color.bg.surface.default`, `color.text.action.brand`, `radius.full`, `font.family.sans`, `shadow.md`

### Accessibility

Notes:
- Pull-to-refresh is a touch gesture; it should never be the only way to refresh. Pair with a visible Refresh button or a CommandPalette entry.
- The component listens to pointer events so it works with mouse drag for desktop testing, but the gesture is mobile-first.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `List` | `child` | Common: PullToRefresh wraps a List. |
| `ChatList` | `alternative` | ChatList has its own scroll behavior. |
| `SwipeableListItem` | `sibling` |  |

### Prompt examples

**mobile feed pull-to-refresh** — _"pull to refresh wrapping a feed list"_

```tsx
<PullToRefresh onRefresh={loadFeed}>
  <List>{rows}</List>
</PullToRefresh>
```

### Related

- List
- SwipeableListItem

---

<a id="safe-area"></a>

# SafeArea

A wrapper that reserves space for the device's safe-area insets — notch, status bar, home indicator. Reads `env(safe-area-inset-*)` and applies the value as padding (default) or margin to the chosen edges.

> category: shell · status: stable · since: 0.5.0

```ts
import { SafeArea } from '@helixui/core'
```

### Tags

`mobile`, `inset`, `notch`, `home-indicator`

### Anatomy

```
╔═════════════════════════════╗  ← top inset (notch / status bar)
║  <children>                ║
║                            ║
╚═════════════════════════════╝  ← bottom inset (home indicator)
```

### Layout

- display: `block`
- width: `fill`
- height: `fill`
- intrinsicSize: `fills viewport; pads chosen edges by env(safe-area-inset-*)`
- stackable: `false`
- fullBleed: `true`

### Visual

A presentational wrapper that reads `env(safe-area-inset-top|right|bottom|left)` and applies them as padding (default) or margin to the chosen edges.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `edges` | `SafeAreaEdge[] \| 'all'` | `all` | Which edges to reserve. `'top' | 'right' | 'bottom' | 'left'` or `'all'`. |
| `apply` | `'padding' \| 'margin'` | `padding` | How to apply the inset. |

### Accessibility

Notes:
- SafeArea is presentational. It does not change focus order or alter content semantics.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `AppShell` | `parent` | Wrap AppShell on mobile builds. |
| `BottomNav` | `parent` | Often wraps the BottomNav region. |
| `FAB` | `sibling` |  |

### Prompt examples

**pad below the notch** — _"safe area top + bottom"_

```tsx
<SafeArea edges={['top','bottom']}>
  <App />
</SafeArea>
```

### Related

- BottomNav
- FAB

---

<a id="theme-provider"></a>

# ThemeProvider

Sets the current theme. HelixUI tokens are scoped to `[data-theme=\"light\"|\"dark\"]`; ThemeProvider applies that attribute and exposes a `useTheme` hook.

> category: shell · status: stable · since: 0.1.0

```ts
import { ThemeProvider, useTheme } from '@helixui/core'
```

### Tags

`theme`, `light`, `dark`, `provider`

### Anatomy

```
<ThemeProvider theme="dark">
  ⟨all components inherit data-theme=dark⟩
</ThemeProvider>
```

### Layout

- display: `block`
- width: `auto`
- height: `auto`
- intrinsicSize: `unstyled wrapper; sets data-theme on root`
- stackable: `true`
- fullBleed: `false`

### Visual

A presentational wrapper that toggles `data-theme="light"` or `data-theme="dark"` on a wrapping element. All helixui tokens are scoped to that attribute.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `theme` | `'light' \| 'dark'` | — | Controlled theme. |
| `defaultTheme` | `'light' \| 'dark'` | `light` | Initial theme when uncontrolled. |
| `rootElement` | `'document' \| 'wrapper'` | `document` | Where to apply `data-theme`. `document` writes to `<html>`. `wrapper` renders a div. |
| `onChange` | `(theme: Theme) => void` | — | Theme change handler. |

### Slots

- children — your app

### Tokens

`color.text.primary`, `color.bg.surface.default`

### Accessibility

Notes:
- Theme switch should respect `prefers-color-scheme` on first load — wire that into your `defaultTheme`.
- Avoid mounting two ThemeProviders with different themes; tokens cascade by attribute.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `HelixUIDNAProvider` | `child` | DNA tunes the genome inside a chosen theme. |

### Prompt examples

**toggle dark mode** — _"wrap the app for theme switching"_

```tsx
<ThemeProvider theme={theme}>
  <App />
</ThemeProvider>
```

---

# navigation

<a id="bottom-nav"></a>

# BottomNav

A fixed bottom tab bar — primary navigation pattern on mobile. Items can be links or buttons; supports an active state, optional icon, and a number/dot badge.

> category: navigation · status: stable · since: 0.5.0

```ts
import { BottomNav } from '@helixui/core'
```

### Tags

`mobile`, `tabs`, `fixed-bottom`, `tab-bar`, `primary-nav`

### Anatomy

```
┌────────────────────────────────────────────────┐  ← page content scrolls
│                                                │
├────────────────────────────────────────────────┤
│   ⌂ Home    ⊙ Search    ◎ Profile              │  ← BottomNav (fixed)
└────────────────────────────────────────────────┘
```

### Layout

- display: `fixed`
- width: `fill`
- height: `content`
- intrinsicSize: `pinned to bottom edge, ~56-64px tall`
- stackable: `false`
- fullBleed: `true`

### Visual

A fixed bottom bar with 3–5 evenly spaced items, each an icon over a tiny label. Active item uses brand foreground; inactive use muted text. Optional Badge/dot floats at top-right of the icon. On notch devices, padding reads `env(safe-area-inset-bottom)`.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `Primary` | `aria-label` on the wrapping `<nav>`. |

### Slots

- BottomNav.Item — anchor (when `href`) or button. Props: `icon`, `active` (sets `aria-current="page"`), `badge` (number → count, true → dot).

### Tokens

`color.bg.surface.default`, `color.bg.action.danger.default`, `color.text.secondary`, `color.text.action.brand`, `color.text.on.danger`, `color.border.default`, `color.border.focus`, `radius.full`, `font.family.sans`, `font.size.xs`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Notes:
- Wrapped in `<nav aria-label>`. Active item is rendered with `aria-current="page"`.
- Includes `padding-bottom: env(safe-area-inset-bottom)` so it sits above the iOS home indicator when used as a fixed bar.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `SafeArea` | `parent` | Wrap in SafeArea on mobile builds for inset. |
| `Sidebar` | `alternative` | Sidebar is desktop primary nav; BottomNav is mobile. |
| `Tabs` | `alternative` | Tabs for in-page section switching; BottomNav for app-level nav. |
| `FAB` | `sibling` |  |
| `AppShell` | `sibling` |  |

### Prompt examples

**mobile primary nav** — _"three-tab bottom bar Home, Search, Profile"_

```tsx
<BottomNav>
  <BottomNav.Item href="/" icon={<HomeIcon />} active>Home</BottomNav.Item>
  <BottomNav.Item href="/search" icon={<SearchIcon />}>Search</BottomNav.Item>
  <BottomNav.Item href="/me" icon={<UserIcon />}>Profile</BottomNav.Item>
</BottomNav>
```

**tab with unread dot** — _"show a dot badge on Inbox"_

```tsx
<BottomNav.Item href="/inbox" icon={<InboxIcon />} badge="dot">Inbox</BottomNav.Item>
```

### Related

- SafeArea
- FAB
- AppShell

---

<a id="breadcrumb"></a>

# Breadcrumb

A trail of pages above the current page. The last item is treated as the current page.

> category: navigation · status: stable · since: 0.1.0

```ts
import { Breadcrumbs, Breadcrumb } from '@helixui/core'
```

### Tags

`trail`, `hierarchy`, `path`

### Anatomy

```
Home › Workspace › Projects › Current page
```

### Layout

- display: `inline-flex`
- width: `fill`
- height: `content`
- intrinsicSize: `one line, wraps on overflow`
- stackable: `false`
- fullBleed: `false`

### Visual

A horizontal row of small links separated by a chevron-like glyph. The last item is rendered as plain text (current page) and gets `aria-current=page`. Truncates with ellipsis when constrained.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `href` | `string` | — | Link target. The last Breadcrumb in the list should omit `href` and renders as `aria-current="page"`. |

### Slots

- Breadcrumbs children — Breadcrumb items
- Breadcrumb children — page label

### Tokens

`color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.border.focus`, `radius.sm`, `space.1`, `space.2`, `font.family.sans`, `font.size.sm`, `font.weight.medium`

### Accessibility

Notes:
- Built on `react-aria-components` Breadcrumbs — emits a `<nav aria-label="Breadcrumbs">` wrapper automatically.
- The last item should omit `href`; helixui renders it as the current page with `aria-current="page"`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `PageHeader` | `slot` | Common in PageHeader.breadcrumb slot. |

### Prompt examples

**show parent path on a settings page** — _"breadcrumb Home / Settings / Billing"_

```tsx
<Breadcrumbs>
  <Breadcrumb href="/">Home</Breadcrumb>
  <Breadcrumb href="/settings">Settings</Breadcrumb>
  <Breadcrumb>Billing</Breadcrumb>
</Breadcrumbs>
```

---

<a id="navigation-menu"></a>

# NavigationMenu

A vertical navigation list with collapsible sections. Use for app sidebars and side navs.

> category: navigation · status: stable · since: 0.1.0

```ts
import { NavigationMenu } from '@helixui/core'
```

### Tags

`nav`, `collapsible`, `side`, `sections`

### Anatomy

```
▾ Section
   • Item
   • Item
▸ Section (collapsed)
▾ Section
   • Item
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `vertical list with collapsible sections`
- stackable: `true`
- fullBleed: `false`

### Visual

A vertical list with sections that can collapse. Section headers show a chevron and bold label; items are pill-shaped with active state.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `Main` | Accessible name on the wrapping `<nav>`. |
| `...rest` | `HTMLAttributes<HTMLElement>` | — | Native nav attributes. |

### Slots

- NavigationMenu.Group — DisclosureGroup; allows multiple sections to be open at once
- NavigationMenu.Section — Disclosure; pass `title` and children
- NavigationMenu.Item — `<a>` with `active` flag → renders `aria-current="page"`

### Tokens

`color.bg.action.neutral.default`, `color.bg.action.brand.subtle`, `color.text.primary`, `color.text.secondary`, `color.text.action.brand`, `color.border.focus`, `radius.md`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`, `font.weight.medium`

### Accessibility

Notes:
- Sections use react-aria's Disclosure — keyboard, ARIA expanded/controls, focus all handled.
- Mark the active link with `active` prop; helixui sets `aria-current="page"`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Sidebar` | `alternative` | Sidebar is the structured rail with header/footer; NavigationMenu is the bare collapsible list. |
| `Breadcrumb` | `sibling` |  |
| `Tabs` | `sibling` |  |

### Prompt examples

**docs side nav** — _"collapsible side nav with two sections"_

```tsx
<NavigationMenu>
  <NavigationMenu.Section title="Getting started">
    <NavigationMenu.Item href="/install">Install</NavigationMenu.Item>
  </NavigationMenu.Section>
  <NavigationMenu.Section title="Components">
    <NavigationMenu.Item href="/components/button">Button</NavigationMenu.Item>
  </NavigationMenu.Section>
</NavigationMenu>
```

### Related

- Breadcrumb
- Tabs

---

<a id="pagination"></a>

# Pagination

Page-by-page navigation with previous/next buttons, page numbers, and ellipses.

> category: navigation · status: stable · since: 0.1.0

```ts
import { Pagination } from '@helixui/core'
```

### Tags

`pages`, `paging`, `numbers`

### Anatomy

```
[ ‹ ]  1  2  …  7  8 [9] 10 …  20  [ › ]
```

### Layout

- display: `inline-flex`
- width: `content`
- height: `content`
- intrinsicSize: `centered, hugs page count`
- stackable: `false`
- fullBleed: `false`

### Visual

A horizontal row of small page-number buttons with previous/next arrows on the ends and ellipses for elided ranges. Current page filled with brand tone.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `page` | `number` | — | Current 1-indexed page. Required. |
| `total` | `number` | — | Total number of pages. Required. |
| `onChange` | `(page: number) => void` | — | Page change handler. |
| `siblings` | `number` | `1` | Pages shown on each side of the current page. |
| `boundaries` | `number` | `1` | Pages shown at the start and end. |
| `label` | `string` | `Pagination` | Accessible label on the `<nav>`. |

### Tokens

`color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.on.brand`, `color.border.focus`, `radius.md`, `space.2`, `font.family.sans`, `font.size.sm`, `font.weight.semibold`

### Accessibility

Notes:
- Wrapped in `<nav aria-label>`, current page marked with `aria-current="page"`.
- Previous/Next buttons have explicit `aria-label`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Table` | `sibling` | Common below a Table. |
| `List` | `sibling` | Or below a List. |

### Prompt examples

**paginate a table** — _"pagination for 20 pages, current page 9"_

```tsx
<Pagination total={20} page={page} onPageChange={setPage} />
```

---

<a id="sidebar"></a>

# Sidebar

A vertical navigation rail with grouped items. Designed for AppShell's sidebar slot, also usable inside a Sheet on mobile.

> category: navigation · status: stable · since: 0.2.0

```ts
import { Sidebar } from '@helixui/core'
```

### Tags

`nav`, `vertical`, `rail`, `sections`, `grouped`, `persistent`

### Anatomy

```
┌─────────────────────────┐
│ Sidebar.Header          │   ← brand / search
├─────────────────────────┤
│ Sidebar.Group "title"   │
│   • Sidebar.Item active │   ← active uses aria-current=page
│   • Sidebar.Item        │
│   • Sidebar.Item   [3]  │   ← trailing content (badge, count)
│                         │
│ Sidebar.Group "title"   │
│   • Sidebar.Item        │
├─────────────────────────┤
│ Sidebar.Footer          │   ← pinned to bottom
└─────────────────────────┘
 ↑ wrapped in <nav aria-label>
```

### Layout

- display: `flex`
- width: `fixed:240px (default), tunable via parent`
- height: `fill`
- intrinsicSize: `full-height vertical column, footer pinned`
- stackable: `false`
- fullBleed: `false`

### Visual

A muted vertical column. Items are pill-shaped (radius.md) with subtle hover (action.neutral.default at low alpha)
and a tinted brand background (action.brand.subtle) when active. Group titles are tiny uppercase labels
(font.size.xs + font.weight.semibold) with low contrast. Icons sit at space.2 from the label. The footer is
separated by border.default and contains compact identity (Avatar + name).

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `Primary` | `aria-label` on the wrapping `<nav>`. |

### Slots

- Sidebar.Header — brand / search at the top
- Sidebar.Group — group of items with optional `title`
- Sidebar.Item — anchor (when `href`) or button. `active` adds `aria-current=page`. Optional `icon` and `trailing`.
- Sidebar.Footer — pinned bottom slot

### Tokens

`color.bg.action.neutral.default`, `color.bg.action.brand.subtle`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.border.default`, `color.border.focus`, `radius.md`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`, `font.size.xs`, `font.weight.semibold`, `font.weight.medium`

### Accessibility

Notes:
- Wraps in `<nav aria-label>`. Active item is rendered with `aria-current="page"`.
- Items can be `<a>` or `<button>` depending on whether `href` is provided.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `AppShell` | `slot` | Fills the `sidebar` slot of AppShell on desktop. |
| `Sheet` | `parent` | Render the same Sidebar inside Sheet (side='start') for the mobile drawer. |
| `NavigationMenu` | `alternative` | Use NavigationMenu for a horizontal top-bar nav. |
| `BottomNav` | `alternative` | Mobile-only horizontal nav at the bottom of the viewport. |
| `Avatar` | `child` | Common in Sidebar.Header and Sidebar.Footer. |

### Prompt examples

**basic side navigation** — _"sidebar with Dashboard, Users, Billing"_

```tsx
<Sidebar label="Workspace nav">
  <Sidebar.Group>
    <Sidebar.Item href="/" active>Dashboard</Sidebar.Item>
    <Sidebar.Item href="/users">Users</Sidebar.Item>
    <Sidebar.Item href="/billing">Billing</Sidebar.Item>
  </Sidebar.Group>
</Sidebar>
```

**grouped navigation with counts** — _"sidebar with two sections, show unread count next to Inbox"_

```tsx
<Sidebar label="Mail">
  <Sidebar.Group title="Mail">
    <Sidebar.Item href="/inbox" trailing="12" active>Inbox</Sidebar.Item>
    <Sidebar.Item href="/sent">Sent</Sidebar.Item>
  </Sidebar.Group>
  <Sidebar.Group title="Workspace">
    <Sidebar.Item href="/team">Team</Sidebar.Item>
  </Sidebar.Group>
</Sidebar>
```

**sidebar with brand + user identity** — _"side nav with logo at the top and current user at the bottom"_

```tsx
<Sidebar>
  <Sidebar.Header>
    <Avatar fallback="HX" /> <Text weight="semibold">helixui</Text>
  </Sidebar.Header>
  <Sidebar.Group>
    <Sidebar.Item href="/" active>Home</Sidebar.Item>
  </Sidebar.Group>
  <Sidebar.Footer>
    <Avatar fallback="ST" size="sm" /> <Text size="sm">Jordan Lee</Text>
  </Sidebar.Footer>
</Sidebar>
```

**mobile drawer reuse** — _"use the same sidebar inside a sheet on mobile"_

```tsx
<Sheet side="start" isOpen={open} onOpenChange={setOpen}>
  <Sidebar>...</Sidebar>
</Sheet>
```

### Related

- AppShell
- NavigationMenu
- Sheet

---

<a id="stepper"></a>

# Stepper

A horizontal or vertical sequence of steps with done / current / pending / failed status. Use for onboarding flows, multi-step forms, or check-out funnels.

> category: navigation · status: stable · since: 0.5.0

```ts
import { Stepper, type StepperStep } from '@helixui/core'
```

### Tags

`steps`, `wizard`, `progress`, `multi-step`

### Anatomy

```
(✓ done) ── (● current) ── (○ pending) ── (! failed)
```

### Layout

- display: `flex`
- width: `fill`
- height: `content`
- intrinsicSize: `horizontal or vertical, fills container`
- stackable: `false`
- fullBleed: `false`

### Visual

A row (or column) of circular step indicators connected by lines. Done shows a check on a brand fill; current is a brand ring; pending is muted; failed uses danger tone.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `steps` | `StepperStep[]` | — | Required. Each has `id`, `label`, optional `description` and explicit `status`. |
| `current` | `number` | — | Index of the current step. Auto-fills `status`: done before, current at, pending after. |
| `orientation` | `'horizontal' \| 'vertical'` | `horizontal` | Layout. |

### Tokens

`color.bg.surface.default`, `color.bg.action.brand.default`, `color.bg.action.brand.subtle`, `color.bg.action.danger.default`, `color.border.default`, `color.border.strong`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.on.brand`, `color.text.on.danger`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.xs`, `font.size.sm`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Notes:
- Renders as `<ol>`. The current step has `aria-current="step"`.
- For onboarding, pair with focus management — focus the heading of the active step on mount.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Form` | `sibling` | Often above a multi-step Form. |
| `PinInput` | `sibling` |  |
| `NumericKeypad` | `sibling` |  |

### Prompt examples

**onboarding progress** — _"3-step stepper, on step 2"_

```tsx
<Stepper current={1} steps={[
  { id: 'account', label: 'Account' },
  { id: 'profile', label: 'Profile' },
  { id: 'done', label: 'Finish' },
]} />
```

### Related

- PinInput
- NumericKeypad

---

<a id="tabs"></a>

# Tabs

Switch between related views without navigating away.

> category: navigation · status: stable · since: 0.1.0

```ts
import { Tabs, TabList, Tab, TabPanel } from '@helixui/core'
```

### Tags

`sections`, `switch`, `in-page`

### Anatomy

```
[ Tab ][ Tab ][ Tab* ]
──────────────────────
  panel content
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `tab strip + panel; panel sized by content`
- stackable: `false`
- fullBleed: `false`

### Visual

A horizontal tab strip with an underline indicator under the active tab, followed by the active panel below. Hover/focus tabs lighten with surface tint.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'underline' \| 'pill'` | `underline` | Visual style. `pill` reads as a SegmentedControl with panels. |
| `orientation` | `'horizontal' \| 'vertical'` | `horizontal` | Layout. |
| `selectedKey` | `Key` | — | Controlled selection. |
| `defaultSelectedKey` | `Key` | — | Uncontrolled initial. |
| `onSelectionChange` | `(key: Key) => void` | — | Change handler. |

### Slots

- Tabs children — TabList + TabPanels
- TabList children — Tab components
- Tab children — label
- TabPanel children — panel content; one per Tab id

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.text.primary`, `color.text.secondary`, `color.text.action.brand`, `color.border.default`, `color.border.focus`, `radius.md`, `space.1`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.weight.medium`, `shadow.sm`

### Accessibility

Role: `tablist`

Keyboard:
- `ArrowLeft` — Previous tab (horizontal).
- `ArrowRight` — Next tab (horizontal).
- `Home` — First tab.
- `End` — Last tab.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `SegmentedControl` | `alternative` | SegmentedControl for compact view-mode pickers. |
| `Tab` | `child` | Each tab. |
| `TabPanel` | `child` | Each panel. |

### Prompt examples

**in-page sections** — _"three-tab interface for Overview/Activity/Settings"_

```tsx
<Tabs>
  <TabList>
    <Tab id="o">Overview</Tab>
    <Tab id="a">Activity</Tab>
    <Tab id="s">Settings</Tab>
  </TabList>
  <TabPanel id="o">…</TabPanel>
  <TabPanel id="a">…</TabPanel>
  <TabPanel id="s">…</TabPanel>
</Tabs>
```

### Related

- SegmentedControl

---

# layout

<a id="box"></a>

# Box

A neutral container with padding and margin shorthands wired to space tokens.

> category: layout · status: stable · since: 0.1.0

```ts
import { Box } from '@helixui/core'
```

### Tags

`primitive`, `container`, `spacing`, `utility`

### Anatomy

```
[ <children> ]  ← unstyled container with padding/margin shorthands
```

### Layout

- display: `block`
- width: `auto`
- height: `auto`
- intrinsicSize: `content size; tunable padding/margin via props`
- stackable: `true`
- fullBleed: `false`

### Visual

A presentational `<div>` with token-aware padding (`p`, `px`, `py`, …) and margin shorthands. No background, border, or radius by default — strictly a layout primitive.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `p` | `number \| string` | — | Padding on all sides. Numeric input → `space.N` token; string passes through as raw CSS. |
| `px` | `number \| string` | — | Inline (left+right) padding. |
| `py` | `number \| string` | — | Block (top+bottom) padding. |
| `m` | `number \| string` | — | Margin on all sides. |
| `mx` | `number \| string` | — | Inline margin. |
| `my` | `number \| string` | — | Block margin. |
| `...rest` | `HTMLAttributes<HTMLDivElement>` | — | Native div attributes. |

### Tokens

`space.0`, `space.1`, `space.2`, `space.3`, `space.4`, `space.5`, `space.6`, `space.8`, `space.10`, `space.12`, `space.16`, `space.20`, `space.24`

### Accessibility

Notes:
- Box is presentational. Use a semantic element where possible (`<section>`, `<article>`, etc.).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Stack` | `alternative` | Use Stack when you want a flex column/row of children. |
| `Flex` | `alternative` | Use Flex for explicit flexbox layout. |
| `Grid` | `alternative` | Use Grid for 2-D layout. |

### Prompt examples

**pad a section** — _"add 24px of padding around this group"_

```tsx
<Box p={6}>{children}</Box>
```

**horizontal rule of margin** — _"add top margin"_

```tsx
<Box mt={4}>{children}</Box>
```

### Related

- Flex
- Grid
- Stack

---

<a id="flex"></a>

# Flex

A flexbox container with direction, alignment, and gap as first-class props.

> category: layout · status: stable · since: 0.1.0

```ts
import { Flex } from '@helixui/core'
```

### Tags

`primitive`, `flexbox`, `row`, `column`, `gap`

### Anatomy

```
[ child ][ child ][ child ]   ← horizontal
  child
  child
  child                          ← vertical (direction="column")
```

### Layout

- display: `flex`
- width: `auto`
- height: `auto`
- intrinsicSize: `flex container; sized by flow + children`
- stackable: `true`
- fullBleed: `false`

### Visual

A flex container with `direction`, `align`, `justify`, `gap`, and `wrap` exposed as props that map to design tokens.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `direction` | `'row' \| 'row-reverse' \| 'column' \| 'column-reverse'` | `row` | Flex direction. |
| `align` | `'start' \| 'center' \| 'end' \| 'stretch' \| 'baseline'` | `stretch` | Cross-axis alignment. |
| `justify` | `'start' \| 'center' \| 'end' \| 'between' \| 'around' \| 'evenly'` | `start` | Main-axis alignment. |
| `gap` | `number \| string` | — | Gap between children. Numeric → `space.N` token. |
| `wrap` | `boolean` | `false` | Allow wrapping. |
| `inline` | `boolean` | `false` | Use `inline-flex` instead of `flex`. |

### Tokens

`space.1`, `space.2`, `space.3`, `space.4`, `space.5`, `space.6`, `space.8`

### Accessibility

Notes:
- Flex is presentational. Use Stack for vertically/horizontally arranged content lists.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Stack` | `alternative` | Stack is opinionated for vertical/horizontal stacking. |
| `Grid` | `alternative` | Use Grid for 2-D layout. |
| `Box` | `sibling` |  |

### Prompt examples

**horizontal row of items** — _"flex row with gap"_

```tsx
<Flex direction="row" gap={3} align="center">{children}</Flex>
```

### Related

- Stack
- Grid
- Box

---

<a id="grid"></a>

# Grid

A CSS grid container. Pass a number for equal columns, or any raw track string.

> category: layout · status: stable · since: 0.1.0

```ts
import { Grid } from '@helixui/core'
```

### Tags

`primitive`, `grid`, `columns`, `rows`

### Anatomy

```
[ . ][ . ][ . ]
[ . ][ . ][ . ]   ← columns/rows tunable
```

### Layout

- display: `grid`
- width: `auto`
- height: `auto`
- intrinsicSize: `CSS grid container, tunable tracks`
- stackable: `true`
- fullBleed: `false`

### Visual

A CSS grid container. Pass a number for equal columns, or any raw `grid-template-columns` track string. Token-aware gaps.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `columns` | `number \| string` | — | Equal columns when number; raw `grid-template-columns` when string. |
| `rows` | `number \| string` | — | Same shape, applied to rows. |
| `gap` | `number \| string` | — | Cell gap. Numeric → `space.N` token. |
| `rowGap` | `number \| string` | — | Row gap override. |
| `columnGap` | `number \| string` | — | Column gap override. |
| `inline` | `boolean` | `false` | Use `inline-grid`. |

### Tokens

`space.2`, `space.4`, `space.6`

### Accessibility

Notes:
- Presentational. Use semantic elements as children.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Flex` | `alternative` | Use Flex for 1-D layout. |
| `Stack` | `alternative` | Use Stack for vertical/horizontal stacking with consistent gap. |
| `Box` | `sibling` |  |

### Prompt examples

**three-column responsive grid** — _"3 column grid with 24px gap"_

```tsx
<Grid columns={3} gap={6}>{cards}</Grid>
```

**auto-fit gallery** — _"auto-fitting tiles min 240px"_

```tsx
<Grid columns="repeat(auto-fit, minmax(240px, 1fr))" gap={6}>{items}</Grid>
```

### Related

- Flex
- Stack
- Box

---

<a id="stack"></a>

# Stack

Arrange children in a column (default) or row, with token-aware gap.

> category: layout · status: stable · since: 0.1.0

```ts
import { Stack } from '@helixui/core'
```

### Tags

`primitive`, `flex`, `gap`, `rhythm`

### Anatomy

```
child
  ↕ gap
child
  ↕ gap
child
```

### Layout

- display: `flex`
- width: `auto`
- height: `auto`
- intrinsicSize: `flex container; sized by children`
- stackable: `true`
- fullBleed: `false`

### Visual

An opinionated flex container. Default direction is column; pass `direction="row"` for horizontal. Token-aware `gap` controls spacing between children.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `direction` | `'row' \| 'column'` | `column` | Stack direction. Replaces vapor-ui's HStack/VStack. |
| `align` | `'start' \| 'center' \| 'end' \| 'stretch' \| 'baseline'` | `stretch` | Cross-axis alignment. |
| `justify` | `'start' \| 'center' \| 'end' \| 'between' \| 'around' \| 'evenly'` | `start` | Main-axis alignment. |
| `gap` | `number \| string` | `4` | Gap between children. Numeric → `space.N` token. |
| `wrap` | `boolean` | `false` | Allow wrapping. |

### Tokens

`space.1`, `space.2`, `space.3`, `space.4`, `space.5`, `space.6`

### Accessibility

Notes:
- Presentational. Use a semantic element via children.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Flex` | `alternative` | Flex when you need explicit align/justify control. |
| `Grid` | `alternative` | Grid for 2-D layout. |
| `Box` | `sibling` |  |

### Prompt examples

**vertical layout** — _"vertical stack with 16px gap"_

```tsx
<Stack gap={4}>{children}</Stack>
```

**right-aligned button row** — _"horizontal stack with right alignment"_

```tsx
<Stack direction="row" justify="end" gap={2}>{buttons}</Stack>
```

### Related

- Flex
- Grid
- Box

---

# primitive

<a id="text"></a>

# Text

Typography primitive — render any element with token-driven size, weight, tone, alignment.

> category: primitive · status: stable · since: 0.1.0

```ts
import { Text } from '@helixui/core'
```

### Tags

`typography`, `text`, `inline`

### Anatomy

```
Inline or block text with token sizes/weights/tones
```

### Layout

- display: `inline`
- width: `auto`
- height: `auto`
- intrinsicSize: `as configured by element`
- stackable: `true`
- fullBleed: `false`

### Visual

Renders as any element (default `<span>`). Props expose font.size, font.weight, color tone, alignment.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `as` | `ElementType` | `span` | Element to render. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| '2xl' \| '3xl' \| '4xl'` | `md` | Maps to `font.size.*` tokens. |
| `weight` | `'regular' \| 'medium' \| 'semibold' \| 'bold'` | — | Maps to `font.weight.*` tokens. |
| `tone` | `'primary' \| 'secondary' \| 'muted' \| 'inverse' \| 'brand' \| 'danger' \| 'success' \| 'warning'` | `primary` | Color tone. |
| `align` | `'start' \| 'center' \| 'end'` | — | Text alignment. |
| `truncate` | `boolean` | `false` | Single-line truncation with ellipsis. |

### Tokens

`font.size.xs`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.size.xl`, `font.size.2xl`, `font.size.3xl`, `font.size.4xl`, `font.weight.regular`, `font.weight.medium`, `font.weight.semibold`, `font.weight.bold`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.action.danger`, `color.text.action.success`, `color.text.action.warning`

### Accessibility

Notes:
- Use `as` to render the correct semantic element. `<Text as="h1" size="3xl">` for page titles.
- Do not rely on size alone for hierarchy — use the right heading element.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Stack` | `parent` | Often inside a Stack. |
| `Card` | `parent` | Body content of a Card. |

### Prompt examples

**muted helper text** — _"small muted helper line"_

```tsx
<Text size="sm" tone="muted">Helper text</Text>
```

---

# surface

<a id="card"></a>

# Card

A surface container with three elevation styles.

> category: surface · status: stable · since: 0.1.0

```ts
import { Card } from '@helixui/core'
```

### Tags

`container`, `surface`, `elevation`, `group`, `panel`

### Anatomy

```
┌──────────────────────────────────┐
│                                  │
│   <children>                     │   ← arbitrary content; helixui recommends Stack inside
│                                  │
└──────────────────────────────────┘
 ↑ surface bg + border (outlined) | shadow.md (elevated) | flat (no border, subtle bg)
 ↑ rounded by radius.lg, padded by space.5
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills available width, hugs content height, ~20px internal padding`
- stackable: `true`
- fullBleed: `false`

### Visual

A rounded rectangle with generous internal padding (space.5) and large radius (radius.lg). `outlined` shows a
1px subtle border on the default surface, `elevated` removes the border and uses a soft shadow (shadow.md),
`flat` is borderless with a slightly recessed background tint. With `interactive`, hover lifts the shadow
half a step and focus shows a 2px focus-ring border.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'flat' \| 'outlined' \| 'elevated'` | `outlined` | Visual treatment. |
| `interactive` | `boolean` | `false` | Adds hover/focus affordance — set on cards that act as links or buttons. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.subtle`, `color.border.default`, `color.border.strong`, `color.border.focus`, `radius.lg`, `space.5`, `shadow.md`

### Accessibility

Notes:
- When `interactive`, also render an interactive element (`<a>` or `<button>`) inside or on top, with appropriate role.
- The card itself is presentational — do not put `onClick` on it without a role.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Stack` | `child` | Use Stack inside Card to control vertical rhythm of contents. |
| `Heading` | `child` | Common first child as a card title. |
| `Text` | `child` | Body content of a card. |
| `Button` | `child` | Action(s) at the bottom of the card. |
| `Sheet` | `alternative` | Use Sheet for content that should overlay the page. |

### Prompt examples

**group related content into a panel** — _"wrap this in a card"_

```tsx
<Card>
  <Stack gap={3}>
    <Heading size="md">Title</Heading>
    <Text>Description goes here.</Text>
  </Stack>
</Card>
```

**make a clickable card linking elsewhere** — _"card that links to /settings"_

```tsx
<Card interactive asChild>
  <a href="/settings">
    <Stack gap={2}>
      <Heading size="sm">Settings</Heading>
      <Text size="sm" tone="muted">Manage your account.</Text>
    </Stack>
  </a>
</Card>
```

**raised hero card on a list page** — _"elevated card with a CTA"_

```tsx
<Card variant="elevated">
  <Stack gap={4}>
    <Heading size="lg">Upgrade to Pro</Heading>
    <Text>Unlock advanced analytics.</Text>
    <Button>Upgrade</Button>
  </Stack>
</Card>
```

---

<a id="collapsible"></a>

# Collapsible

A toggleable disclosure panel — show or hide a chunk of content behind a header.

> category: surface · status: stable · since: 0.1.0

```ts
import { Collapsible } from '@helixui/core'
```

### Tags

`disclosure`, `expand`, `accordion`, `show-hide`

### Anatomy

```
[▶ Title]                 ← collapsed
[▼ Title]
   <children>                ← expanded
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `header always visible, body animates open/closed`
- stackable: `true`
- fullBleed: `false`

### Visual

A header row with a rotating chevron and a body that animates its height when toggled. Header uses font.weight.semibold and a hover surface; body uses default text.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `ReactNode` | — | Header label. Required. |
| `isExpanded` | `boolean` | — | Controlled expanded state. |
| `defaultExpanded` | `boolean` | `false` | Uncontrolled initial. |
| `onExpandedChange` | `(expanded: boolean) => void` | — | Change handler. |
| `isDisabled` | `boolean` | `false` | Disables toggling. |

### Slots

- children — panel content

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.text.primary`, `color.text.secondary`, `color.border.default`, `color.border.focus`, `radius.md`, `space.3`, `space.4`, `font.family.sans`, `font.size.md`, `font.size.sm`, `font.weight.medium`

### Accessibility

Notes:
- Built on react-aria-components `Disclosure` — full ARIA expanded/controls and keyboard handled.
- For multiple coordinated collapsibles, use `DisclosureGroup` directly from `react-aria-components`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Stack` | `parent` | Group multiple Collapsibles in a Stack for an accordion. |
| `NavigationMenu` | `sibling` |  |
| `Tabs` | `sibling` |  |

### Prompt examples

**FAQ entry** — _"expandable FAQ question"_

```tsx
<Collapsible title="What is helixui?">
  helixui is an AI-friendly design system.
</Collapsible>
```

### Related

- NavigationMenu
- Tabs

---

# overlay

<a id="action-sheet"></a>

# ActionSheet

An iOS-style modal sheet that slides up from the bottom edge with a list of actions. Different from Sheet — Sheet is a side drawer, ActionSheet is a vertical action menu.

> category: overlay · status: stable · since: 0.5.0

```ts
import { ActionSheet, type ActionSheetAction } from '@helixui/core'
```

### Tags

`mobile`, `modal`, `menu`, `bottom-sheet`, `actions`, `ios`

### Anatomy

```
[overlay (dimmed)]
  ┌── action sheet panel (slides up from bottom) ──┐
  │  Title (optional)                              │
  │ ─────────────────────────────────────────────  │  n  │  • Action 1                                    │
  │  • Action 2                                    │
  │  • Destructive action  (red)                   │
  │ ─────────────────────────────────────────────  │
  │  Cancel                                        │
  └────────────────────────────────────────────────┘
```

### Layout

- display: `portal`
- width: `fill`
- height: `content`
- intrinsicSize: `pinned to bottom edge, max-h ~80vh, scrolls inside`
- stackable: `false`
- fullBleed: `true`

### Visual

A bottom-anchored panel with rounded top corners (radius.lg) that slides up from the bottom edge over a dimmed overlay. Each action is a full-width row separated by hairlines; destructive rows render in danger tone. A trailing Cancel row is separated by a small gap. Mounts with a translateY animation that respects prefers-reduced-motion.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `ReactNode` | — | Top centered title. |
| `description` | `ReactNode` | — | Sub-title under the title. |
| `actions` | `ActionSheetAction[]` | — | Required. List of actions; each has `id`, `label`, optional `description`, `icon`, `destructive`, `disabled`, and `onAction(close)`. |
| `cancelLabel` | `ReactNode` | `Cancel` | Label for the bottom cancel button. Set null to hide. |
| `isOpen` | `boolean` | — | Controlled open state. |
| `defaultOpen` | `boolean` | `false` | Uncontrolled initial open. |
| `onOpenChange` | `(open: boolean) => void` | — | Open change handler. |

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.action.danger`, `color.border.default`, `color.border.focus`, `radius.lg`, `space.1`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.xs`, `font.size.sm`, `font.size.md`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Role: `dialog`

Keyboard:
- `Escape` — Close.

Notes:
- Built on react-aria-components Modal — focus trap, restoration, dismiss on overlay click, all handled.
- The cancel button is a button (not an action item) so it visually separates from the list — matches iOS pattern.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Sheet` | `alternative` | Use Sheet for general side drawers; ActionSheet is the iOS-style action menu only. |
| `Menu` | `alternative` | On desktop prefer Menu anchored to a trigger. |
| `Button` | `trigger` | Common opener. |
| `Dialog` | `sibling` |  |
| `FAB` | `sibling` |  |

### Prompt examples

**mobile destructive choice** — _"show a delete / cancel sheet on tap"_

```tsx
<ActionSheet
  isOpen={open}
  onOpenChange={setOpen}
  actions={[
    { label: 'Delete', tone: 'danger', onPress: handleDelete },
    { label: 'Cancel', tone: 'neutral' },
  ]}
/>
```

**photo source picker** — _"Take photo / Choose from library / Cancel sheet"_

```tsx
<ActionSheet
  title="Add photo"
  isOpen={open}
  onOpenChange={setOpen}
  actions={[
    { label: 'Take Photo', onPress: takePhoto },
    { label: 'Choose from Library', onPress: pick },
    { label: 'Cancel' },
  ]}
/>
```

### Related

- Sheet
- Dialog
- FAB

---

<a id="command-palette"></a>

# CommandPalette

A Cmd+K command palette — searchable list of actions in a modal, with keyboard navigation and grouping.

> category: overlay · status: beta · since: 0.2.0

```ts
import { CommandPalette, type Command } from '@helixui/core'
```

### Tags

`cmd-k`, `search`, `actions`, `modal`, `productivity`

### Anatomy

```
┌─ overlay ────────────────────────────────┐
│  ┌── modal ───────────────────────────┐  │
│  │  > search                          │  │
│  │  ─────────────                     │  │
│  │  Section                           │  │
│  │   • action 1   ⌘K                  │  │
│  │   • action 2                       │  │
│  │  Section                           │  │
│  │   • action 3                       │  │
│  └────────────────────────────────────┘  │
└──────────────────────────────────────────┘
```

### Layout

- display: `portal`
- width: `fixed:560px`
- height: `content`
- intrinsicSize: `centered modal, max-h ~60vh`
- stackable: `false`
- fullBleed: `false`

### Visual

A centered modal with a top search input and a scrollable list of grouped commands beneath. Arrow keys navigate, Enter activates, ⌘K opens. Each item shows an optional icon, label, and shortcut hint.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `commands` | `Command[]` | — | Required. Each command has `id`, `label`, optional `group`, `hint`, `keywords`, `icon`, and an `onAction(close)` handler. |
| `isOpen` | `boolean` | — | Controlled visibility. |
| `defaultOpen` | `boolean` | `false` | Uncontrolled initial visibility. |
| `onOpenChange` | `(open: boolean) => void` | — | Visibility change handler. |
| `shortcut` | `string` | `Mod+k` | Global keyboard shortcut to open. `Mod` = Cmd on Mac, Ctrl elsewhere. |
| `placeholder` | `string` | `Type a command…` | Search input placeholder. |
| `emptyMessage` | `ReactNode` | `No matches.` | Shown when no commands match the query. |

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.subtle`, `color.border.default`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `radius.lg`, `radius.md`, `radius.sm`, `space.2`, `space.3`, `space.4`, `space.6`, `font.family.sans`, `font.family.mono`, `font.size.xs`, `font.size.sm`, `font.size.md`, `font.weight.semibold`, `shadow.lg`

### Accessibility

Keyboard:
- `Mod+k` — Open palette globally.
- `ArrowDown` — Next command.
- `ArrowUp` — Previous command.
- `Enter` — Run highlighted command.
- `Escape` — Close palette.

Notes:
- The input is `role="combobox"`; the list is `role="listbox"`; items are `role="option"`. The active item is announced via `aria-activedescendant`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Menu` | `alternative` | Menu is anchored to a trigger; CommandPalette is global. |
| `Dialog` | `alternative` | Dialog is for tasks; CommandPalette is for actions. |
| `Popover` | `sibling` |  |

### Prompt examples

**global cmd-k** — _"cmd+k command palette with two sections"_

```tsx
<CommandPalette
  isOpen={open}
  onOpenChange={setOpen}
  commands={[
    { group: 'File', items: [{ id: 'new', label: 'New file', onPress: createFile }] },
    { group: 'Help', items: [{ id: 'docs', label: 'Open docs', onPress: openDocs }] },
  ]}
/>
```

### Related

- Menu
- Dialog
- Popover

---

<a id="dialog"></a>

# Dialog

A modal that traps focus and dims the page behind it. Use for tasks that require completion before continuing.

> category: overlay · status: stable · since: 0.1.0

```ts
import { Dialog, DialogTrigger } from '@helixui/core'
```

### Tags

`modal`, `blocking`, `confirm`, `focus-trap`, `dismissable`

### Anatomy

```
┌─ overlay (full screen, dimmed) ────────────────────────┐
│                                                        │
│      ┌── dialog panel ─────────────────────────┐      │
│      │  Title (h2 slot)                         │      │
│      │  Description                              │      │
│      │                                           │      │
│      │  <children — usually a Stack form>        │      │
│      │                                           │      │
│      │  [ Cancel ]  [ Confirm ]   ← actions row  │      │
│      └──────────────────────────────────────────┘      │
│                                                        │
└────────────────────────────────────────────────────────┘
 ↑ trapped focus, dismiss on overlay-click + Escape (when isDismissable)
```

### Layout

- display: `portal`
- width: `fixed:380/540/720px (sm/md/lg)`
- height: `content`
- intrinsicSize: `centered, max-w by size, max-h ~80vh, scrolls inside`
- stackable: `false`
- fullBleed: `false`

### Visual

A centered surface (radius.xl) on a dimmed overlay. The panel uses surface.default with a strong shadow (shadow.lg)
and ample padding (space.6). Title is large semibold (font.size.xl + font.weight.semibold), description in muted
secondary text below. Mounts with a subtle scale-and-fade (respects prefers-reduced-motion). Body scrolls
internally when it overflows; header and footer remain pinned only if you compose them with Stack.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `ReactNode` | — | Dialog title — rendered as `<h2 slot="title">` for screen readers. |
| `description` | `ReactNode` | — | Lead paragraph below the title. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Max width — 380 / 540 / 720 px. |
| `isDismissable` | `boolean` | `true` | Allow close via overlay click and Escape. |
| `isOpen` | `boolean` | — | Controlled open state. |
| `defaultOpen` | `boolean` | `false` | Uncontrolled initial open. |
| `onOpenChange` | `(open: boolean) => void` | — | Open change handler. |

### Slots

- DialogTrigger child — the button that opens the dialog
- Dialog children — content; render-prop receives `{ close }` to close imperatively

### Tokens

`color.bg.surface.default`, `color.text.primary`, `color.text.secondary`, `radius.xl`, `space.4`, `space.6`, `space.12`, `font.family.sans`, `font.size.sm`, `font.size.xl`, `font.weight.semibold`, `font.lineHeight.tight`, `shadow.lg`

### Accessibility

Role: `dialog`

Keyboard:
- `Tab` — Cycles through focusable content. Focus is trapped.
- `Escape` — Closes the dialog when `isDismissable`.

Notes:
- Always provide `title` (or set `aria-label` on the Dialog) so screen readers announce the dialog's purpose.
- Animations respect `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `DialogTrigger` | `parent` | Required wrapper that provides the open trigger element. |
| `Button` | `trigger` | Most common trigger inside DialogTrigger. |
| `Stack` | `child` | Recommended layout for the dialog body and its actions row. |
| `Form` | `child` | Forms inside dialogs submit and then close via the render-prop `close()`. |
| `Sheet` | `alternative` | On small screens prefer Sheet (side='bottom') for the same task. |
| `Popover` | `alternative` | Use Popover for non-blocking, anchored interactions. |

### Prompt examples

**destructive confirmation** — _"delete account confirmation modal"_

```tsx
<DialogTrigger>
  <Button tone="danger">Delete account</Button>
  <Dialog title="Delete account?" description="This cannot be undone.">
    {({ close }) => (
      <Stack direction="row" justify="end" gap={2}>
        <Button variant="ghost" onPress={close}>Cancel</Button>
        <Button tone="danger" onPress={close}>Delete</Button>
      </Stack>
    )}
  </Dialog>
</DialogTrigger>
```

**small form in a modal** — _"modal to rename a project"_

```tsx
<DialogTrigger>
  <Button variant="soft">Rename</Button>
  <Dialog title="Rename project" size="sm">
    {({ close }) => (
      <Stack gap={3}>
        <TextInput label="Name" />
        <Stack direction="row" justify="end" gap={2}>
          <Button variant="ghost" onPress={close}>Cancel</Button>
          <Button onPress={close}>Save</Button>
        </Stack>
      </Stack>
    )}
  </Dialog>
</DialogTrigger>
```

**non-dismissable required choice** — _"accept terms blocking modal that cannot be dismissed"_

```tsx
<Dialog isOpen title="Accept the terms" isDismissable={false}>
  {({ close }) => (
    <Stack gap={4}>
      <Text>You must accept the terms to continue.</Text>
      <Button onPress={close}>I agree</Button>
    </Stack>
  )}
</Dialog>
```

**controlled open/close** — _"dialog whose open state lives in my component"_

```tsx
const [open, setOpen] = useState(false);
<Dialog isOpen={open} onOpenChange={setOpen} title="Edit">
  ...
</Dialog>
```

### Related

- Sheet
- Popover

---

<a id="fab"></a>

# FAB

Floating action button — circular by default, or pill (`extended`) with an icon + label. Fixed-positioned at the bottom-right by default; place yourself with `positioned={false}`.

> category: overlay · status: stable · since: 0.5.0

```ts
import { FAB } from '@helixui/core'
```

### Tags

`mobile`, `floating`, `primary-action`, `circular`

### Anatomy

```
…page content…
                     ╭─╮
                     │+│   ← circular FAB
                     ╰─╯
```

### Layout

- display: `fixed`
- width: `content`
- height: `content`
- intrinsicSize: `~56px circle (default), or pill in extended`
- stackable: `false`
- fullBleed: `false`

### Visual

A circular brand-colored button with a centered icon, fixed to the bottom-right with safe-area padding. The `extended` variant becomes a pill with icon + label. Uses shadow.lg for lift.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `aria-label` | `string` | — | Required accessible name when icon-only (no extended label). |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `brand` | Color intent. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Diameter / pill height — 40 / 56 / 64 px. |
| `extended` | `boolean` | `false` | Render as a pill with icon + label child. |
| `positioned` | `boolean` | `true` | Fixed-position at bottom-right with safe-area inset; set false to place manually. |
| `icon` | `ReactNode` | — | Icon content. |

### Slots

- children — used as label only when `extended`

### Tokens

`color.bg.action.brand.default`, `color.bg.action.brand.hover`, `color.bg.action.danger.default`, `color.bg.action.danger.hover`, `color.bg.action.neutral.default`, `color.bg.surface.default`, `color.text.on.brand`, `color.text.on.danger`, `color.text.primary`, `color.border.default`, `color.border.focus`, `radius.full`, `space.2`, `space.4`, `space.5`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.weight.semibold`, `shadow.lg`

### Accessibility

Role: `button`

Notes:
- Always provide `aria-label` for the icon-only variant — the screen reader has no visible text.
- Default placement adds `bottom: var(--helixui-space-4) + env(safe-area-inset-bottom)` so the FAB clears the iOS home indicator and any BottomNav.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `SafeArea` | `parent` | Wrap on mobile builds for inset. |
| `IconButton` | `alternative` | IconButton stays inline; FAB floats. |
| `BottomNav` | `sibling` |  |
| `ActionSheet` | `sibling` |  |

### Prompt examples

**compose new email** — _"a floating + button in the bottom-right"_

```tsx
<FAB icon={<PlusIcon />} aria-label="Compose" onPress={compose} />
```

**extended FAB with label** — _"pill-shaped FAB saying "New post""_

```tsx
<FAB extended icon={<PlusIcon />}>New post</FAB>
```

### Related

- BottomNav
- ActionSheet
- IconButton

---

<a id="floating-bar"></a>

# FloatingBar

A pinned action bar that floats over content — typically used for bulk actions on selected items.

> category: overlay · status: stable · since: 0.1.0

```ts
import { FloatingBar } from '@helixui/core'
```

### Tags

`floating`, `bulk-actions`, `selection`, `toolbar`

### Anatomy

```
┌── floating bar ──┐
│ 3 selected   ✕  Delete  Move ▾ │
└─────────────────┘
```

### Layout

- display: `fixed`
- width: `content`
- height: `content`
- intrinsicSize: `centered horizontally, near bottom of viewport`
- stackable: `false`
- fullBleed: `false`

### Visual

A pill-shaped surface with strong shadow (shadow.lg) that floats over the page content. Shows a leading status (e.g. "3 selected"), a divider, then trailing actions.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `placement` | `'bottom' \| 'top'` | `bottom` | Edge to anchor to. |
| `visible` | `boolean` | `true` | Show/hide with animation. Use to reveal on selection. |

### Slots

- children — a single pill-shaped wrapper that contains the actions

### Tokens

`color.bg.surface.default`, `color.border.default`, `color.text.primary`, `radius.full`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `shadow.lg`

### Accessibility

Role: `toolbar`

Notes:
- Provide an `aria-label` on the bar describing the available actions ("Bulk actions on N items").
- The bar is `aria-hidden` when not `visible`, removing it from the tab order.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Table` | `sibling` | Common over a Table during multi-select. |
| `List` | `sibling` | Or over a List with selectable rows. |
| `Button` | `sibling` |  |
| `IconButton` | `sibling` |  |

### Prompt examples

**bulk row actions** — _"floating bar showing 3 selected with Delete and Move"_

```tsx
<FloatingBar visible={count > 0} status={`${count} selected`}>
  <Button onPress={remove}>Delete</Button>
  <Button onPress={move}>Move</Button>
</FloatingBar>
```

### Related

- Button
- IconButton

---

<a id="menu"></a>

# Menu

A floating list of commands attached to a trigger.

> category: overlay · status: stable · since: 0.1.0

```ts
import { Menu, MenuItem, MenuTrigger, MenuSeparator, SubmenuTrigger } from '@helixui/core'
```

### Tags

`floating`, `menu`, `dropdown`, `actions`

### Anatomy

```
[ trigger ▾ ]
   ┌────────────────┐
   │ • Edit         │
   │ • Duplicate    │
   │ ─────────────  │
   │ • Delete  ⌘⌫   │
   └────────────────┘
```

### Layout

- display: `portal`
- width: `content`
- height: `content`
- intrinsicSize: `anchored to trigger, max-h with scroll`
- stackable: `false`
- fullBleed: `false`

### Visual

A floating panel anchored to its trigger. Items are rows with optional leading icon, label, and trailing kbd shortcut. Separators are 1px hairlines. Submenu items show a trailing chevron.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `placement` | `'top' \| 'bottom' \| 'start' \| 'end'` | `bottom` | Anchor placement. |
| `selectionMode` | `'none' \| 'single' \| 'multiple'` | `none` | Selection model. `none` for command menus. |
| `...rest` | `MenuProps from react-aria-components` | — | All forwarded. |

### Slots

- MenuTrigger children — the trigger button + Menu
- Menu children — MenuItem, MenuSeparator, SubmenuTrigger

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.neutral.hover`, `color.bg.action.danger.subtle`, `color.border.default`, `color.text.primary`, `color.text.muted`, `color.text.action.danger`, `radius.md`, `space.1`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.size.xs`, `shadow.md`

### Accessibility

Role: `menu`

Keyboard:
- `ArrowDown` — Move down.
- `ArrowUp` — Move up.
- `ArrowRight` — Open submenu.
- `ArrowLeft` — Close submenu.
- `Enter` — Activate item.
- `Escape` — Close menu.

Notes:
- For destructive items, set `destructive` — color shifts to danger and the focused background lightens to danger.subtle.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Button` | `trigger` | Common opener (MenuTrigger). |
| `IconButton` | `trigger` | Common opener for icon-only triggers. |
| `CommandPalette` | `alternative` | CommandPalette is global ⌘K; Menu is anchored. |
| `Popover` | `sibling` |  |
| `Dialog` | `sibling` |  |

### Prompt examples

**context menu** — _"three-dot menu with Edit, Duplicate, Delete"_

```tsx
<MenuTrigger>
  <IconButton aria-label="More"><MoreIcon /></IconButton>
  <Menu>
    <MenuItem onAction={edit}>Edit</MenuItem>
    <MenuItem onAction={dup}>Duplicate</MenuItem>
    <MenuSeparator />
    <MenuItem onAction={remove}>Delete</MenuItem>
  </Menu>
</MenuTrigger>
```

### Related

- Popover
- Dialog

---

<a id="popover"></a>

# Popover

A floating panel anchored to a trigger. Use for ephemeral content that doesn't justify a Dialog.

> category: overlay · status: stable · since: 0.1.0

```ts
import { Popover, PopoverTrigger, PopoverContent } from '@helixui/core'
```

### Tags

`floating`, `anchored`, `transient`

### Anatomy

```
[ trigger ]
   ╭───────────╮
   │  content  │  ← anchored
   ╰───▽───────╯
```

### Layout

- display: `portal`
- width: `content`
- height: `content`
- intrinsicSize: `anchored to trigger; placement auto`
- stackable: `false`
- fullBleed: `false`

### Visual

A floating panel with shadow.lg and arrow caret, anchored to a trigger. Closes on click-outside, Escape, or programmatically.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `placement` | `'top' \| 'bottom' \| 'start' \| 'end' \| …` | `bottom` | Anchor placement. See react-aria docs for full enum. |
| `offset` | `number` | `8` | Distance from trigger in pixels. |
| `isOpen` | `boolean` | — | Controlled open state. |
| `defaultOpen` | `boolean` | `false` | Uncontrolled initial open. |
| `onOpenChange` | `(open: boolean) => void` | — | Open change handler. |

### Slots

- PopoverTrigger child — the anchor element
- PopoverContent child — the floating content (renders in a portal)

### Tokens

`color.bg.surface.default`, `color.border.default`, `color.text.primary`, `radius.md`, `space.4`, `font.family.sans`, `font.size.sm`, `shadow.md`

### Accessibility

Notes:
- Composed of `<DialogTrigger>` + `<Popover>` + `<Dialog>` from react-aria-components — focus trapping, restoration, dismiss-on-outside, escape, all built in.
- Animation respects `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Button` | `trigger` | Common opener. |
| `IconButton` | `trigger` | Common opener for icon-only. |
| `Dialog` | `alternative` | Use Dialog for modal/blocking interactions. |
| `Tooltip` | `alternative` | Tooltip for short labels; Popover for richer content. |
| `Menu` | `sibling` |  |

### Prompt examples

**rich tooltip with actions** — _"popover anchored to a Help button"_

```tsx
<PopoverTrigger>
  <Button variant="ghost">Help</Button>
  <Popover><PopoverContent>Need help? <a href="/docs">Read the docs.</a></PopoverContent></Popover>
</PopoverTrigger>
```

### Related

- Dialog
- Tooltip
- Menu

---

<a id="sheet"></a>

# Sheet

A modal panel that slides in from a screen edge. Use for navigation, filters, or longer task flows on mobile.

> category: overlay · status: stable · since: 0.1.0

```ts
import { Sheet, SheetTrigger } from '@helixui/core'
```

### Tags

`drawer`, `side-panel`, `mobile`, `modal`

### Anatomy

```
┌─ overlay ────────────────────┐
│ ┌─ Sheet (side=start) ──┐    │
│ │  content              │    │  ← slides in from left/right/top/bottom
│ │                       │    │
│ └───────────────────────┘    │
└──────────────────────────────┘
```

### Layout

- display: `portal`
- width: `content`
- height: `fill`
- intrinsicSize: `fills 1 dimension; size by `side``
- stackable: `false`
- fullBleed: `true`

### Visual

A panel that slides in from the chosen edge over a dimmed overlay. Common sides are start (drawer), end (right inspector), bottom (mobile filters).

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `side` | `'start' \| 'end' \| 'top' \| 'bottom'` | `end` | Edge the sheet enters from. |
| `title` | `ReactNode` | — | Sheet title. |
| `description` | `ReactNode` | — | Lead paragraph. |
| `isDismissable` | `boolean` | `true` | Close via overlay click and Escape. |
| `isOpen` | `boolean` | — | Controlled open state. |
| `defaultOpen` | `boolean` | `false` | Uncontrolled initial open. |
| `onOpenChange` | `(open: boolean) => void` | — | Open change handler. |

### Slots

- SheetTrigger child — the trigger button
- Sheet children — render-prop receives `{ close }`

### Tokens

`color.bg.surface.default`, `color.text.primary`, `color.text.secondary`, `radius.xl`, `space.4`, `space.6`, `font.family.sans`, `font.size.sm`, `font.size.xl`, `font.weight.semibold`, `shadow.lg`

### Accessibility

Role: `dialog`

Notes:
- Same focus trapping and dismiss semantics as Dialog. The visual difference is the slide-in animation from a screen edge.
- On `bottom` and `top` sides, the sheet has rounded corners only on the entering edge.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Sidebar` | `child` | Used as the mobile drawer body. |
| `Dialog` | `alternative` | Dialog for centered tasks; Sheet for edge-anchored. |
| `ActionSheet` | `alternative` | ActionSheet is the iOS-style action menu. |
| `Popover` | `sibling` |  |

### Prompt examples

**mobile sidebar drawer** — _"left drawer with the main nav"_

```tsx
<Sheet side="start" isOpen={open} onOpenChange={setOpen}>
  <Sidebar>...</Sidebar>
</Sheet>
```

**filter panel** — _"right side filter sheet"_

```tsx
<SheetTrigger>
  <Button>Filter</Button>
  <Sheet side="end">…</Sheet>
</SheetTrigger>
```

### Related

- Dialog
- Popover

---

<a id="tooltip"></a>

# Tooltip

A short, on-hover/on-focus label for a control. Use for icon-only buttons or to expand abbreviations.

> category: overlay · status: stable · since: 0.1.0

```ts
import { Tooltip, TooltipTrigger } from '@helixui/core'
```

### Tags

`hint`, `label`, `on-hover`, `on-focus`

### Anatomy

```
[ trigger ]
   ╭───────────╮
   │ small text │
   ╰─▽─────────╯
```

### Layout

- display: `portal`
- width: `content`
- height: `content`
- intrinsicSize: `small floating label`
- stackable: `false`
- fullBleed: `false`

### Visual

A small dark surface with light text and an arrow caret pointing at the trigger. Appears on hover and focus, hides on blur or after a delay.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `placement` | `'top' \| 'bottom' \| 'start' \| 'end'` | `top` | Anchor placement. |
| `delay` | `number` | `300` | Open delay in ms. |
| `closeDelay` | `number` | `100` | Close delay in ms. |

### Slots

- TooltipTrigger child — the focusable element being described
- Tooltip child — the floating label

### Tokens

`color.bg.surface.inverse`, `color.text.inverse`, `radius.sm`, `space.2`, `font.family.sans`, `font.size.xs`, `font.weight.medium`

### Accessibility

Notes:
- Tooltips appear only on hover/focus and never replace a label. Use `aria-label` for naming.
- Tooltip content must be plain text. For richer content use a Popover with `role="dialog"`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `IconButton` | `wraps` | Most common — explain what the icon means. |
| `Popover` | `alternative` | Use Popover for richer interactive content. |

### Prompt examples

**explain an icon button** — _"tooltip on a settings icon button"_

```tsx
<TooltipTrigger>
  <IconButton aria-label="Settings"><GearIcon /></IconButton>
  <Tooltip>Open settings</Tooltip>
</TooltipTrigger>
```

### Related

- Popover
- IconButton

---

# form

<a id="button"></a>

# Button

Triggers an action when clicked.

> category: form · status: stable · since: 0.1.0

```ts
import { Button } from '@helixui/core'
```

### Tags

`clickable`, `action`, `primary`, `destructive`, `submit`, `cta`

### Anatomy

```
┌────────────────────────────────┐
│  [icon?]  Label  [icon?]       │   ← children = label, optional leading/trailing icon
└────────────────────────────────┘
 ↑ background per (variant, tone)
 ↑ border per (variant, tone)
 ↑ rounded by radius.md
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `~28px (sm) / 36px (md) / 44px (lg) tall, hugs label width`
- stackable: `true`
- fullBleed: `false`

### Visual

A pill-shaped, slightly rounded rectangle (radius.md). `solid` fills with the tone color and uses on-tone text;
`soft` is a tinted fill of the tone with the tone's text color; `outline` is transparent with a 1px tone border;
`ghost` is fully transparent until hover. Hover and active states deepen the tone by one step. The focus ring
is a 2px offset outline on `:focus-visible` only. Disabled buttons are 50% opacity and lose pointer events.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'solid' \| 'soft' \| 'ghost' \| 'outline'` | `solid` | Visual style. `solid` is the highest-emphasis option; `ghost` the lowest. |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `brand` | Color intent. `brand` for primary actions, `neutral` for secondary, `danger` for destructive. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Button size. Use `sm` in compact UIs (toolbars), `lg` for prominent calls to action. |
| `disabled` | `boolean` | `false` | Disables interaction. Removes the element from the tab order. |
| `type` | `'button' \| 'submit' \| 'reset'` | `button` | Native HTML button type. Defaults to `button` so the component does not accidentally submit forms. |
| `...rest` | `ButtonHTMLAttributes<HTMLButtonElement>` | — | All standard button attributes are forwarded to the underlying `<button>`. |

### Tokens

`color.bg.action.brand.default`, `color.bg.action.brand.hover`, `color.bg.action.brand.active`, `color.bg.action.brand.subtle`, `color.bg.action.neutral.default`, `color.bg.action.neutral.hover`, `color.bg.action.neutral.active`, `color.bg.action.danger.default`, `color.bg.action.danger.hover`, `color.bg.action.danger.active`, `color.bg.action.danger.subtle`, `color.bg.surface.default`, `color.text.on.brand`, `color.text.on.danger`, `color.text.primary`, `color.text.action.brand`, `color.text.action.danger`, `color.border.default`, `color.border.strong`, `color.border.focus`, `color.border.danger`, `radius.md`, `space.2`, `space.3`, `space.4`, `space.5`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.family.sans`, `font.weight.semibold`, `font.lineHeight.tight`

### Accessibility

Role: `button`

Keyboard:
- `Space` — Activates the button.
- `Enter` — Activates the button.

Notes:
- Always provide an accessible name via children or `aria-label`. Icon-only buttons must use `aria-label`.
- Prefer `aria-disabled="true"` over `disabled` when the action is conditionally unavailable but should remain focusable so users can discover it.
- The focus ring is rendered with `outline` and only on `:focus-visible`, so mouse users do not see it.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `IconButton` | `alternative` | Use IconButton when there is no text label. |
| `Form` | `parent` | `type="submit"` submits the surrounding Form. |
| `DialogTrigger` | `child` | Common opener for dialogs. |
| `Stack` | `parent` | Group multiple buttons in a Stack with `direction="row"`. |
| `Tooltip` | `wraps` | Wrap with Tooltip when the action needs explanation. |

### Prompt examples

**primary call-to-action** — _"add a Save button"_

```tsx
<Button>Save</Button>
```

**destructive action** — _"make a Delete button"_

```tsx
<Button tone="danger">Delete</Button>
```

**secondary action next to a primary** — _"Cancel + Save buttons in a row"_

```tsx
<Stack direction="row" gap={2} justify="end">
  <Button variant="ghost" tone="neutral">Cancel</Button>
  <Button>Save</Button>
</Stack>
```

**icon-only action in a toolbar** — _"small ghost button with just a search icon"_

```tsx
<Button variant="ghost" size="sm" aria-label="Search">
  <SearchIcon />
</Button>
```

**form submission** — _"submit button at the bottom of a form"_

```tsx
<Button type="submit" size="lg">Create account</Button>
```

### Related

- IconButton

---

<a id="calendar"></a>

# Calendar

A month-view date picker. Internationalized via @internationalized/date — supports any calendar system, not just Gregorian.

> category: form · status: stable · since: 0.1.0

```ts
import { Calendar, RangeCalendar } from '@helixui/core'
```

### Tags

`date`, `picker`, `month-view`, `i18n`

### Anatomy

```
[<] May 2026 [>]
Su Mo Tu We Th Fr Sa
             1  2  3
 4  5  6  7  8  9 10
11 12 13 14 15 16 17  ← selected highlighted
18 19 20 21 22 23 24
25 26 27 28 29 30 31
```

### Layout

- display: `block`
- width: `content`
- height: `content`
- intrinsicSize: `~280×320px (month grid)`
- stackable: `false`
- fullBleed: `false`

### Visual

A 7-column grid with a previous/next month header. Day cells are square; today shows a ring; selected day fills with brand color; hover tints with action.brand.subtle. Range mode highlights the span between two anchors.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `DateValue` | — | Controlled selected date. |
| `defaultValue` | `DateValue` | — | Uncontrolled initial selection. |
| `minValue` | `DateValue` | — | Earliest selectable date. |
| `maxValue` | `DateValue` | — | Latest selectable date. |
| `isDisabled` | `boolean` | `false` | Disable the entire calendar. |
| `isReadOnly` | `boolean` | `false` | Block selection but keep navigation. |
| `onChange` | `(date: DateValue) => void` | — | Selection change handler. |

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.bg.action.brand.subtle`, `color.border.default`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.on.brand`, `radius.md`, `radius.sm`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.xs`, `font.size.sm`, `font.size.md`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Role: `application`

Keyboard:
- `ArrowKeys` — Move focus by day.
- `PageUp` — Previous month.
- `PageDown` — Next month.
- `Home` — Start of week.
- `End` — End of week.
- `Enter` — Select date.

Notes:
- Built on react-aria-components Calendar — full a11y, RTL, calendar systems, internationalization.
- Use `@internationalized/date` to construct DateValue objects (`parseDate`, `today`, etc.).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Popover` | `parent` | Often rendered inside a Popover triggered by a TextInput. |
| `TextInput` | `sibling` | Common pairing — input shows formatted date, calendar picks it. |

### Prompt examples

**simple date picker** — _"pick a single date"_

```tsx
<Calendar value={date} onChange={setDate} />
```

**date range** — _"pick a start and end date"_

```tsx
<RangeCalendar value={range} onChange={setRange} />
```

---

<a id="checkbox"></a>

# Checkbox

A binary checkbox with indeterminate state.

> category: form · status: stable · since: 0.1.0

```ts
import { Checkbox } from '@helixui/core'
```

### Tags

`boolean`, `toggle`, `multi-select`, `form`

### Anatomy

```
[ ☐ ]  Label       ← unchecked
[ ☑ ]  Label       ← checked
[ ▣ ]  Label       ← indeterminate
```

### Layout

- display: `inline-flex`
- width: `content`
- height: `content`
- intrinsicSize: `~20px box + label gap`
- stackable: `true`
- fullBleed: `false`

### Visual

A small rounded square (radius.sm) that fills with brand color when checked, with a white check glyph. Indeterminate state shows a horizontal bar. Label sits to the right with space.2 gap.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `isSelected` | `boolean` | `false` | Controlled checked state. |
| `defaultSelected` | `boolean` | `false` | Uncontrolled initial state. |
| `isIndeterminate` | `boolean` | `false` | Shows a dash glyph indicating mixed state. |
| `isRequired` | `boolean` | `false` | Marks required for validation. |
| `isInvalid` | `boolean` | `false` | Forces invalid state. |
| `isDisabled` | `boolean` | `false` | Disables interaction. |
| `onChange` | `(isSelected: boolean) => void` | — | Change handler. |
| `...rest` | `CheckboxProps from react-aria-components` | — | All forwarded. |

### Slots

- children — visible label text

### Tokens

`color.bg.surface.default`, `color.bg.action.brand.default`, `color.text.primary`, `color.text.on.brand`, `color.border.strong`, `color.border.focus`, `color.border.danger`, `radius.sm`, `space.2`, `font.family.sans`, `font.size.sm`

### Accessibility

Role: `checkbox`

Keyboard:
- `Space` — Toggles the checkbox.

Notes:
- Built on react-aria-components Checkbox — full keyboard, screen-reader, and indeterminate handling.
- For groups of related options, use CheckboxGroup (follow react-aria-components).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Field` | `parent` | Use Field if you need separate label/description structure. |
| `Form` | `parent` | Submitted as part of a Form. |
| `Switch` | `sibling` |  |
| `RadioGroup` | `sibling` |  |

### Prompt examples

**agree-to-terms** — _"checkbox to accept terms"_

```tsx
<Checkbox isSelected={ok} onChange={setOk}>I agree to the terms</Checkbox>
```

**select all in a table** — _"header checkbox with indeterminate when partially selected"_

```tsx
<Checkbox isIndeterminate={partial} isSelected={all} onChange={toggleAll}>Select all</Checkbox>
```

### Related

- Switch
- RadioGroup

---

<a id="code-editor"></a>

# CodeEditor

An editable code surface backed by either CodeMirror 6 or Monaco. Pick the engine via a single prop. Both engines lazy-load and are declared as optional peer dependencies — install only what you use.

> category: form · status: stable · since: 0.6.0

```ts
import { CodeEditor } from '@helixui/core'
```

### Tags

`code`, `editor`, `editable`, `codemirror`, `monaco`

### Anatomy

```
┌─ tsx ──────────────────────────────────┐
│  1  const x = 1;          ← line nums   │
│  2  console.log(x);                     │
│  3  |                                   │
└─────────────────────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `fixed:320px`
- intrinsicSize: `fills width, default 320px tall, scrolls inside`
- stackable: `false`
- fullBleed: `false`

### Visual

A full-featured code editor surface with line numbers, syntax highlighting, and (when enabled) folding and minimap. Engine-agnostic — both CodeMirror 6 and Monaco are supported and lazy-loaded.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | `''` | Current document text. |
| `onChange` | `(value: string) => void` | `—` | Fires on every edit with the new text. |
| `engine` | `'codemirror' \| 'monaco'` | `codemirror` | Which engine to mount. CodeMirror is lighter; Monaco offers full IDE feel. |
| `language` | `'typescript' \| 'javascript' \| 'json' \| 'python' \| 'html' \| 'css' \| 'markdown' \| 'plaintext'` | `plaintext` | Language for syntax highlighting and language services. |
| `theme` | `'light' \| 'dark' \| 'auto'` | `auto` | `auto` follows `document.documentElement.dataset.theme` and updates live. |
| `readOnly` | `boolean` | `false` | Disable editing. |
| `lineNumbers` | `boolean` | `auto` | On by default on desktop, off on mobile. |
| `wordWrap` | `boolean` | `auto` | Off by default on desktop, on on mobile. |
| `tabSize` | `number` | `2` | Tab width in spaces. |
| `fontSize` | `number` | `14 / 13` | 14 desktop, 13 mobile by default. |
| `height` | `number \| string` | `360` | Numbers are treated as px. Strings pass through (`'50vh'`, `'100%'`). |
| `autoFocus` | `boolean` | `false` | Focus the editor when it mounts. |
| `codemirrorExtensions` | `unknown[]` | `[]` | Extra CodeMirror 6 extensions appended after defaults. |
| `monacoOptions` | `Record<string, unknown>` | `{}` | Partial Monaco IStandaloneEditorConstructionOptions, spread last. |
| `onMount` | `(info: { engine, instance }) => void` | `—` | Fires once mounted. Receives the underlying editor instance. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.subtle`, `color.border.default`, `color.border.focus`, `color.text.muted`, `color.text.primary`, `color.text.action.danger`, `color.bg.action.danger.subtle`, `radius.md`, `font.family.mono`, `motion.duration.fast`, `motion.easing.standard`

### Accessibility

Notes:
- Both engines provide their own keyboard accessibility (cursor movement, selection, find).
- Container shows a `:focus-within` ring matching helixui's other inputs.
- Respects `prefers-reduced-motion` via the global motion stylesheet — no per-engine guard required.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `CodeBlock` | `alternative` | Use CodeBlock for static display. |
| `Form` | `parent` | Can act as a controlled form input. |

### Prompt examples

**editable JSON config** — _"editable code area for JSON"_

```tsx
<CodeEditor language="json" value={value} onChange={setValue} />
```

### Related

- CodeBlock

---

<a id="color-picker"></a>

# ColorPicker

An HSB color picker — saturation/brightness area, hue slider, and hex input. Available inline or in a popover.

> category: form · status: beta · since: 0.1.0

```ts
import { ColorPicker, ColorPickerInline } from '@helixui/core'
```

### Tags

`color`, `hsb`, `picker`

### Anatomy

```
┌──────────────────┐
│ saturation/value │
│   gradient area  │
│       (●)        │  ← drag handle
└──────────────────┘
┌─────── hue slider ──────┐ #3b82f6  [hex]
```

### Layout

- display: `block`
- width: `content`
- height: `content`
- intrinsicSize: `~240×240 area + sliders`
- stackable: `false`
- fullBleed: `false`

### Visual

A 2-D saturation × value gradient with a draggable thumb, a horizontal hue slider beneath, and a hex input. ColorPickerInline embeds it; ColorPicker (default) puts it inside a Popover.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Visible label. |
| `value` | `Color` | — | Controlled color (use `parseColor()` from react-aria-components). |
| `defaultValue` | `Color` | `#3b82f6` | Uncontrolled initial color. |
| `onChange` | `(color: Color) => void` | — | Color change handler. |

### Tokens

`color.bg.surface.default`, `color.border.default`, `color.border.focus`, `color.text.primary`, `radius.md`, `radius.sm`, `radius.full`, `space.2`, `space.3`, `font.family.sans`, `font.family.mono`, `font.size.sm`, `font.weight.medium`, `shadow.md`

### Accessibility

Notes:
- Built on react-aria-components ColorPicker — keyboard arrows move the saturation/brightness thumb and hue thumb in 1% steps; Shift+arrow moves in 10% steps.
- The hex input accepts any valid CSS color and normalizes it.
- The popover variant uses DialogTrigger for focus management when open.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Popover` | `parent` | Default rendering is inside a Popover. |

### Prompt examples

**theme color picker** — _"pick a hex color"_

```tsx
<ColorPicker value={color} onChange={setColor} />
```

### Related

- Popover

---

<a id="currency-input"></a>

# CurrencyInput

Locale-aware currency input. Formats on blur, parses on the fly. Uses Intl.NumberFormat for symbols, separators, and precision.

> category: form · status: stable · since: 0.1.0

```ts
import { CurrencyInput } from '@helixui/core'
```

### Tags

`currency`, `money`, `money-input`, `locale`, `intl`, `payment`, `pricing`

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number \| null` | `undefined` | Controlled numeric value. |
| `defaultValue` | `number \| null` | `undefined` | Uncontrolled initial value. |
| `onValueChange` | `(value: number \| null) => void` | `undefined` | Fires with the parsed numeric value or null when the field is empty. |
| `currency` | `string` | `USD` | ISO 4217 currency code. Drives the symbol and the default precision. |
| `locale` | `string` | `navigator.language` | Override the user's locale. Affects symbol position and decimal separator. |
| `showSymbol` | `boolean` | `true` | Render the currency symbol inside the input. |
| `precision` | `number` | `undefined` | Override the number of decimal places. Defaults to what the currency expects. |
| `positiveOnly` | `boolean` | `true` | Reject negative values. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Input size. |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `brand` | Tone for focus ring. |

### Tokens

`color.bg.input`, `color.bg.surface.default`, `color.bg.action.brand.subtle`, `color.border.subtle`, `color.border.action.brand`, `color.border.danger`, `color.text.primary`, `color.text.muted`, `radius.md`, `spacing.1`, `spacing.2`, `spacing.3`, `spacing.4`, `font.size.xs`, `font.size.sm`, `font.size.md`, `font.size.lg`

### Accessibility

Role: `textbox`

Keyboard:
- `0-9` — Enter digits.
- `.` — Decimal separator (or `,` depending on locale).

Notes:
- Uses `inputmode='decimal'` so mobile keyboards show the numeric layout.
- On blur the value reformats with thousands separators.
- Without an explicit `aria-label`, defaults to e.g. "USD amount".

### Related

- text-input
- number-field

---

<a id="date-field"></a>

# DateField

Segmented date input — month / day / year (or whatever the user's locale prefers). Built on react-aria-components.

> category: form · status: stable · since: 0.1.0

```ts
import { DateField } from '@helixui/core'
```

### Tags

`date`, `input`, `segmented`, `picker`, `calendar`

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `undefined` | Field label rendered above the segmented input. |
| `description` | `string` | `undefined` | Helper text rendered below the field. |
| `errorMessage` | `string` | `undefined` | Validation message shown when the field is invalid. |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `brand` | Tone for the focus ring and error styling. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Touch target size, matching every other helixui input. |
| `value` | `DateValue \| null` | `undefined` | Controlled value. |
| `defaultValue` | `DateValue` | `undefined` | Uncontrolled initial value. |
| `onChange` | `(value: DateValue \| null) => void` | `undefined` | Fires whenever the user completes a segment edit. |
| `minValue` | `DateValue` | `undefined` | Earliest selectable date. |
| `maxValue` | `DateValue` | `undefined` | Latest selectable date. |
| `isDisabled` | `boolean` | `false` | Renders the field disabled and removes it from tab order. |
| `isReadOnly` | `boolean` | `false` | Renders the field non-editable but still focusable. |

### Tokens

`color.bg.input`, `color.bg.surface.default`, `color.border.subtle`, `color.border.action.brand`, `color.border.danger`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.danger`, `radius.sm`, `radius.md`, `spacing.1`, `spacing.2`, `spacing.3`, `spacing.4`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.size.xs`

### Accessibility

Role: `group`

Keyboard:
- `Tab` — Focus the next segment.
- `ArrowUp` — Increment the focused segment.
- `ArrowDown` — Decrement the focused segment.
- `0-9` — Overwrite the focused segment.

Notes:
- Each segment is independently focusable.
- Disabled and read-only states respect ARIA conventions.
- `errorMessage` is announced via `aria-describedby`.

---

<a id="date-picker"></a>

# DatePicker

Segmented date input plus a popover calendar. Pick a date by typing, arrow keys, or clicking the grid.

> category: form · status: stable · since: 0.1.0

```ts
import { DatePicker } from '@helixui/core'
```

### Tags

`date`, `picker`, `popover`, `calendar`, `input`

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `undefined` | Field label rendered above the trigger. |
| `description` | `string` | `undefined` | Helper text rendered below the trigger. |
| `errorMessage` | `string` | `undefined` | Validation error rendered when the field is invalid. |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `brand` | Tone for the focus ring and the selected day in the calendar. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Touch target size matching every other helixui input. |
| `value` | `DateValue \| null` | `undefined` | Controlled selected date. |
| `defaultValue` | `DateValue` | `undefined` | Uncontrolled initial selected date. |
| `onChange` | `(value: DateValue \| null) => void` | `undefined` | Fires when the user picks a date in the grid or commits a segment edit. |
| `minValue` | `DateValue` | `undefined` | Earliest selectable date. |
| `maxValue` | `DateValue` | `undefined` | Latest selectable date. |
| `isDateUnavailable` | `(date: DateValue) => boolean` | `undefined` | Mark specific dates as unselectable (blackout dates). |
| `isDisabled` | `boolean` | `false` | Disable the entire picker. |
| `isReadOnly` | `boolean` | `false` | Show the field as non-editable while still focusable. |

### Tokens

`color.bg.input`, `color.bg.surface.default`, `color.bg.surface.subtle`, `color.bg.action.brand.default`, `color.bg.action.brand.subtle`, `color.border.subtle`, `color.border.action.brand`, `color.border.danger`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.action.brand.on`, `color.text.danger`, `radius.sm`, `radius.md`, `radius.lg`, `shadow.lg`, `spacing.1`, `spacing.2`, `spacing.3`, `spacing.4`, `font.size.xs`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.weight.regular`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Role: `combobox`

Keyboard:
- `Tab` — Focus the next segment or the trigger.
- `ArrowUp` — Increment focused segment.
- `ArrowDown` — Decrement focused segment.
- `Enter` — Open the popover from the trigger; select a focused day in the grid.
- `Escape` — Close the popover.
- `ArrowKeys` — Inside the grid — move by day; PageUp/PageDown by month.

Notes:
- Each input segment is independently focusable.
- The trigger is a labeled `<button>` that opens a dialog with the calendar.
- The dialog traps focus while open and restores focus to the trigger on close.
- Days announce their selection state and unavailable state.
- `errorMessage` is exposed via `aria-describedby`.

---

<a id="date-range-picker"></a>

# DateRangePicker

Two segmented date inputs (start + end) plus a popover range calendar.

> category: form · status: stable · since: 0.1.0

```ts
import { DateRangePicker } from '@helixui/core'
```

### Tags

`date`, `range`, `picker`, `calendar`, `popover`, `departure`, `return`

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `undefined` | Field label rendered above the trigger row. |
| `description` | `string` | `undefined` | Helper text rendered below the trigger row. |
| `errorMessage` | `string` | `undefined` | Validation error rendered when the field is invalid. |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `brand` | Tone for the focus ring and selected days. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Touch target size, matching every other helixui input. |
| `value` | `RangeValue<DateValue> \| null` | `undefined` | Controlled selected range. |
| `defaultValue` | `RangeValue<DateValue>` | `undefined` | Uncontrolled initial range. |
| `onChange` | `(value: RangeValue<DateValue> \| null) => void` | `undefined` | Fires when the user picks a complete range. |
| `minValue` | `DateValue` | `undefined` | Earliest selectable date. |
| `maxValue` | `DateValue` | `undefined` | Latest selectable date. |
| `isDateUnavailable` | `(date: DateValue) => boolean` | `undefined` | Mark specific dates as unselectable (blackout dates). |
| `isDisabled` | `boolean` | `false` | Disable the entire picker. |
| `isReadOnly` | `boolean` | `false` | Show as non-editable. |

### Tokens

`color.bg.surface.default`, `color.bg.action.brand.default`, `color.bg.action.brand.subtle`, `color.border.subtle`, `color.border.action.brand`, `color.text.primary`, `color.text.muted`, `color.text.action.brand`, `color.text.action.brand.on`, `radius.md`, `spacing.1`

### Accessibility

Role: `combobox`

Keyboard:
- `Tab` — Move between start / end segments and the trigger.
- `ArrowUp` — Increment focused segment.
- `ArrowDown` — Decrement focused segment.
- `Enter` — Open the popover; on the grid, anchor or commit the range.
- `ArrowKeys` — Inside the grid — move by day; PageUp/PageDown by month.

Notes:
- Each segment is independently focusable.
- The trigger is a labeled button; opens a dialog with a range-aware calendar.
- Days inside the active range announce as `aria-selected`.

### Related

- date-picker
- calendar

---

<a id="date-time-picker"></a>

# DateTimePicker

Date + time picker — segmented date input, time field, and a popover calendar. For meeting times, appointment slots, scheduled posts.

> category: form · status: stable · since: 0.1.0

```ts
import { DateTimePicker } from '@helixui/core'
```

### Tags

`date`, `time`, `picker`, `calendar`, `schedule`, `appointment`

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `undefined` | Field label rendered above the row. |
| `description` | `string` | `undefined` | Helper text rendered below the row. |
| `errorMessage` | `string` | `undefined` | Validation message shown when invalid. |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `brand` | Tone for focus ring + selected day. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Touch target size. |
| `value` | `DateValue \| null` | `undefined` | Controlled date. |
| `onChange` | `(value: DateValue \| null) => void` | `undefined` | Fires when the date changes. |
| `time` | `TimeValue` | `undefined` | Controlled time portion. |
| `onTimeChange` | `(value: TimeValue \| null) => void` | `undefined` | Fires when the time changes. |
| `defaultTime` | `TimeValue` | `undefined` | Uncontrolled initial time. |
| `timeStep` | `number` | `5` | Granularity of the minute field, in minutes. |

### Tokens

`color.bg.surface.default`, `color.bg.action.brand.default`, `color.border.subtle`, `color.border.action.brand`, `color.text.primary`, `color.text.muted`, `color.text.action.brand`, `radius.sm`, `radius.md`, `radius.lg`, `spacing.1`, `spacing.2`, `spacing.3`

### Accessibility

Role: `combobox`

Keyboard:
- `Tab` — Move between date segments, time segments, and the trigger.
- `ArrowUp` — Increment focused segment.
- `ArrowDown` — Decrement focused segment.
- `Enter` — Open the popover from the trigger; select a focused day in the grid.

Notes:
- Date and time fields are independently focusable.
- Time field defaults to 24-hour; pass `hourCycle={12}` via wrapping for am/pm.
- The popover calendar only affects the date; the time persists across day changes.

### Related

- date-picker
- date-range-picker
- calendar

---

<a id="field"></a>

# Field

A vertical layout for label + control + description + error message. Use with non-RAC controls; RAC inputs (TextInput, Checkbox, etc.) already accept `label`/`description`/`errorMessage` props.

> category: form · status: stable · since: 0.1.0

```ts
import { Field } from '@helixui/core'
```

### Tags

`label`, `description`, `error`, `wrapper`

### Anatomy

```
Label                                            (required)
[control]
Help text describing the field
Error message
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `vertical stack, hugs control height`
- stackable: `true`
- fullBleed: `false`

### Visual

A vertical stack: a label (font.weight.semibold), the wrapped control, an optional muted description, and an error message in danger tone when present.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `...rest` | `HTMLAttributes<HTMLDivElement>` | — | Native div attributes. |

### Slots

- children — Field.Label, the control, Field.Description, Field.Error in any order

### Tokens

`color.text.primary`, `color.text.secondary`, `color.text.action.danger`, `font.family.sans`, `font.size.sm`, `font.weight.medium`, `space.2`

### Accessibility

Notes:
- Field is presentational. Wire `htmlFor`/`id` between Label and the control yourself.
- Field.Error has `role="alert"` so screen readers announce changes.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `TextInput` | `wraps` | Wrap any non-RAC control with Field for label/description/error. |
| `Form` | `parent` | Inside a Form. |
| `Textarea` | `sibling` |  |
| `Checkbox` | `sibling` |  |
| `Switch` | `sibling` |  |
| `RadioGroup` | `sibling` |  |

### Prompt examples

**wrap a custom control** — _"add label/help to a custom select"_

```tsx
<Field label="Country" description="Used for tax purposes">
  <CustomSelect />
</Field>
```

### Related

- TextInput
- Textarea
- Checkbox
- Switch
- RadioGroup

---

<a id="file-upload"></a>

# FileUpload

Drag-and-drop file upload with progress, errors, and accept/size filtering. Pair with your own upload pipeline.

> category: form · status: stable · since: 0.1.0

```ts
import { FileUpload } from '@helixui/core'
```

### Tags

`file`, `upload`, `dropzone`, `attachment`, `drag-drop`, `input`

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `undefined` | Field label rendered above the dropzone. |
| `description` | `ReactNode` | `undefined` | Helper text rendered below the dropzone. |
| `hint` | `ReactNode` | `undefined` | Visible inside the dropzone — defaults to a "Click to upload or drag and drop" cue. |
| `accept` | `string` | `undefined` | MIME / extension filter; e.g. "image/*" or ".pdf,.docx". |
| `maxSize` | `number` | `undefined` | Max file size in bytes. Files larger are reported via `onReject`. |
| `multiple` | `boolean` | `false` | Allow selecting more than one file. |
| `onFiles` | `(files: File[]) => void` | `undefined` | Fires when files pass the accept + size filters. |
| `onReject` | `(rejections: { file: File; reason: 'size' \| 'type' }[]) => void` | `undefined` | Fires for files that fail filtering. |
| `progress` | `Record<string, number>` | `undefined` | Map of file.name → 0-100 percent. helixui renders a progress bar per file. |
| `errors` | `Record<string, string>` | `undefined` | Optional per-file error messages, keyed by file.name. |
| `tone` | `'brand' \| 'neutral'` | `brand` | Tone for the active drop ring. |
| `disabled` | `boolean` | `false` | Disable interaction. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.subtle`, `color.bg.action.brand.subtle`, `color.bg.action.brand.default`, `color.border.subtle`, `color.border.action.brand`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.danger`, `radius.sm`, `radius.md`, `radius.lg`, `spacing.1`, `spacing.2`, `spacing.3`, `spacing.5`, `font.size.xs`, `font.size.sm`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Role: `button`

Keyboard:
- `Tab` — Focus the dropzone.
- `Enter` — Open the native file picker.
- `Space` — Open the native file picker.

Notes:
- The dropzone is a labeled button (`role="button"`) for screen readers.
- Drag-and-drop is a supplementary affordance; keyboard + native picker is the primary path.
- Each progress bar exposes ARIA progress state with min/max/value.
- Disabled state removes the dropzone from the tab order.

### Related

- attachment-tile

---

<a id="form"></a>

# Form

A `<form>` wrapper from react-aria-components that surfaces validation errors per-field via the `validationErrors` prop.

> category: form · status: stable · since: 0.1.0

```ts
import { Form } from '@helixui/core'
```

### Tags

`form`, `validation`, `submit`, `rac`

### Anatomy

```
<Form>
  Field…
  Field…
  [ Cancel ] [ Submit ]
</Form>
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `native form element; layout by children`
- stackable: `true`
- fullBleed: `false`

### Visual

A `<form>` wrapper with no inherent visuals. Provides a `validationErrors` prop that surfaces server validation against fields by name.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `validationErrors` | `Record<string, string \| string[]>` | — | Server-side validation errors keyed by field name. Forwarded to each FieldError. |
| `onSubmit` | `(e: FormEvent) => void` | — | Submit handler. Native form behavior unless `e.preventDefault()`. |
| `...rest` | `FormHTMLAttributes<HTMLFormElement>` | — | All native form attributes. |

### Tokens

`space.5`

### Accessibility

Notes:
- Use `<Form>` instead of `<form>` to get react-aria's coordinated validation handling.
- Server errors via `validationErrors` are surfaced to the corresponding fields automatically.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Field` | `child` | Each control is wrapped in a Field. |
| `TextInput` | `child` | RAC inputs accept label/description directly. |
| `Button` | `child` | Submit button at the end. |
| `Textarea` | `sibling` |  |
| `Checkbox` | `sibling` |  |
| `RadioGroup` | `sibling` |  |

### Prompt examples

**login form** — _"email + password + submit"_

```tsx
<Form onSubmit={handleSubmit}>
  <TextInput name="email" label="Email" />
  <TextInput name="password" label="Password" type="password" />
  <Button type="submit">Sign in</Button>
</Form>
```

### Related

- TextInput
- Textarea
- Checkbox
- RadioGroup
- Field

---

<a id="icon-button"></a>

# IconButton

A square button containing only an icon. Requires an accessible label.

> category: form · status: stable · since: 0.1.0

```ts
import { IconButton } from '@helixui/core'
```

### Tags

`clickable`, `icon-only`, `compact`, `action`

### Anatomy

```
[ ⊙ ]   ← square button, icon only
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `~28/36/44px square (sm/md/lg)`
- stackable: `true`
- fullBleed: `false`

### Visual

A square button (radius.md) sized for an icon child. Same variants and tones as Button. Requires `aria-label`.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `aria-label` | `string` | — | Required. Names the action — screen readers have no visible text to read. |
| `variant` | `'solid' \| 'soft' \| 'ghost' \| 'outline'` | `ghost` | Visual style. |
| `tone` | `'brand' \| 'neutral' \| 'danger'` | `neutral` | Color intent. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Square size — 32 / 40 / 48 px. |

### Slots

- children — the icon node

### Tokens

`color.bg.action.brand.default`, `color.bg.action.brand.hover`, `color.bg.action.brand.subtle`, `color.bg.action.neutral.default`, `color.bg.action.neutral.hover`, `color.bg.action.danger.default`, `color.bg.action.danger.hover`, `color.bg.action.danger.subtle`, `color.bg.surface.default`, `color.text.primary`, `color.text.on.brand`, `color.text.on.danger`, `color.text.action.brand`, `color.text.action.danger`, `color.border.default`, `color.border.strong`, `color.border.focus`, `radius.md`

### Accessibility

Role: `button`

Notes:
- `aria-label` is required. TypeScript enforces it.
- For destructive icon-only actions, include a Tooltip describing what the action does.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Tooltip` | `wraps` | Wrap with Tooltip to expose what the icon means. |
| `Button` | `alternative` | Use Button when there is a text label. |
| `ChatHeader` | `child` | Common in right-aligned actions. |

### Prompt examples

**menu trigger icon** — _"three-dot icon button with tooltip"_

```tsx
<TooltipTrigger><IconButton aria-label="More"><MoreIcon /></IconButton><Tooltip>More</Tooltip></TooltipTrigger>
```

### Related

- Button
- Tooltip

---

<a id="input-group"></a>

# InputGroup

A horizontal layout for multiple controls. With `attached`, children share a single rounded border.

> category: form · status: stable · since: 0.1.0

```ts
import { InputGroup } from '@helixui/core'
```

### Tags

`composite`, `attached`, `input-row`

### Anatomy

```
[ prefix ][ input              ][ suffix ]
 └────── attached border (single radius) ───────┘
```

### Layout

- display: `inline-flex`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, hugs content height`
- stackable: `false`
- fullBleed: `false`

### Visual

A horizontal row of controls. With `attached`, children share a single rounded outer border and inner borders collapse, producing the classic "URL prefix + input + button" look.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `attached` | `boolean` | `false` | Joins children with shared border (segmented look). |
| `...rest` | `HTMLAttributes<HTMLDivElement>` | — | Native div attributes. |

### Slots

- children — controls (TextInput, Button, IconButton, Select, etc.)

### Tokens

`space.2`, `radius.md`

### Accessibility

Role: `group`

Notes:
- Container is `role=\"group\"`; provide a `aria-label` describing the group's purpose.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `TextInput` | `child` | Most common middle child. |
| `Button` | `child` | Trailing action. |
| `Select` | `child` | Leading or trailing. |

### Prompt examples

**URL field with copy button** — _"attached input + button row"_

```tsx
<InputGroup attached>
  <TextInput value={url} readOnly />
  <Button onPress={copy}>Copy</Button>
</InputGroup>
```

### Related

- TextInput

---

<a id="multi-select"></a>

# MultiSelect

A combobox that accepts multiple values, displayed as removable tags inline.

> category: form · status: beta · since: 0.1.0

```ts
import { MultiSelect, MultiSelectOption } from '@helixui/core'
```

### Tags

`combobox`, `tags`, `chips`, `multi`

### Anatomy

```
[ chip × ][ chip × ][ chip × ]  type… ▾
                                  └─ popover listbox ─┐
                                     • option 1       │
                                     • option 2       │
                                     ▼ load more
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, hugs height + chip rows`
- stackable: `false`
- fullBleed: `false`

### Visual

A combobox-style input with selected values rendered as inline removable tags. Typing filters the popover listbox below; selecting an option adds another chip.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Visible label. |
| `description` | `ReactNode` | — | Helper text. |
| `errorMessage` | `string \| (v: ValidationResult) => string` | — | Error text. |
| `placeholder` | `string` | `Add…` | Combobox input placeholder. |
| `selectedKeys` | `Selection` | — | Controlled selected ids. |
| `defaultSelectedKeys` | `Iterable<string \| number>` | — | Uncontrolled initial selection. |
| `onSelectionChange` | `(keys: Selection) => void` | — | Selection change handler. |

### Slots

- children — MultiSelectOption components

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.subtle`, `color.bg.action.brand.default`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.on.brand`, `color.text.action.danger`, `color.border.default`, `color.border.focus`, `radius.md`, `radius.sm`, `radius.full`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`, `font.size.xs`, `font.weight.medium`, `shadow.md`

### Accessibility

Notes:
- Composes react-aria-components ComboBox + TagGroup. ComboBox handles input typing & list selection; TagGroup handles selected-tag removal with Backspace and Delete.
- Provide `aria-label` on the container if no `label` is shown.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Select` | `alternative` | Use Select for single-value. |

### Prompt examples

**pick multiple tags** — _"multi-select for tags"_

```tsx
<MultiSelect value={tags} onChange={setTags}>
  <MultiSelectOption value="design">Design</MultiSelectOption>
  <MultiSelectOption value="ai">AI</MultiSelectOption>
</MultiSelect>
```

### Related

- Select

---

<a id="number-field"></a>

# NumberField

A numeric input with locale-aware parsing, optional +/- steppers, min/max/step, and validation.

> category: form · status: stable · since: 0.2.0

```ts
import { NumberField } from '@helixui/core'
```

### Tags

`number`, `input`, `stepper`, `numeric`

### Anatomy

```
Label
[          1,234 ][−][+]
Description / error
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, hugs height`
- stackable: `true`
- fullBleed: `false`

### Visual

A text input formatted as a number with optional +/- steppers on the right. Locale-aware parsing (commas vs dots) and validation against `min`/`max`/`step`.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Visible label. |
| `description` | `ReactNode` | — | Helper text. |
| `errorMessage` | `string \| (v: ValidationResult) => string` | — | Error text. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Control height. |
| `steppers` | `boolean` | `true` | Show +/- buttons inside the group. |
| `minValue` | `number` | — | Minimum allowed value. |
| `maxValue` | `number` | — | Maximum allowed value. |
| `step` | `number` | `1` | Step amount per +/- click. |
| `formatOptions` | `Intl.NumberFormatOptions` | — | Locale formatting (currency, percent, units). |

### Tokens

`color.bg.surface.default`, `color.bg.surface.muted`, `color.bg.action.neutral.default`, `color.border.default`, `color.border.focus`, `color.border.danger`, `color.text.primary`, `color.text.secondary`, `color.text.action.danger`, `radius.md`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.weight.medium`

### Accessibility

Notes:
- Built on react-aria-components NumberField — locale-aware parsing/formatting and ARIA spinbutton semantics.
- Pass `formatOptions` (Intl.NumberFormatOptions) for currency, percent, or unit-formatted inputs.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Field` | `wraps` | NumberField has built-in label/description/error like other RAC inputs. |
| `Form` | `parent` | Submitted as part of a Form. |
| `TextInput` | `sibling` |  |
| `Slider` | `sibling` |  |

### Prompt examples

**quantity input** — _"number input with min 0 max 99"_

```tsx
<NumberField label="Qty" minValue={0} maxValue={99} value={qty} onChange={setQty} />
```

### Related

- TextInput
- Slider

---

<a id="numeric-keypad"></a>

# NumericKeypad

An iOS/Android-style 3×4 numeric keypad with optional letter sub-labels (ABC, DEF, …). Use for PIN entry, banking apps, or custom input flows where the system keyboard is unwanted.

> category: form · status: stable · since: 0.5.0

```ts
import { NumericKeypad } from '@helixui/core'
```

### Tags

`mobile`, `keypad`, `pin`, `numeric`

### Anatomy

```
1   2   3
4   5   6
7   8   9
        0   ⌫
```

### Layout

- display: `grid`
- width: `fill`
- height: `content`
- intrinsicSize: `3×4 grid; tile size scales with width`
- stackable: `false`
- fullBleed: `false`

### Visual

A 3×4 grid of large round buttons (44px+) with optional letter sub-labels (ABC, DEF, …) for phone-style entry. Backspace key in the bottom-right.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `onDigit` | `(digit: string) => void` | — | Called for each digit press 0–9. |
| `onBackspace` | `() => void` | — | Called when backspace is tapped (when no `submitLabel`). |
| `onSubmit` | `() => void` | — | Called when the submit key is tapped (when `submitLabel` is set). |
| `bottomLeft` | `ReactNode` | — | Custom node for the bottom-left cell (default empty). |
| `bottomRight` | `ReactNode` | — | Custom node for the bottom-right cell (default backspace). |
| `submitLabel` | `ReactNode` | — | When set, renders a brand-colored submit button at bottom-right and triggers `onSubmit` instead of backspace. |
| `size` | `'md' \| 'lg'` | `md` | Key height — 56 / 72 px. |

### Tokens

`color.bg.action.neutral.default`, `color.bg.action.neutral.hover`, `color.bg.action.neutral.active`, `color.bg.action.brand.default`, `color.bg.action.brand.hover`, `color.text.primary`, `color.text.on.brand`, `color.text.muted`, `color.border.focus`, `radius.full`, `space.2`, `space.3`, `font.family.sans`, `font.size.2xl`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Notes:
- Each key is a `<button>` with an `aria-label` ("Digit 1"). The wrapper is `role="group"`.
- For currency inputs, set `bottomLeft` to a decimal `.` button.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `PinInput` | `sibling` | Often paired with PinInput for mobile PIN entry. |

### Prompt examples

**mobile PIN entry** — _"on-screen numeric keypad"_

```tsx
<NumericKeypad onPress={handleKey} />
```

### Related

- PinInput

---

<a id="pin-input"></a>

# PinInput

A row of single-character cells for PIN / OTP entry. Auto-advances on type, supports paste-to-fill, backspace-to-previous, arrow navigation, and SMS one-time-code autofill.

> category: form · status: stable · since: 0.5.0

```ts
import { PinInput } from '@helixui/core'
```

### Tags

`otp`, `pin`, `verification`, `sms`

### Anatomy

```
[ _ ][ _ ][ _ ][ _ ][ _ ][ _ ]   ← 6-digit code
```

### Layout

- display: `inline-flex`
- width: `content`
- height: `content`
- intrinsicSize: `~44-56px tall, hugs N cells`
- stackable: `false`
- fullBleed: `false`

### Visual

A row of single-character cells with auto-advance, paste-to-fill, backspace-to-previous, and SMS one-time-code autofill on iOS/Android.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `length` | `number` | `6` | Number of cells. |
| `value` | `string` | — | Controlled value. |
| `defaultValue` | `string` | — | Uncontrolled initial. |
| `onChange` | `(value: string) => void` | — | Change handler. |
| `onComplete` | `(value: string) => void` | — | Called once when the last cell is filled. |
| `pattern` | `'digits' \| 'alphanumeric'` | `digits` | Allowed character set. |
| `mask` | `boolean` | `false` | Mask the value (for PINs). |
| `isInvalid` | `boolean` | `false` | Invalid styling. |
| `isDisabled` | `boolean` | `false` | Disable all cells. |
| `label` | `ReactNode` | — | Label above the cells. |
| `description` | `ReactNode` | — | Helper text. |
| `errorMessage` | `ReactNode` | — | Error text. Implies `isInvalid`. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Cell size. |
| `autoFocus` | `boolean` | `false` | Focus the first cell on mount. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.muted`, `color.bg.action.brand.default`, `color.border.default`, `color.border.focus`, `color.border.danger`, `color.text.primary`, `color.text.secondary`, `color.text.action.danger`, `radius.md`, `space.2`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.size.xl`, `font.size.2xl`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Notes:
- First cell has `autocomplete="one-time-code"` so iOS / Android can offer SMS code autofill.
- `inputMode="numeric"` on digit-only mode brings up the numeric keypad on mobile.
- Error message has `role="alert"`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `NumericKeypad` | `sibling` | Pair on mobile when system keyboard is undesired. |
| `Field` | `wraps` | Wrap with Field for label/error. |
| `TextInput` | `sibling` |  |
| `Stepper` | `sibling` |  |

### Prompt examples

**verify SMS code** — _"6-digit OTP input"_

```tsx
<PinInput length={6} value={code} onChange={setCode} />
```

### Related

- TextInput
- NumericKeypad
- Stepper

---

<a id="radio-card"></a>

# RadioCard

A radio option styled as a card. Use inside a RadioGroup when each option needs more space (icon, title, description).

> category: form · status: stable · since: 0.1.0

```ts
import { RadioCard } from '@helixui/core'
```

### Tags

`radio`, `card`, `option`, `selectable`

### Anatomy

```
┌─ ◉ Title ──────────┐
│   description       │
│   [icon]            │
└─────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `card-sized; rows grow with content`
- stackable: `true`
- fullBleed: `false`

### Visual

A Card-shaped radio option. Selected state highlights with a brand border + tinted background; the radio dot is in the top-left or top-right per variant.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | — | Required. The value submitted when this option is selected. |
| `title` | `ReactNode` | — | Headline of the card. |
| `description` | `ReactNode` | — | Supporting text below the title. |
| `icon` | `ReactNode` | — | Optional leading icon. |
| `isDisabled` | `boolean` | `false` | Disables this option. |

### Slots

- children — additional content

### Tokens

`color.bg.surface.default`, `color.bg.action.brand.subtle`, `color.bg.action.brand.default`, `color.border.default`, `color.border.strong`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `color.text.action.brand`, `radius.md`, `space.1`, `space.3`, `space.4`, `font.family.sans`, `font.size.md`, `font.size.sm`, `font.weight.semibold`

### Accessibility

Role: `radio`

Keyboard:
- `ArrowDown` — Move to next option in group.
- `ArrowUp` — Move to previous option in group.
- `Space` — Selects the focused card.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `RadioGroup` | `parent` | Use inside a RadioGroup. |

### Prompt examples

**plan picker** — _"three plan radio cards"_

```tsx
<RadioGroup value={plan} onChange={setPlan}>
  <RadioCard value="free" title="Free" description="$0/mo" />
  <RadioCard value="pro" title="Pro" description="$12/mo" />
  <RadioCard value="team" title="Team" description="$24/mo" />
</RadioGroup>
```

### Related

- RadioGroup

---

<a id="radio-group"></a>

# RadioGroup

A list of mutually exclusive options. Use Radio components as children.

> category: form · status: stable · since: 0.1.0

```ts
import { RadioGroup, Radio } from '@helixui/core'
```

### Tags

`radio`, `choice`, `exclusive`

### Anatomy

```
( ◉ ) Option A
( ◯ ) Option B
( ◯ ) Option C
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `vertical stack of options`
- stackable: `true`
- fullBleed: `false`

### Visual

A vertical or horizontal group of radio buttons. Selected radio fills with brand color; label sits to the right.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Group label. |
| `description` | `ReactNode` | — | Helper text. |
| `errorMessage` | `string \| (v: ValidationResult) => string` | — | Error text. |
| `orientation` | `'vertical' \| 'horizontal'` | `vertical` | Layout. |
| `value` | `string` | — | Controlled selected value. |
| `defaultValue` | `string` | — | Uncontrolled initial value. |
| `isRequired` | `boolean` | `false` | Required for validation. |
| `isDisabled` | `boolean` | `false` | Disables all radios. |
| `onChange` | `(value: string) => void` | — | Change handler. |

### Slots

- children — Radio components

### Tokens

`color.bg.surface.default`, `color.bg.action.brand.default`, `color.border.strong`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `color.text.action.danger`, `space.2`, `space.4`, `font.family.sans`, `font.size.sm`, `font.weight.medium`

### Accessibility

Role: `radiogroup`

Keyboard:
- `ArrowDown` — Move to next radio.
- `ArrowUp` — Move to previous radio.
- `Space` — Selects focused radio.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Radio` | `child` | Default radio child. |
| `RadioCard` | `child` | Card-shaped option. |
| `Field` | `wraps` | RadioGroup has built-in label/description. |
| `Checkbox` | `sibling` |  |

### Prompt examples

**simple choice** — _"choose A / B / C"_

```tsx
<RadioGroup label="Choose one" value={v} onChange={setV}>
  <Radio value="a">A</Radio>
  <Radio value="b">B</Radio>
  <Radio value="c">C</Radio>
</RadioGroup>
```

### Related

- RadioCard
- Checkbox

---

<a id="rating"></a>

# Rating

A star rating control. Interactive by default — click or tap to set; supports half-star precision and a read-only display mode.

> category: form · status: stable · since: 0.5.0

```ts
import { Rating } from '@helixui/core'
```

### Tags

`stars`, `rating`, `review`

### Anatomy

```
★ ★ ★ ★ ☆   4 of 5
```

### Layout

- display: `inline-flex`
- width: `content`
- height: `content`
- intrinsicSize: `hugs N stars`
- stackable: `true`
- fullBleed: `false`

### Visual

A row of star glyphs filled to the current value. Half-star precision when enabled. Read-only mode disables interaction and lowers contrast.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number` | — | Controlled value 0..max. |
| `defaultValue` | `number` | `0` | Uncontrolled initial. |
| `max` | `number` | `5` | Total stars. |
| `step` | `0.5 \| 1` | `1` | Increments. `0.5` enables half-star precision. |
| `onChange` | `(v) => void` | — | Change handler. |
| `readOnly` | `boolean` | `false` | Display mode — no hover, no click. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Star size. |
| `label` | `string` | `Rating` | `aria-label`. |
| `allowClear` | `boolean` | `false` | Clicking the current value clears back to 0. |

### Tokens

`color.bg.action.warning.default`, `color.border.focus`

### Accessibility

Role: `slider`

Notes:
- When interactive: `role="slider"`, `aria-valuenow/min/max` reflect the value. When `readOnly`: `role="img"`.
- Each tap target is a `<button>` so it's keyboard-accessible.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Form` | `parent` | Inside a form when collecting reviews. |
| `Slider` | `sibling` |  |

### Prompt examples

**leave a review** — _"5-star rating with half precision"_

```tsx
<Rating value={value} onChange={setValue} allowHalf />
```

**show product score** — _"read-only rating of 4.5"_

```tsx
<Rating value={4.5} readOnly />
```

### Related

- Slider

---

<a id="rich-text-editor"></a>

# RichTextEditor

WYSIWYG editor backed by TipTap (built on ProseMirror). Lazy-loads the engine and every extension; declared as optional peer dependencies. Ships a default toolbar but exposes an imperative handle for fully custom UI.

> category: form · status: stable · since: 0.7.0

```ts
import { RichTextEditor } from '@helixui/core'
```

### Tags

`wysiwyg`, `editor`, `tiptap`, `prosemirror`

### Anatomy

```
┌── toolbar (B I U • ¶ ) ──┐
├──────────────────────────┤
│  editable content area   │
│  …                       │
└──────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `fill`
- intrinsicSize: `fills available; toolbar pinned top`
- stackable: `false`
- fullBleed: `false`

### Visual

A WYSIWYG editor with a default toolbar (bold, italic, lists, links, code) and a content area. Lazy-loads TipTap and selected extensions. Imperative handle exposes ProseMirror APIs.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | `''` | HTML string for the current document. |
| `onChange` | `(html: string) => void` | `—` | Fires on every edit with the new HTML. |
| `onChangeText` | `(text: string) => void` | `—` | Plain-text snapshot, fired alongside onChange. |
| `onChangeJSON` | `(json: unknown) => void` | `—` | TipTap JSON snapshot, fired alongside onChange. |
| `onSelectionChange` | `(state: RichTextSelectionState) => void` | `—` | Fires whenever the selection or active formats change. |
| `extensions` | `RichTextExtension[] \| 'all'` | `starter` | Built-in extensions to enable. Defaults to a starter preset; pass 'all' to enable everything. |
| `theme` | `'light' \| 'dark' \| 'auto'` | `auto` | `auto` follows `document.documentElement.dataset.theme`. |
| `readOnly` | `boolean` | `false` | Disable editing. |
| `autoFocus` | `boolean` | `false` | Focus the editor when it mounts. |
| `placeholder` | `string` | `Write something…` | Empty-state hint. Requires the `placeholder` extension (on by default). |
| `toolbar` | `boolean` | `true` | Show the built-in toolbar. |
| `renderToolbar` | `(handle, state) => ReactNode` | `—` | Render a custom toolbar instead of the default. Receives the imperative handle and current selection state. |
| `height` | `number \| string` | `360` | Editing surface height. Numbers are treated as px. |
| `editorRef` | `Ref<RichTextEditorHandle>` | `—` | Imperative handle for advanced control. |
| `tiptapExtensions` | `unknown[]` | `[]` | Extra TipTap extensions appended after the built-in ones. |
| `onMount` | `(handle: RichTextEditorHandle) => void` | `—` | Fires once mounted, with the imperative handle. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.subtle`, `color.bg.surface.inverse`, `color.border.default`, `color.border.focus`, `color.text.primary`, `color.text.muted`, `color.text.action.brand`, `color.text.action.danger`, `color.bg.action.brand.default`, `color.bg.action.danger.subtle`, `radius.md`, `radius.sm`, `font.family.sans`, `font.family.mono`, `motion.duration.fast`, `motion.easing.standard`

### Accessibility

Notes:
- TipTap exposes a `role='textbox' aria-multiline='true'` surface.
- Toolbar buttons set `aria-pressed` for active states.
- Container shows a `:focus-within` ring matching helixui's other inputs.
- Respects `prefers-reduced-motion` via the global motion stylesheet.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `CodeEditor` | `alternative` | CodeEditor for code; RichTextEditor for prose. |
| `Form` | `parent` | Treat as a controlled form input. |
| `TextInput` | `sibling` |  |
| `Textarea` | `sibling` |  |

### Prompt examples

**blog post editor** — _"WYSIWYG editor for a post body"_

```tsx
<RichTextEditor value={body} onChange={setBody} placeholder="Write…" />
```

### Related

- TextInput
- Textarea
- CodeEditor

---

<a id="segmented-control"></a>

# SegmentedControl

A grouped row of toggle buttons for picking between a small number of mutually exclusive views.

> category: form · status: stable · since: 0.1.0

```ts
import { SegmentedControl, Segment } from '@helixui/core'
```

### Tags

`toggle-group`, `tabs`, `choice`

### Anatomy

```
[ Day ][ Week ][ Month ]   ← exclusive choice (one filled)
```

### Layout

- display: `inline-flex`
- width: `content`
- height: `content`
- intrinsicSize: `pill row, ~28-36px tall`
- stackable: `false`
- fullBleed: `false`

### Visual

A pill-shaped row of equal-width segments with a sliding active background. Active segment uses elevated surface; inactive use subtle background.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `'sm' \| 'md'` | `md` | Control height. |
| `selectionMode` | `'single' \| 'multiple'` | `single` | Selection model. |
| `disallowEmptySelection` | `boolean` | `true` | Prevent unselecting the last item in single mode. |
| `selectedKeys` | `Set<string>` | — | Controlled selection. |
| `defaultSelectedKeys` | `Iterable<string>` | — | Uncontrolled initial selection. |
| `onSelectionChange` | `(keys: Set<string>) => void` | — | Selection change handler. |

### Slots

- children — Segment components

### Tokens

`color.bg.action.neutral.default`, `color.bg.surface.default`, `color.text.primary`, `color.text.secondary`, `color.border.focus`, `radius.md`, `space.3`, `font.family.sans`, `font.size.xs`, `font.size.sm`, `font.weight.medium`, `shadow.sm`

### Accessibility

Role: `radiogroup`

Keyboard:
- `ArrowLeft` — Move focus left.
- `ArrowRight` — Move focus right.
- `Space` — Selects focused segment.

Notes:
- For 5+ options, prefer Tabs or a Select.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Tabs` | `alternative` | Tabs for in-page section switching; SegmentedControl for compact view modes. |

### Prompt examples

**view mode picker** — _"segmented control Day / Week / Month"_

```tsx
<SegmentedControl value={mode} onChange={setMode}>
  <Segment value="day">Day</Segment>
  <Segment value="week">Week</Segment>
  <Segment value="month">Month</Segment>
</SegmentedControl>
```

### Related

- Tabs

---

<a id="select"></a>

# Select

A single-value picker rendered as a popover listbox.

> category: form · status: stable · since: 0.1.0

```ts
import { Select, Option } from '@helixui/core'
```

### Tags

`picker`, `dropdown`, `single-value`

### Anatomy

```
[ Selected value         ▾ ]
   ╭──── popover ───╮
   │ • Option A     │
   │ • Option B  ✓  │
   │ • Option C     │
   ╰────────────────╯
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, hugs height`
- stackable: `false`
- fullBleed: `false`

### Visual

A trigger button styled like a TextInput with a trailing chevron. On open, a popover listbox appears anchored to the trigger; selected option is checkmarked.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Visible label. |
| `description` | `ReactNode` | — | Helper text. |
| `errorMessage` | `string \| (v: ValidationResult) => string` | — | Error text. |
| `placeholder` | `string` | `Select…` | Shown when nothing is selected. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Trigger height. |
| `selectedKey` | `Key \| null` | — | Controlled selected option. |
| `defaultSelectedKey` | `Key` | — | Uncontrolled initial. |
| `onSelectionChange` | `(key: Key) => void` | — | Selection change handler. |

### Slots

- children — Option components

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.subtle`, `color.border.default`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.action.danger`, `radius.md`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.weight.medium`, `shadow.md`

### Accessibility

Role: `combobox`

Keyboard:
- `ArrowDown` — Open / move down.
- `Enter` — Select highlighted option.
- `Escape` — Close.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Field` | `wraps` | Built-in label/description/error. |
| `Form` | `parent` | Submitted as part of a Form. |
| `MultiSelect` | `alternative` | MultiSelect for multiple values. |

### Prompt examples

**country picker** — _"select with three options"_

```tsx
<Select label="Country" value={country} onChange={setCountry}>
  <Option value="us">United States</Option>
  <Option value="kr">Korea</Option>
  <Option value="jp">Japan</Option>
</Select>
```

### Related

- MultiSelect

---

<a id="slider"></a>

# Slider

A horizontal slider for a single value or a range. Pass an array `value`/`defaultValue` to get a range slider with two thumbs.

> category: form · status: stable · since: 0.2.0

```ts
import { Slider } from '@helixui/core'
```

### Tags

`range`, `value`, `horizontal`

### Anatomy

```
─────────●─────────────────  single thumb
─────●═══════════●─────────  range (two thumbs)
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, ~32px tall`
- stackable: `true`
- fullBleed: `false`

### Visual

A horizontal track with a brand-filled portion under the thumb(s). Single thumb for one value; two thumbs for a range. Optional ticks and labels.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Visible label. |
| `showValue` | `boolean` | `true` | Render the formatted current value to the right of the label. |
| `value` | `number \| number[]` | — | Controlled value(s). |
| `defaultValue` | `number \| number[]` | — | Uncontrolled initial value(s). |
| `minValue` | `number` | `0` | Min. |
| `maxValue` | `number` | `100` | Max. |
| `step` | `number` | `1` | Step. |
| `formatOptions` | `Intl.NumberFormatOptions` | — | Format the rendered output (percent, currency, units). |
| `onChange` | `(value) => void` | — | Change handler. |

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.border.focus`, `radius.full`, `space.2`, `font.family.sans`, `font.size.sm`, `font.weight.medium`, `shadow.sm`

### Accessibility

Keyboard:
- `ArrowKeys` — Step value.
- `PageUp` — Big step up.
- `PageDown` — Big step down.
- `Home` — Min.
- `End` — Max.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Form` | `parent` | Submitted as part of a Form. |
| `Field` | `wraps` | Has built-in label/description. |
| `NumberField` | `sibling` |  |

### Prompt examples

**volume control** — _"slider 0 to 100"_

```tsx
<Slider label="Volume" value={vol} onChange={setVol} minValue={0} maxValue={100} />
```

**price range** — _"range slider for min/max price"_

```tsx
<Slider label="Price" value={range} onChange={setRange} minValue={0} maxValue={500} />
```

### Related

- NumberField

---

<a id="switch"></a>

# Switch

A two-state toggle. Use when a setting takes effect immediately; use Checkbox in forms.

> category: form · status: stable · since: 0.1.0

```ts
import { Switch } from '@helixui/core'
```

### Tags

`toggle`, `on-off`, `setting`

### Anatomy

```
(○──)   off
(──●)   on (filled brand)
```

### Layout

- display: `inline-flex`
- width: `content`
- height: `content`
- intrinsicSize: `~32×20 toggle + label`
- stackable: `true`
- fullBleed: `false`

### Visual

A pill-shaped track with a sliding circular knob. Off uses neutral track; on uses brand-filled track. Animates the knob with a soft transition.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `isSelected` | `boolean` | `false` | Controlled state. |
| `defaultSelected` | `boolean` | `false` | Uncontrolled initial state. |
| `isDisabled` | `boolean` | `false` | Disables interaction. |
| `onChange` | `(isSelected: boolean) => void` | — | Change handler. |
| `...rest` | `SwitchProps from react-aria-components` | — | All forwarded. |

### Slots

- children — visible label text

### Tokens

`color.bg.action.neutral.active`, `color.bg.action.brand.default`, `color.text.primary`, `color.border.focus`, `color.white`, `radius.full`, `space.2`, `shadow.sm`, `font.family.sans`, `font.size.sm`

### Accessibility

Role: `switch`

Keyboard:
- `Space` — Toggles the switch.
- `Enter` — Toggles the switch.

Notes:
- Use Switch for instant changes (mute audio, dark mode). Use Checkbox for opt-ins inside forms.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Field` | `wraps` | Wrap if you need separate label/description structure. |
| `Checkbox` | `alternative` | Checkbox for forms; Switch for instant settings. |

### Prompt examples

**instant setting toggle** — _"switch for "Enable notifications""_

```tsx
<Switch isSelected={on} onChange={setOn}>Enable notifications</Switch>
```

### Related

- Checkbox

---

<a id="text-input"></a>

# TextInput

A single-line text input with built-in label, description, error, and prefix/suffix slots.

> category: form · status: stable · since: 0.1.0

```ts
import { TextInput } from '@helixui/core'
```

### Tags

`input`, `text`, `single-line`

### Anatomy

```
Label
[ prefix | text input | suffix ]
Help / error
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, ~36-44px tall`
- stackable: `true`
- fullBleed: `false`

### Visual

A single-line input with built-in label, description, error, and prefix/suffix slots for icons or units.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Visible label rendered above the input. |
| `description` | `ReactNode` | — | Helper text below the input. |
| `errorMessage` | `string \| (v: ValidationResult) => string` | — | Error message below the input. Can be a function for built-in `validate` results. |
| `placeholder` | `string` | — | Placeholder text. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Control height. |
| `prefix` | `ReactNode` | — | Inline content before the input — icon or static label. |
| `suffix` | `ReactNode` | — | Inline content after the input. |
| `isRequired` | `boolean` | `false` | Marks the field required for validation. |
| `isInvalid` | `boolean` | `false` | Forces the invalid state. |
| `isDisabled` | `boolean` | `false` | Disables the input. |
| `...rest` | `TextFieldProps from react-aria-components` | — | Forwarded — value/defaultValue/onChange/onBlur/etc. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.muted`, `color.border.default`, `color.border.focus`, `color.border.danger`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.danger`, `radius.md`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.weight.medium`

### Accessibility

Notes:
- Built on react-aria-components TextField — keyboard, screen-reader, and validation are handled.
- Pass `label` instead of relying on `placeholder` for accessibility.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Form` | `parent` | Inside Form. |
| `InputGroup` | `parent` | Compose with Buttons via InputGroup. |
| `NumberField` | `alternative` | NumberField for numbers. |
| `Textarea` | `alternative` | Textarea for multi-line. |
| `Field` | `sibling` |  |

### Prompt examples

**simple text field** — _"email input with placeholder"_

```tsx
<TextInput label="Email" placeholder="you@example.com" value={email} onChange={setEmail} />
```

**with leading icon** — _"search input with magnifying glass prefix"_

```tsx
<TextInput label="Search" prefix={<SearchIcon />} value={q} onChange={setQ} />
```

### Related

- Textarea
- InputGroup
- Field

---

<a id="textarea"></a>

# Textarea

A multi-line text input with optional label, description, and error.

> category: form · status: stable · since: 0.1.0

```ts
import { Textarea } from '@helixui/core'
```

### Tags

`multi-line`, `input`, `text`

### Anatomy

```
Label
┌──────────────────────────┐
│                          │
│  multi-line input        │
│                          │
└──────────────────────────┘
Help / error
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, default 4 rows`
- stackable: `true`
- fullBleed: `false`

### Visual

A multi-line text input wrapped with built-in label, description, and error message. Resizable vertically by default.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Visible label. |
| `description` | `ReactNode` | — | Helper text. |
| `errorMessage` | `string \| (v: ValidationResult) => string` | — | Error message. |
| `placeholder` | `string` | — | Placeholder. |
| `rows` | `number` | `4` | Initial visible rows. |
| `resize` | `'none' \| 'vertical' \| 'horizontal' \| 'both'` | `vertical` | User resize affordance. |
| `...rest` | `TextFieldProps` | — | Forwarded to react-aria's TextField. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.muted`, `color.border.default`, `color.border.focus`, `color.border.danger`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.danger`, `radius.md`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.weight.medium`, `font.lineHeight.normal`

### Accessibility

Notes:
- Built on react-aria-components TextField.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Form` | `parent` | Inside Form. |
| `TextInput` | `alternative` | TextInput for single-line. |
| `RichTextEditor` | `alternative` | RichTextEditor for formatted content. |
| `Field` | `sibling` |  |

### Prompt examples

**comment box** — _"multi-line comment input"_

```tsx
<Textarea label="Comment" rows={4} value={c} onChange={setC} />
```

### Related

- TextInput
- Field

---

# data

<a id="chart"></a>

# Chart

Unified chart surface backed by either Chart.js or Recharts. Both engines accept the same `<ChartData>` shape (labels + datasets); the adapter translates to engine-native formats internally. Both engines lazy-load and are declared as optional peer dependencies — install only what you use.

> category: data · status: stable · since: 0.7.0

```ts
import { Chart } from '@helixui/core'
```

### Tags

`data-viz`, `graph`, `plot`, `analytics`

### Anatomy

```
┌──────────────────────────────┐
│  Title                        │
│  ▁▂▃▅▆▇█▇▆▅▃▂▁  legend       │
│  └──────────────axis────────  │
│  Caption                      │
└──────────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `fixed:320px`
- intrinsicSize: `fills available width, default 320px tall`
- stackable: `true`
- fullBleed: `false`

### Visual

A surface with optional title, legend, and caption. The plot area uses brand / success / warning / danger token colors for series. Tooltips appear on hover/touch; axis labels use muted text. Animations respect prefers-reduced-motion.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `type` | `'line' \| 'area' \| 'bar' \| 'stackedBar' \| 'horizontalBar' \| 'pie' \| 'doughnut' \| 'radar' \| 'scatter'` | `—` | Chart type. Same set across both engines. |
| `data` | `ChartData` | `—` | Unified `{ labels, datasets }` shape. Adapters translate it. |
| `engine` | `'chartjs' \| 'recharts'` | `chartjs` | Which engine to use. Chart.js draws to canvas; Recharts to SVG. |
| `theme` | `'light' \| 'dark' \| 'auto'` | `auto` | `auto` follows `document.documentElement.dataset.theme`. |
| `legend` | `boolean` | `true` | Show / hide the legend. |
| `grid` | `boolean` | `true` | Show / hide axis grid lines. |
| `tooltip` | `boolean` | `true` | Show / hide tooltips on hover/touch. |
| `animate` | `boolean` | `auto` | Animate on mount and on data change. Defaults follow `prefers-reduced-motion`. |
| `hideAxes` | `boolean` | `false` | Useful for compact widgets — drops both x and y tick labels. |
| `smooth` | `boolean` | `true` | Smoothed curves for line/area. |
| `compactNumbers` | `boolean` | `true` | Pretty-format the y-axis as `1.2K` / `3.4M`. |
| `cutout` | `number` | `0.6` | Doughnut cutout (0–1). Ignored for non-doughnut types. |
| `height` | `number \| string` | `320` | Numbers are treated as px. |
| `title` | `ReactNode` | `—` | Optional title rendered above the chart. |
| `caption` | `ReactNode` | `—` | Optional caption rendered below the chart. |
| `chartjsOptions` | `Record<string, unknown>` | `{}` | Spread last into Chart.js options. Escape hatch. |
| `rechartsOptions` | `Record<string, unknown>` | `{}` | Reserved for the recharts adapter. |
| `onMount` | `(info: { engine, instance }) => void` | `—` | Fires once mounted. Receives the underlying engine instance. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.subtle`, `color.bg.action.brand.default`, `color.bg.action.success.default`, `color.bg.action.warning.default`, `color.bg.action.danger.default`, `color.bg.action.danger.subtle`, `color.border.default`, `color.text.primary`, `color.text.muted`, `color.text.action.danger`, `radius.md`, `font.family.sans`, `motion.duration.fast`, `motion.easing.standard`

### Accessibility

Notes:
- Canvas-based engines (Chart.js) get a `role='img'` on the canvas with the chart title as `aria-label`.
- Tooltips honor pointer + touch.
- Animations turn off when `prefers-reduced-motion: reduce` unless `animate` is explicitly set.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Card` | `parent` | Often wrapped in a Card on dashboards. |
| `StatCard` | `sibling` | KPI tiles next to a chart. |
| `Sparkline` | `alternative` | Use Sparkline for tiny inline trends. |

### Prompt examples

**monthly revenue line chart** — _"show a line chart of revenue"_

```tsx
<Chart type="line" data={{ labels, datasets: [{ label: 'Revenue', data }] }} />
```

**bar chart with engine override** — _"use recharts for a bar chart"_

```tsx
<Chart engine="recharts" type="bar" data={data} />
```

### Related

- Sparkline
- StatCard

---

<a id="code-block"></a>

# CodeBlock

A fenced code display with language label and copy button. Built-in tokenizer for ts / js / py / json / bash; bring your own highlighter for others.

> category: data · status: stable · since: 0.3.0

```ts
import { CodeBlock } from '@helixui/core'
```

### Tags

`code`, `mono`, `snippet`, `copy`

### Anatomy

```
┌─ tsx ─────────────────────────── [📋] ┐
│  const x = 1;                         │
│  console.log(x);                       │
└────────────────────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, scrolls horizontally on overflow`
- stackable: `true`
- fullBleed: `false`

### Visual

A surface with a small language label in the top-left, a copy button in the top-right, and monospace content (font.family.mono) on a subtle surface (surface.subtle). Tokenized highlighting for ts/js/py/json/bash; falls back to plain text otherwise.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `code` | `string` | — | Source text. Required. |
| `language` | `string` | `ts` | Language tag for highlighter and label. |
| `filename` | `string` | — | Optional filename — replaces the language label. |
| `noCopy` | `boolean` | `false` | Hide the copy button. |
| `highlight` | `(code, language?) => string` | — | Override the built-in highlighter. Returns HTML string. |

### Tokens

`color.bg.surface.inverse`, `color.text.inverse`, `color.border.default`, `radius.md`, `radius.sm`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.family.mono`, `font.size.xs`, `font.size.sm`, `font.weight.medium`

### Accessibility

Notes:
- Copy button announces 'Copied' via its `aria-label` after a successful copy.
- Built-in highlighter is regex-based (small) — for richer highlighting pass `highlight` (e.g. wrap Prism / Shiki).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `CodeEditor` | `alternative` | CodeBlock is read-only display; CodeEditor is editable. |
| `Card` | `parent` | Often inside a Card or doc body. |
| `ChatMessage` | `sibling` |  |

### Prompt examples

**show a tsx snippet** — _"render a code block with copy button"_

```tsx
<CodeBlock language="tsx">{`const x = 1;`}</CodeBlock>
```

### Related

- ChatMessage

---

<a id="data-table"></a>

# DataTable

A full-featured table primitive — sortable, filterable, selectable, paginated. Works for read-only display and for selection-driven workflows. Zero external dependencies.

> category: data · status: stable · since: 0.1.0

```ts
import { DataTable, type ColumnDef } from '@helixui/core'
```

### Tags

`table`, `datagrid`, `list`, `sort`, `filter`, `pagination`, `selection`, `admin`

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `data` | `readonly T[]` | `required` | The rows to display. Order is preserved unless sorting is active. |
| `columns` | `readonly ColumnDef<T>[]` | `required` | Column definitions. Each column has an id, header, accessor, and optional sort/filter/cell renderer. |
| `getRowId` | `(row: T, index: number) => string` | `defaultGetRowId` | Stable row identifier. Defaults to `row.id` if present, otherwise the row index. |
| `pageSize` | `number` | `undefined` | Enables client-side pagination. Renders all rows if absent. |
| `selectable` | `boolean` | `false` | Show the row-selection checkbox column. |
| `onSelectionChange` | `(ids: Set<string>) => void` | `undefined` | Fires whenever the selection changes. |
| `defaultSelection` | `Iterable<string>` | `undefined` | Initial selection (uncontrolled). |
| `selection` | `Set<string>` | `undefined` | Controlled selection. Pair with `onSelectionChange`. |
| `defaultSort` | `{ id: string; direction: 'asc' \| 'desc' }` | `undefined` | Initial sort (uncontrolled). |
| `sort` | `{ id: string; direction: 'asc' \| 'desc' } \| null` | `undefined` | Controlled sort. Pair with `onSortChange`. Use for server-side sorting. |
| `onSortChange` | `(sort: { id: string; direction: 'asc' \| 'desc' } \| null) => void` | `undefined` | Fires when the user changes the active sort. |
| `emptyState` | `ReactNode` | `undefined` | Rendered when no rows match. Defaults to a friendly "No results" message. |
| `loading` | `boolean` | `false` | When true, replaces the body with `loadingState`. |
| `loadingState` | `ReactNode` | `undefined` | Rendered while `loading` is true. Defaults to a "Loading…" line. |
| `striped` | `boolean` | `true` | Alternate row backgrounds. |
| `bordered` | `boolean` | `true` | Borders between rows. |
| `density` | `'compact' \| 'comfortable'` | `undefined` | Overrides the density gene for this table. Useful for admin views. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.subtle`, `color.bg.action.brand.subtle`, `color.bg.action.brand.default`, `color.border.subtle`, `color.border.action.brand`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `radius.sm`, `radius.md`, `spacing.1`, `spacing.2`, `spacing.3`, `spacing.4`, `spacing.8`, `font.size.xs`, `font.size.sm`, `font.weight.semibold`

### Accessibility

Role: `table`

Keyboard:
- `Tab` — Focus moves between sortable headers / filter inputs / checkboxes.
- `Space` — On a focused sort header — toggles asc → desc → off.
- `ArrowKeys` — Native browser scrolling inside the table region.

Notes:
- Sortable headers announce `aria-sort` (ascending / descending / none).
- Each row's checkbox has a contextual `aria-label`.
- The scrollable container is a focusable region with a visible focus ring.
- Caption announces the total row count and active sort.

### Related

- table

---

<a id="list"></a>

# List

A denser data list — feed, inbox, settings rows. Each item has media / primary / secondary / trailing slots.

> category: data · status: stable · since: 0.2.0

```ts
import { List } from '@helixui/core'
```

### Tags

`rows`, `feed`, `inbox`, `settings`

### Anatomy

```
[ media ]  Primary text                    [ trailing ]
           Secondary muted text
──────────────────────────────────────────────────────────
[ media ]  Primary…                              [ trailing ]
           Secondary…
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, rows hug content`
- stackable: `true`
- fullBleed: `false`

### Visual

A vertical list of rows, each with media (avatar/icon), primary + secondary text, and trailing content. Hairline dividers between rows. Hover surface (action.neutral.default at low alpha) on interactive rows.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `divided` | `boolean` | `false` | Render a 1px border between items. |
| `interactive` | `boolean` | `false` | Add hover/focus affordance — for clickable lists. |

### Slots

- List.Item — media, primary, secondary, trailing slots; optional href to render as `<a>`

### Tokens

`color.bg.action.neutral.default`, `color.text.primary`, `color.text.secondary`, `color.border.default`, `color.border.focus`, `radius.md`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.weight.medium`

### Accessibility

Notes:
- Renders `<ul><li>`. Items become `<a>` when `href` is provided, otherwise plain rows.
- For selectable lists with keyboard nav, prefer `Table` with selection or react-aria-components `GridList`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Avatar` | `child` | Common media slot. |
| `Badge` | `child` | Common trailing slot. |
| `Card` | `parent` | Often wrapped in a Card. |
| `EmptyState` | `alternative` | When list is empty, render EmptyState. |
| `Table` | `sibling` |  |

### Prompt examples

**inbox list** — _"list of conversations with avatar, name, last message, unread count"_

```tsx
<List>
  {threads.map(t => (
    <List.Item key={t.id}
      media={<Avatar fallback={t.initials} />}
      primary={t.name}
      secondary={t.preview}
      trailing={<Badge>{t.unread}</Badge>}
    />
  ))}
</List>
```

### Related

- Table

---

<a id="sparkline"></a>

# Sparkline

Tiny inline trend visualization rendered as pure SVG. No peer dependencies. Pairs with `<StatCard>` for KPI tiles, with `<List>` cells for per-row trends, or with `<Chart>` for full-size views.

> category: data · status: stable · since: 0.7.0

```ts
import { Sparkline } from '@helixui/core'
```

### Tags

`mini-chart`, `inline`, `svg`, `trend`

### Anatomy

```
▁▂▃▅▆▇█▇▆▅▃▂▁    ← inline tiny chart
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `~80×24px (tunable)`
- stackable: `true`
- fullBleed: `false`

### Visual

A pure-SVG mini line/area chart with no axes or labels. Renders quickly inline next to a number. Tone (success/danger) tints the line per direction.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `data` | `number[]` | `—` | Series of y-values. Indexes are the x positions. |
| `variant` | `'line' \| 'area' \| 'bar'` | `line` | Render mode. |
| `tone` | `'brand' \| 'success' \| 'warning' \| 'danger' \| 'neutral' \| 'auto' \| string` | `auto` | Color. `'auto'` picks success for upward, danger for downward, neutral for flat. Any CSS color is accepted. |
| `strokeWidth` | `number` | `1.5` | Stroke width for line / area. |
| `width` | `number` | `96` | Render width in px. |
| `height` | `number` | `28` | Render height in px. |
| `showLast` | `boolean` | `true` | Dot at the last point. Defaults true for line/area, false for bar. |
| `min` | `number` | `auto` | Force min y. Defaults auto-fit with 10% pad. |
| `max` | `number` | `auto` | Force max y. Defaults auto-fit with 10% pad. |
| `smooth` | `boolean` | `true` | Catmull-Rom smoothed curve for line/area. |
| `ariaLabel` | `string` | `—` | When set, the SVG gains `role='img'` and is announced. |

### Tokens

`color.bg.action.brand.default`, `color.bg.action.success.default`, `color.bg.action.warning.default`, `color.bg.action.danger.default`, `color.text.muted`, `radius.sm`

### Accessibility

Notes:
- Decorative by default — pass `ariaLabel` to surface a description.
- Renders deterministically without animation; safe under `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `StatCard` | `child` | Shown as the trend visualization in a StatCard. |
| `List` | `child` | Per-row trend in a list. |
| `Chart` | `alternative` | Use Chart for full-size data viz. |

### Prompt examples

**KPI trend line** — _"tiny green sparkline for revenue"_

```tsx
<Sparkline data={[1, 2, 3, 5, 4, 6, 8]} tone="success" />
```

### Related

- Chart
- StatCard

---

<a id="stat-card"></a>

# StatCard

A KPI display — label, big value, a delta vs previous period, and an optional description line.

> category: data · status: stable · since: 0.2.0

```ts
import { StatCard } from '@helixui/core'
```

### Tags

`kpi`, `metric`, `tile`, `dashboard`

### Anatomy

```
┌──────────────────────┐
│  Label               │
│  $12,840             │   ← big value
│  ▲ +12.4%            │   ← delta
│  vs last month       │   ← description
│  ▁▂▃▅▆▇█             │   ← optional Sparkline
└──────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills available width, ~120-160px tall`
- stackable: `true`
- fullBleed: `false`

### Visual

A Card-shaped KPI tile with a small label, a large numeric value (font.size.2xl+), a delta with directional arrow tinted by tone, and optional supporting description and Sparkline.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Metric name. |
| `value` | `ReactNode` | — | Big number — typically a string. Tabular-numerals are applied. |
| `description` | `ReactNode` | — | Small caption below the value. |
| `delta` | `string` | — | Signed delta string e.g. `+12.4%` or `-2`. Sign is parsed for color. |
| `trend` | `'up' \| 'down' \| 'flat'` | — | Override inferred trend. |
| `invertedTrend` | `boolean` | `false` | Lower is better (e.g. error rate). Flips up→bad, down→good. |

### Tokens

`color.bg.surface.default`, `color.border.default`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.success`, `color.text.action.danger`, `radius.lg`, `space.1`, `space.2`, `space.4`, `space.5`, `font.family.sans`, `font.size.xs`, `font.size.sm`, `font.size.3xl`, `font.weight.medium`, `font.weight.semibold`, `font.weight.bold`

### Accessibility

Notes:
- Label/value/description are plain text. Pair multiple StatCards in a Grid for a KPI row.
- When using as a link or button, wrap or render the appropriate role inside.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Sparkline` | `child` | Trend visualization at the bottom. |
| `Card` | `alternative` | StatCard is opinionated; Card is generic. |
| `Grid` | `parent` | Common in a dashboard Grid. |

### Prompt examples

**dashboard KPI** — _"revenue KPI with +12.4% delta"_

```tsx
<StatCard
  label="Revenue"
  value="$12,840"
  delta={{ value: '+12.4%', tone: 'success' }}
  description="vs last month"
/>
```

### Related

- Card

---

<a id="swipeable-list-item"></a>

# SwipeableListItem

A list row that reveals leading or trailing actions when the user swipes left or right. Pass the row content as `children`; pass actions for either edge.

> category: data · status: beta · since: 0.5.0

```ts
import { SwipeableListItem, type SwipeAction } from '@helixui/core'
```

### Tags

`mobile`, `gesture`, `swipe`, `row-actions`

### Anatomy

```
← (Archive) ─── [ row content ] ─── (Delete) →
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width; row hugs content height`
- stackable: `true`
- fullBleed: `false`

### Visual

A list row with hidden leading/trailing actions revealed by horizontal swipe. Snaps open or closed; release past threshold triggers the action.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `leadingActions` | `SwipeAction[]` | `[]` | Actions revealed by left-to-right swipe. |
| `trailingActions` | `SwipeAction[]` | `[]` | Actions revealed by right-to-left swipe. |
| `commitThreshold` | `number` | `120` | Pixel distance past which release commits the first action on that side. |
| `actionWidth` | `number` | `80` | Width (px) of one action button. |

### Slots

- children — the list row content

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.bg.action.danger.default`, `color.bg.action.success.default`, `color.bg.action.warning.default`, `color.text.primary`, `color.text.on.brand`, `color.text.on.danger`, `color.text.on.success`, `color.text.on.warning`, `font.family.sans`, `font.size.xs`, `font.weight.medium`

### Accessibility

Notes:
- Pointer-event-driven (works with mouse and touch). On keyboard-only flows, the swipe affordance is hidden — pair with a Menu / context affordance for keyboard parity.
- Snaps open to the first action when released past `actionWidth/2`; commits the first action when released past `commitThreshold`.
- For destructive actions, set `tone="danger"` AND require explicit confirmation (an extra prompt) — accidental swipes happen.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `List` | `parent` | Used as List items on mobile. |
| `ActionSheet` | `sibling` |  |
| `Menu` | `sibling` |  |

### Prompt examples

**swipe to archive or delete** — _"left action archive, right action delete"_

```tsx
<SwipeableListItem
  trailingActions={[{ id: 'del', label: 'Delete', tone: 'danger', onPress: del }]}
  leadingActions={[{ id: 'arc', label: 'Archive', onPress: archive }]}
>
  Row content
</SwipeableListItem>
```

### Related

- List
- ActionSheet
- Menu

---

<a id="table"></a>

# Table

An interactive data table with selection, sorting, keyboard navigation, and a screen-reader-friendly grid.

> category: data · status: stable · since: 0.1.0

```ts
import { Table, TableHeader, TableBody, Row, Column, Cell } from '@helixui/core'
```

### Tags

`grid`, `rows`, `columns`, `sortable`, `selectable`

### Anatomy

```
┌─ Header  Header  Header ─┐
├──────────────────────────┤
│  cell    cell    cell    │
│  cell    cell    cell    │
│  cell    cell    cell    │
└──────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, scrolls horizontally on overflow`
- stackable: `false`
- fullBleed: `false`

### Visual

A row × column grid with a sticky header, hairline row dividers, and zebra hover. Sortable columns show a chevron when active. Selectable rows show a leading checkbox column.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `selectionMode` | `'none' \| 'single' \| 'multiple'` | `none` | Row selection mode. |
| `selectionBehavior` | `'replace' \| 'toggle'` | `replace` | How rows are selected. |
| `sortDescriptor` | `SortDescriptor` | — | Controlled sort state. |
| `onSortChange` | `(d: SortDescriptor) => void` | — | Sort change handler. |

### Slots

- Table children — TableHeader + TableBody
- Column children — header label
- Cell children — cell content

### Tokens

`color.bg.surface.subtle`, `color.bg.action.brand.subtle`, `color.border.default`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.size.xs`, `font.weight.semibold`

### Accessibility

Role: `grid`

Keyboard:
- `ArrowKeys` — Move focus between cells.
- `Space` — Toggle row selection.
- `Cmd/Ctrl+A` — Select all (when `selectionMode=multiple`).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `FloatingBar` | `sibling` | Use over a Table when rows are selected. |
| `Pagination` | `sibling` | Below the Table. |
| `EmptyState` | `alternative` | When no rows. |

### Prompt examples

**sortable user table** — _"three-column table with sort and selection"_

```tsx
<Table selectionMode="multiple" onSortChange={setSort}>
  <TableHeader>
    <Column id="name" allowsSorting>Name</Column>
    <Column id="email">Email</Column>
    <Column id="role">Role</Column>
  </TableHeader>
  <TableBody>
    {rows.map(r => (
      <Row key={r.id}><Cell>{r.name}</Cell><Cell>{r.email}</Cell><Cell>{r.role}</Cell></Row>
    ))}
  </TableBody>
</Table>
```

### Related

- Pagination

---

# feedback

<a id="badge"></a>

# Badge

A small inline label for status, counts, or categories.

> category: feedback · status: stable · since: 0.1.0

```ts
import { Badge } from '@helixui/core'
```

### Tags

`label`, `count`, `status`, `pill`, `chip`

### Anatomy

```
( New )   ( 3 )   ( beta )   ← small pill of text
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `~16-22px tall, hugs text`
- stackable: `true`
- fullBleed: `false`

### Visual

A small pill (radius.full) with a tone-tinted background and matching foreground text. Compact font (font.size.xs) with semibold weight. Solid / soft / outline variants control emphasis. Often used inline next to a heading or appended to a list item.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `tone` | `'neutral' \| 'brand' \| 'danger' \| 'success' \| 'warning'` | `neutral` | Color intent. |
| `variant` | `'soft' \| 'solid' \| 'outline'` | `soft` | Visual treatment. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Badge size. `sm` for compact inline chips, `md` for section eyebrows / statuses, `lg` for prominent hero / featured-card headers (uppercase by default). |

### Tokens

`color.bg.action.brand.subtle`, `color.bg.action.brand.default`, `color.bg.action.danger.subtle`, `color.bg.action.danger.default`, `color.bg.action.success.subtle`, `color.bg.action.success.default`, `color.bg.action.warning.subtle`, `color.bg.action.warning.default`, `color.bg.action.neutral.default`, `color.bg.surface.inverse`, `color.text.action.brand`, `color.text.action.danger`, `color.text.action.success`, `color.text.action.warning`, `color.text.primary`, `color.text.inverse`, `color.text.on.brand`, `color.text.on.danger`, `color.text.on.success`, `color.text.on.warning`, `radius.full`, `space.1`, `space.2`, `space.3`

### Accessibility

Notes:
- Color alone is not enough — pair the tone with a clear text label.
- For dynamic counts, place the badge near content it relates to via `aria-describedby`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Sidebar` | `child` | Often appears as `Sidebar.Item.trailing`. |
| `List` | `child` | Common in trailing slot of a List row. |
| `Tabs` | `child` | Counts next to tab labels. |

### Prompt examples

**tag a feature as new** — _"a green New badge"_

```tsx
<Badge tone="success">New</Badge>
```

**unread count** — _"show "12" as a count badge"_

```tsx
<Badge tone="brand" variant="solid">12</Badge>
```

---

<a id="banner"></a>

# Banner

A persistent page-level alert. Stronger than Callout, less interruptive than Toast or Dialog.

> category: feedback · status: stable · since: 0.2.0

```ts
import { Banner } from '@helixui/core'
```

### Tags

`alert`, `page-level`, `persistent`, `announcement`

### Anatomy

```
┌─[icon]── Title — short description ───────── [Action] [×] ─┐
└────────────────────────────────────────────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `full-bleed at the top of a page or section`
- stackable: `false`
- fullBleed: `true`

### Visual

A full-bleed colored band at the top of a page or section. Tinted background per tone (info/success/warning/danger), a leading icon, message text, optional action button, and a dismiss × on the right.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `tone` | `'info' \| 'success' \| 'warning' \| 'danger' \| 'neutral'` | `info` | Color intent. |
| `title` | `ReactNode` | — | Bold headline. |
| `description` | `ReactNode` | — | Body text. |
| `icon` | `ReactNode` | — | Leading icon. |
| `actions` | `ReactNode` | — | Right-aligned actions. |
| `dismissible` | `boolean` | `false` | Show a close button. |
| `open` | `boolean` | — | Controlled visibility. When omitted, the close button manages internal state. |
| `onOpenChange` | `(open: boolean) => void` | — | Visibility change handler. |

### Slots

- children — additional content below description

### Tokens

`color.bg.action.brand.subtle`, `color.bg.action.brand.default`, `color.bg.action.success.subtle`, `color.bg.action.success.default`, `color.bg.action.warning.subtle`, `color.bg.action.warning.default`, `color.bg.action.danger.subtle`, `color.bg.action.danger.default`, `color.bg.surface.subtle`, `color.text.action.brand`, `color.text.action.success`, `color.text.action.warning`, `color.text.action.danger`, `color.text.primary`, `color.border.default`, `radius.md`, `radius.sm`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.weight.semibold`, `font.lineHeight.normal`

### Accessibility

Role: `status`

Notes:
- For non-interruptive page state. For critical errors that block the user, prefer Dialog.
- Close button has `aria-label="Dismiss"`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `PageHeader` | `sibling` | Renders above PageHeader at the top of a page. |
| `Callout` | `alternative` | Use Callout inline within content; Banner is page-level. |
| `Toast` | `alternative` | Toast for transient; Banner for persistent. |
| `Dialog` | `sibling` |  |

### Prompt examples

**announce a maintenance window** — _"page-wide maintenance notice"_

```tsx
<Banner tone="warning" title="Maintenance window" description="We'll be down 9–10pm UTC tonight." onDismiss={hide} />
```

**success after a long action** — _"banner saying changes published"_

```tsx
<Banner tone="success" title="Changes published." />
```

### Related

- Callout
- Toast
- Dialog

---

<a id="callout"></a>

# Callout

An inline message banner — info, success, warning, danger, or neutral.

> category: feedback · status: stable · since: 0.1.0

```ts
import { Callout } from '@helixui/core'
```

### Tags

`inline-alert`, `note`, `tip`, `in-content`

### Anatomy

```
┌─[i]── Heading ─────────────────────────────┐
│   Body copy explaining the situation.       │
└────────────────────────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `inline within a content column`
- stackable: `true`
- fullBleed: `false`

### Visual

A rounded surface (radius.md) with a tone-tinted background, leading icon, optional title, and body. Subtler than Banner — designed to live inside content, not float at page top.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `tone` | `'info' \| 'success' \| 'warning' \| 'danger' \| 'neutral'` | `info` | Color intent. |
| `title` | `ReactNode` | — | Bold headline above the body. |
| `icon` | `ReactNode` | — | Optional leading icon. Provided by the caller; helixui has no icon set. |

### Slots

- children — the body content

### Tokens

`color.bg.action.brand.subtle`, `color.bg.action.success.subtle`, `color.bg.action.warning.subtle`, `color.bg.action.danger.subtle`, `color.bg.surface.subtle`, `color.text.action.brand`, `color.text.action.success`, `color.text.action.warning`, `color.text.action.danger`, `color.text.primary`, `color.border.default`, `radius.md`, `space.1`, `space.3`, `space.4`, `font.size.sm`, `font.weight.semibold`, `font.lineHeight.normal`

### Accessibility

Role: `status`

Notes:
- For non-critical updates the default `role="status"` is appropriate. For critical errors that must interrupt the user, use a Toast or Dialog instead.
- Do not use color alone to convey meaning; the leading icon and title text should make the tone unambiguous.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Banner` | `alternative` | Banner for page-level; Callout for in-content. |
| `Stack` | `parent` | Often inside a Stack of body content. |
| `Toast` | `sibling` |  |

### Prompt examples

**in-content tip** — _"a blue info callout about API limits"_

```tsx
<Callout tone="info" title="Heads up">Rate limit is 100 req/min.</Callout>
```

**inline error** — _"red error callout in a settings page"_

```tsx
<Callout tone="danger">Couldn't save changes — please retry.</Callout>
```

### Related

- Toast

---

<a id="empty-state"></a>

# EmptyState

A centered placeholder for "no data yet" — icon, title, description, and an action.

> category: feedback · status: stable · since: 0.2.0

```ts
import { EmptyState } from '@helixui/core'
```

### Tags

`placeholder`, `no-data`, `cta`

### Anatomy

```
        [icon]
      Title
   short description
     [ Action ]
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `centered, ~280px tall`
- stackable: `false`
- fullBleed: `false`

### Visual

A centered column with a large muted icon, a heading, a description, and an optional primary action button. Used inside an empty Card, empty list, or empty page.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `icon` | `ReactNode` | — | Optional leading icon. |
| `title` | `ReactNode` | — | Headline. |
| `description` | `ReactNode` | — | Supporting text. |
| `actions` | `ReactNode` | — | Buttons or links to recover from the empty state. |
| `size` | `'sm' \| 'md'` | `md` | Compact or full size. |

### Tokens

`color.bg.action.neutral.default`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `radius.full`, `space.2`, `space.3`, `space.6`, `space.12`, `font.family.sans`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.weight.semibold`

### Accessibility

Role: `status`

Notes:
- The container uses `role="status"` so screen readers announce the empty state when it appears.
- Always include `actions` if there's a path to recover (create the first item, retry, …).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Card` | `parent` | Often inside a Card to show "no data yet". |
| `Button` | `child` | Primary CTA below the description. |
| `Banner` | `sibling` |  |

### Prompt examples

**empty inbox** — _"no messages placeholder with a Compose button"_

```tsx
<EmptyState
  icon={<InboxIcon />}
  title="No messages"
  description="When someone writes you, it appears here."
  action={<Button>Compose</Button>}
/>
```

### Related

- Banner

---

<a id="presence-dot"></a>

# PresenceDot

A small status dot — online / away / busy / offline. Use standalone or attached to an Avatar.

> category: feedback · status: stable · since: 0.3.0

```ts
import { PresenceDot } from '@helixui/core'
```

### Tags

`status`, `online`, `dot`, `presence`

### Anatomy

```
●  ← solid color dot
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `~8-10px circle`
- stackable: `true`
- fullBleed: `false`

### Visual

A small solid circle in a status color: success (online), warning (away), danger (busy), neutral (offline). Often anchored to the bottom-right of an Avatar.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `status` | `'online' \| 'away' \| 'busy' \| 'offline'` | `online` | Status; drives the color. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Dot size. |
| `attached` | `boolean` | `false` | When true, position absolutely in the bottom-right of the parent (parent must be `position: relative`). |
| `label` | `string` | — | Override the default `aria-label` ('Online', 'Away', etc.). |

### Tokens

`color.bg.surface.default`, `color.bg.action.success.default`, `color.bg.action.warning.default`, `color.bg.action.danger.default`, `color.text.muted`

### Accessibility

Role: `status`

Notes:
- The dot has `role="status"` and an `aria-label` for screen readers.
- The white border isolates the dot from the avatar; uses `color.bg.surface.default`, so it adapts to dark mode.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Avatar` | `sibling` | Anchored to an Avatar. |
| `AvatarGroup` | `sibling` |  |

### Prompt examples

**show online status** — _"green presence dot on an avatar"_

```tsx
<Box position="relative">
  <Avatar fallback="ST" />
  <PresenceDot status="online" />
</Box>
```

### Related

- Avatar
- AvatarGroup

---

<a id="progress-bar"></a>

# ProgressBar

Linear progress indicator. Determinate when given a `value`; indeterminate (looping shimmer) when `value` is omitted.

> category: feedback · status: stable · since: 0.2.0

```ts
import { ProgressBar } from '@helixui/core'
```

### Tags

`progress`, `loading`, `determinate`, `indeterminate`

### Anatomy

```
[████████████░░░░░░░░░░]  62%   ← determinate
[shimmer ░░░░░░░░░░░░░░░]       ← indeterminate (looping)
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `~6-8px tall, fills width`
- stackable: `true`
- fullBleed: `false`

### Visual

A thin horizontal bar with a brand-tinted track. Determinate fills the track to `value`; indeterminate animates a moving highlight across.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number` | — | Current value. Omit for indeterminate. |
| `max` | `number` | `100` | Max value. |
| `tone` | `'brand' \| 'success' \| 'warning' \| 'danger' \| 'neutral'` | `brand` | Fill color. |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Track height — 4 / 8 / 12 px. |
| `label` | `ReactNode` | — | Inline label above the bar. |
| `showValue` | `boolean` | `false` | Render the percentage on the right of the label row. |

### Tokens

`color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.bg.action.success.default`, `color.bg.action.warning.default`, `color.bg.action.danger.default`, `color.text.primary`, `color.text.secondary`, `radius.full`, `space.2`, `font.family.sans`, `font.size.sm`, `font.weight.medium`

### Accessibility

Role: `progressbar`

Notes:
- When `value` is provided the element receives `aria-valuenow/min/max`. Omit `value` for indeterminate (no `aria-valuenow`).
- Animation respects `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Spinner` | `alternative` | Spinner for tiny inline loading; ProgressBar for measured/long. |
| `Skeleton` | `alternative` | Skeleton when the layout itself should look loading. |

### Prompt examples

**upload progress** — _"progress bar at 62%"_

```tsx
<ProgressBar value={0.62} />
```

**unknown duration** — _"looping indeterminate bar"_

```tsx
<ProgressBar />
```

### Related

- Spinner

---

<a id="skeleton"></a>

# Skeleton

A shimmering placeholder for content that's still loading.

> category: feedback · status: stable · since: 0.1.0

```ts
import { Skeleton } from '@helixui/core'
```

### Tags

`loading`, `placeholder`, `shimmer`

### Anatomy

```
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒    ← shimmer animation
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `sized by props (width/height)`
- stackable: `true`
- fullBleed: `false`

### Visual

A flat block (radius.md) with a moving shimmer gradient. Common shapes: rectangular line, circle (avatar), and full row block. Animation respects prefers-reduced-motion.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `shape` | `'rect' \| 'circle' \| 'text'` | `rect` | Skeleton shape. |
| `width` | `number \| string` | — | Override CSS width. |
| `height` | `number \| string` | — | Override CSS height. |

### Tokens

`color.bg.action.neutral.default`, `color.bg.action.neutral.hover`, `radius.md`, `radius.sm`, `radius.full`

### Accessibility

Notes:
- Skeleton is `aria-hidden`. It must be paired with a `aria-live` region elsewhere if the loading state is meaningful (e.g. "Loading messages…").
- Animation respects `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `List` | `child` | Used as placeholder rows while loading. |
| `Card` | `child` | Inside Cards as placeholder content. |
| `Spinner` | `sibling` |  |

### Prompt examples

**list loading state** — _"5 skeleton rows while loading"_

```tsx
{Array.from({ length: 5 }).map((_, i) => (
  <Skeleton key={i} height={48} />
))}
```

### Related

- Spinner

---

<a id="spinner"></a>

# Spinner

An indeterminate loading indicator.

> category: feedback · status: stable · since: 0.1.0

```ts
import { Spinner } from '@helixui/core'
```

### Tags

`loading`, `spinner`, `indicator`

### Anatomy

```
◐   ← rotating ring
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `16/20/24/32px (sm/md/lg/xl)`
- stackable: `true`
- fullBleed: `false`

### Visual

A circular progress ring with a rotating gap. Color follows currentColor. Animation respects prefers-reduced-motion.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `size` | `'sm' \| 'md' \| 'lg'` | `md` | Visual size. |
| `tone` | `'current' \| 'brand' \| 'neutral'` | `current` | Color. `current` inherits from CSS `color`. |
| `label` | `string` | `Loading` | Accessible name announced by screen readers. |

### Tokens

`color.text.action.brand`, `color.text.muted`

### Accessibility

Role: `status`

Notes:
- For determinate progress, use a different component (helixui does not yet ship one — use the native `<progress>` for now).
- Animation duration extends under `prefers-reduced-motion` rather than stopping outright; a frozen spinner suggests "stuck".

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Button` | `child` | Inside a Button when the action is in flight. |
| `ProgressBar` | `alternative` | ProgressBar when there is a known value or this takes long. |
| `Skeleton` | `sibling` |  |

### Prompt examples

**loading indicator** — _"small inline spinner"_

```tsx
<Spinner size="sm" />
```

### Related

- Skeleton

---

<a id="toast"></a>

# Toast

Transient messages that announce a background result. Mount `<ToastProvider />` once; call `toast.success(...)` from anywhere.

> category: feedback · status: beta · since: 0.1.0

```ts
import { ToastProvider, toast } from '@helixui/core'
```

### Tags

`transient`, `notification`, `pop-up`

### Anatomy

```
┌─────────────────────────┐
│ ✓ Saved.                │   ← stacks bottom-right
└─────────────────────────┘
```

### Layout

- display: `fixed`
- width: `content`
- height: `content`
- intrinsicSize: `corner-anchored, ~360px wide`
- stackable: `true`
- fullBleed: `false`

### Visual

A small surface in a viewport corner, tinted by tone (success/info/warning/danger), auto-dismissing after a timeout. Stacks vertically when multiple are visible.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `title` | `string` | — | Primary message. Required. |
| `description` | `string` | — | Optional second line. |
| `tone` | `'neutral' \| 'info' \| 'success' \| 'warning' \| 'danger'` | `neutral` | Color intent. Drives the left border color. |

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.bg.action.success.default`, `color.bg.action.warning.default`, `color.bg.action.danger.default`, `color.border.default`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `radius.md`, `radius.sm`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.weight.semibold`, `shadow.md`

### Accessibility

Role: `status`

Notes:
- Built on react-aria-components' UNSTABLE_Toast queue (the only API path while toast is stabilising). Do not stack multiple `<ToastProvider/>` instances.
- Tones use color borders + accessible icons (caller-supplied) — never rely on color alone.
- Toasts pause on focus and pointer hover. Hovered or focused toasts will not auto-dismiss.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Banner` | `alternative` | Banner for persistent; Toast for transient. |
| `Callout` | `sibling` |  |

### Prompt examples

**save confirmation** — _"show a green toast saying Saved"_

```tsx
toast.success('Saved.')
```

**error** — _"red error toast"_

```tsx
toast.error('Could not save.')
```

### Related

- Callout

---

# media

<a id="attachment-tile"></a>

# AttachmentTile

A compact tile for a file attachment — thumbnail or icon + name + size + optional remove or upload progress.

> category: media · status: stable · since: 0.3.0

```ts
import { AttachmentTile } from '@helixui/core'
```

### Tags

`file`, `attachment`, `upload`, `preview`, `tile`

### Anatomy

```
┌──────────────────────────────────────────┐
│  [thumb/icon]  filename.ext           [×] │
│                12 KB · uploading 60%      │
└──────────────────────────────────────────┘
```

### Layout

- display: `flex`
- width: `fill`
- height: `content`
- intrinsicSize: `~56px tall, hugs available width`
- stackable: `true`
- fullBleed: `false`

### Visual

A horizontal tile with a square thumbnail or file-type icon on the left, name + meta in the middle (font.size.sm), and an optional remove button on the right. While uploading, a thin progress bar overlays the bottom edge.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `ReactNode` | — | File name. |
| `size` | `ReactNode` | — | Pre-formatted size ('1.4 MB'). |
| `thumbnail` | `string` | — | Image URL — when set, replaces the file glyph with a thumbnail. |
| `icon` | `ReactNode` | — | Custom icon node (overrides default file glyph). |
| `progress` | `number` | — | 0–100. While set, shows a progress fill instead of remove. |
| `onRemove` | `() => void` | — | Show a close button that triggers this callback. Hidden during upload. |
| `compact` | `boolean` | `false` | Hide the size line and shrink padding (for inline use in messages). |

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.bg.action.brand.default`, `color.border.default`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `radius.md`, `radius.sm`, `radius.full`, `space.2`, `font.family.sans`, `font.size.xs`, `font.size.sm`, `font.weight.medium`

### Accessibility

Notes:
- Remove button has `aria-label="Remove attachment"`.
- Progress is shown visually only — pair with a `aria-live` status if the user must hear it.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatComposer` | `child` | Common in the chat composer attachment row. |
| `List` | `child` | Each List row may render as an AttachmentTile. |
| `ChatMessage` | `sibling` |  |

### Prompt examples

**show an uploaded file** — _"render a docx attachment with a remove X"_

```tsx
<AttachmentTile name="report.docx" size="48 KB" onRemove={handleRemove} />
```

**in-progress upload** — _"show upload progress on an image"_

```tsx
<AttachmentTile name="photo.jpg" size="2.4 MB" progress={0.6} />
```

### Related

- ChatComposer
- ChatMessage

---

<a id="avatar"></a>

# Avatar

A user or entity image with text fallback when the image is missing or fails to load.

> category: media · status: stable · since: 0.1.0

```ts
import { Avatar } from '@helixui/core'
```

### Tags

`user`, `identity`, `image`, `fallback`, `circle`

### Anatomy

```
●  ← circular image; if missing → initials on tinted bg
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `24/32/40/48/64px square (xs/sm/md/lg/xl)`
- stackable: `true`
- fullBleed: `false`

### Visual

A circular image with rounded fallback when the image fails to load. Fallback shows uppercase initials on a deterministic tinted background derived from the name. Optional ring (border) or PresenceDot can sit on top.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | `string` | — | Image URL. |
| `alt` | `string` | — | Accessible label. Used as `aria-label`. If empty, `fallback` is used. |
| `fallback` | `string` | — | Text to display when no image is available — typically initials. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `md` | Avatar size. |
| `shape` | `'circle' \| 'square'` | `circle` | Avatar shape. |

### Tokens

`color.bg.action.neutral.default`, `color.text.secondary`, `font.family.sans`, `font.weight.semibold`, `font.size.xs`, `font.size.sm`, `font.size.md`, `font.size.xl`, `radius.full`, `radius.md`

### Accessibility

Notes:
- Always pass `alt` when the avatar identifies a real person or entity. Use empty `alt=""` only when the avatar is purely decorative and accompanied by visible text.
- Initials in `fallback` should be 1–2 characters.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `AvatarGroup` | `child` | Used inside AvatarGroup for stacked rows. |
| `PresenceDot` | `sibling` | Render PresenceDot anchored to the avatar. |
| `ChatMessage` | `child` | Common as the leading slot of a ChatMessage. |

### Prompt examples

**user avatar with initials fallback** — _"avatar for "Sara Tang""_

```tsx
<Avatar src={user.imageUrl} fallback="ST" alt="Sara Tang" />
```

**large avatar in a profile header** — _"64px avatar in a profile card"_

```tsx
<Avatar size="xl" src={user.imageUrl} fallback="ST" />
```

---

<a id="avatar-group"></a>

# AvatarGroup

A row of overlapping avatars with an optional overflow chip — `+N` for hidden members.

> category: media · status: stable · since: 0.2.0

```ts
import { AvatarGroup } from '@helixui/core'
```

### Tags

`users`, `collaborators`, `stacked`, `overflow`

### Anatomy

```
( ●●●●  +12 )  ← overlapping avatars + overflow chip
```

### Layout

- display: `inline-flex`
- width: `content`
- height: `content`
- intrinsicSize: `hugs N avatars with negative inline gap`
- stackable: `true`
- fullBleed: `false`

### Visual

A row of avatars with negative left margin so each avatar overlaps the previous by ~30%. Each has a thin border that matches the surface so the overlap reads as separation. A `+N` overflow chip is the last child when there are more than `max` avatars.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `max` | `number` | — | Cap visible avatars; rest go into the +N chip. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl'` | `md` | Avatar size; applied to all children. |
| `total` | `number` | — | Override total count when `children` is only the visible subset. |

### Slots

- children — Avatar elements

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.text.secondary`, `radius.full`, `font.family.sans`, `font.weight.semibold`, `font.size.xs`, `font.size.sm`, `font.size.md`, `font.size.xl`

### Accessibility

Notes:
- The overflow chip has `aria-label="N more"`.
- Pass meaningful `alt` to each Avatar for screen-reader output.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Avatar` | `child` | Each child is an Avatar. |
| `List` | `child` | Often rendered as the trailing slot of a list row. |

### Prompt examples

**show a small collaborator pile** — _"show the first 4 avatars and +N chip for the rest"_

```tsx
<AvatarGroup max={4}>
  {users.map(u => <Avatar key={u.id} fallback={u.initials} src={u.image} />)}
</AvatarGroup>
```

### Related

- Avatar

---

<a id="carousel"></a>

# Carousel

A horizontal scroll-snap row of items. Native scroll on mobile (swipe); hidden arrows on hover for desktop; optional dots showing pagination.

> category: media · status: stable · since: 0.5.0

```ts
import { Carousel } from '@helixui/core'
```

### Tags

`slides`, `swipe`, `horizontal`, `gallery`

### Anatomy

```
[<]  [ slide ][ slide ][ slide ][ slide ]  [>]
              ● ○ ○ ○   ← pagination dots
```

### Layout

- display: `flex`
- width: `fill`
- height: `content`
- intrinsicSize: `one slide per snap point, height of tallest slide`
- stackable: `false`
- fullBleed: `false`

### Visual

A horizontally scrolling row that scroll-snaps each slide into view. Hidden arrow buttons appear on hover (desktop) at the edges; mobile uses native swipe. Optional dots at the bottom indicate position.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `arrows` | `boolean` | `true` | Show prev/next arrows on hover (hidden on touch). |
| `dots` | `boolean` | `false` | Show pagination dots below the track. |
| `snap` | `'start' \| 'center'` | `start` | Scroll-snap alignment of items. |
| `gap` | `number \| string` | — | Gap between items (px when number). |
| `label` | `string` | `Carousel` | `aria-label` on the wrapping region. |

### Slots

- Carousel.Item — wraps each slide. Width is up to you (e.g. `flex: 0 0 80%`).

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.active`, `color.bg.action.brand.default`, `color.border.default`, `color.border.focus`, `color.text.primary`, `radius.full`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `shadow.md`

### Accessibility

Notes:
- Wrapper is `role="region"` with `aria-roledescription="carousel"`.
- Dots are `role="tablist" / role="tab"` with `aria-selected`.
- On touch devices, scrollbars are hidden; swipe is the only nav. Arrows are mouse-only.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Card` | `child` | Each slide is often a Card. |

### Prompt examples

**image gallery** — _"a swipeable photo carousel with dots"_

```tsx
<Carousel showDots>
  {photos.map(p => <img key={p.id} src={p.url} alt="" />)}
</Carousel>
```

---

# chat

<a id="chat-composer"></a>

# ChatComposer

A multi-line message composer with auto-resize, Enter-to-send (Shift+Enter for newline), and slots for attachments and toolbar buttons.

> category: chat · status: stable · since: 0.3.0

```ts
import { ChatComposer } from '@helixui/core'
```

### Tags

`input`, `message`, `send`, `ai`, `multiline`

### Anatomy

```
┌────────────────────────────────────────┐
│ [📎] | Type a message...           [↑] │
│       (auto-resize, Enter sends)       │
└────────────────────────────────────────┘
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `min ~48px, grows up to maxHeight on multi-line`
- stackable: `false`
- fullBleed: `false`

### Visual

A rounded surface (radius.lg) holding a multi-line textarea, optional attachment button on the left, and a brand-colored send button on the right. Auto-grows up to a max height, then scrolls inside. Enter sends; Shift+Enter inserts a newline.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `string` | — | Controlled message text. |
| `defaultValue` | `string` | — | Uncontrolled initial text. |
| `onChange` | `(v: string) => void` | — | Called on every keystroke. |
| `onSend` | `(v: string) => void` | — | Called when the user presses Enter or clicks send. Receives the trimmed message. |
| `placeholder` | `string` | `Send a message…` | Placeholder. |
| `isDisabled` | `boolean` | `false` | Disable the entire composer. |
| `isSending` | `boolean` | `false` | While true, the send button is disabled (use during request). |
| `attachments` | `ReactNode` | — | Slot above the input — attachment chips, mentions. |
| `beforeInput` | `ReactNode` | — | Slot to the left of the input (formatting toolbar, attach button). |
| `afterInput` | `ReactNode` | — | Slot to the right of the input, before the send button. |
| `sendIcon` | `ReactNode` | — | Override the default paper-plane icon. |
| `sendLabel` | `string` | `Send` | `aria-label` on the send button. |
| `minRows` | `number` | `1` | Auto-resize floor. |
| `maxRows` | `number` | `8` | Auto-resize ceiling; scrolls beyond. |

### Tokens

`color.bg.surface.default`, `color.bg.surface.muted`, `color.bg.action.brand.default`, `color.bg.action.brand.hover`, `color.bg.action.neutral.default`, `color.text.primary`, `color.text.on.brand`, `color.text.muted`, `color.border.default`, `color.border.focus`, `radius.lg`, `radius.full`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.md`

### Accessibility

Keyboard:
- `Enter` — Send the message.
- `Shift+Enter` — Insert newline.

Notes:
- The send button is disabled when the message is empty or whitespace.
- IME composition is respected — `Enter` does not send while composing (Korean/Japanese/Chinese input).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `AttachmentTile` | `child` | Renders attached files inside the composer. |
| `PromptSuggestions` | `sibling` | Suggestions appear above the composer. |
| `ChatList` | `sibling` | Sits below the chat list scroll area. |
| `ChatMessage` | `sibling` |  |
| `IconButton` | `sibling` |  |

### Prompt examples

**AI chat input** — _"composer that sends on Enter"_

```tsx
<ChatComposer onSend={handleSend} placeholder="Ask anything…" />
```

**with attachments** — _"composer with paperclip"_

```tsx
<ChatComposer onSend={handleSend} onAttach={handleAttach} />
```

### Related

- ChatList
- ChatMessage
- AttachmentTile
- IconButton

---

<a id="chat-header"></a>

# ChatHeader

The top bar of a single conversation — avatar, title, subtitle, right-aligned actions.

> category: chat · status: stable · since: 0.3.0

```ts
import { ChatHeader } from '@helixui/core'
```

### Tags

`conversation`, `top-bar`, `identity`

### Anatomy

```
┌──── ●  Sara Tang   typing…   ──── [⋮][📞] ┐
```

### Layout

- display: `flex`
- width: `fill`
- height: `content`
- intrinsicSize: `~56px tall, full width`
- stackable: `false`
- fullBleed: `true`

### Visual

A horizontal bar with a leading Avatar, a title with optional subtitle (online status, typing), and right-aligned action icons. Border-bottom by border.default separates it from the message list.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `avatar` | `ReactNode` | — | Avatar rendered on the left. May contain a PresenceDot. |
| `title` | `ReactNode` | — | Conversation title — channel name, person, AI assistant. |
| `subtitle` | `ReactNode` | — | Member count, presence text, model name. |
| `actions` | `ReactNode` | — | Right-aligned IconButtons / Buttons — call, search, more. |

### Tokens

`color.bg.surface.default`, `color.border.default`, `color.text.primary`, `color.text.muted`, `space.1`, `space.3`, `space.4`, `font.family.sans`, `font.size.xs`, `font.size.md`, `font.weight.semibold`

### Accessibility

Notes:
- Renders as `<header>`. The title is plain content — wrap in a heading tag if appropriate (`<Text as="h2">`).

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Avatar` | `child` | Leading slot. |
| `IconButton` | `child` | Right-aligned actions. |
| `ChatList` | `sibling` | Sits above the chat list. |
| `ChatComposer` | `sibling` |  |

### Prompt examples

**one-on-one chat header** — _"header with avatar, name, online dot"_

```tsx
<ChatHeader avatar={<Avatar fallback="ST" />} title="Sara" subtitle="online" />
```

### Related

- ChatList
- ChatComposer

---

<a id="chat-list"></a>

# ChatList

A scrolling container for ChatMessages with sticky-to-bottom auto-scroll. When the user has scrolled up to read history, new messages do NOT yank them back.

> category: chat · status: stable · since: 0.3.0

```ts
import { ChatList } from '@helixui/core'
```

### Tags

`messages`, `scroll`, `sticky-bottom`, `feed`

### Anatomy

```
┌────────────────────────┐
│ [old messages above]   │ ↑ scrolls
│ ChatMessage            │
│ ChatMessage            │
│ ChatMessage  ← new     │ ← stays pinned to bottom unless user scrolled up
└────────────────────────┘
```

### Layout

- display: `flex`
- width: `fill`
- height: `fill`
- intrinsicSize: `fills available height, scrolls`
- stackable: `false`
- fullBleed: `false`

### Visual

A vertically scrolling column that auto-pins to the bottom when new messages arrive — but only if the user is already near the bottom. If they scrolled up to read history, new messages do not yank them back.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `autoScroll` | `boolean` | `true` | Auto-scroll on children change (only if user is near the bottom). |
| `label` | `string` | `Conversation` | `aria-label` for the log container. |

### Slots

- children — ChatMessage components

### Tokens

`space.4`, `font.family.sans`

### Accessibility

Role: `log`

Notes:
- Container is `role="log"` with `aria-live="polite"`. New messages are announced once.
- The sticky-to-bottom behaviour preserves the user's reading position when they scroll up.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatMessage` | `child` | Each child is a ChatMessage. |
| `ChatHeader` | `sibling` | Sits below ChatHeader. |
| `ChatComposer` | `sibling` | Sits above ChatComposer. |
| `TypingIndicator` | `sibling` |  |

### Prompt examples

**render an AI conversation** — _"list of chat messages with sticky-bottom"_

```tsx
<ChatList>
  {messages.map(m => <ChatMessage key={m.id} role={m.role}>{m.content}</ChatMessage>)}
</ChatList>
```

### Related

- ChatMessage
- ChatComposer
- TypingIndicator

---

<a id="chat-message"></a>

# ChatMessage

A single message in a chat — user / assistant / system role, bubble or inline (Slack-style) variant, optional avatar / name / time / footer.

> category: chat · status: stable · since: 0.3.0

```ts
import { ChatMessage } from '@helixui/core'
```

### Tags

`bubble`, `message`, `role`, `user`, `assistant`

### Anatomy

```
[avatar]  Name · time
          ┌──────────────────────┐
          │  message body…       │
          └──────────────────────┘
          [optional footer]
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `left or right aligned by role, max ~720px wide`
- stackable: `true`
- fullBleed: `false`

### Visual

A row containing an avatar, a name + timestamp meta line, and a content bubble. User messages typically right-align with brand-tinted bubble; assistant left-aligns with neutral surface. The `inline` variant strips the bubble for Slack-style flat feeds.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `role` | `'user' \| 'assistant' \| 'system'` | `assistant` | Speaker. `user` aligns right (in bubble variant); `system` centers and dims. |
| `variant` | `'bubble' \| 'inline'` | `bubble` | `bubble` for messenger UIs; `inline` for thread-style chat. |
| `avatar` | `ReactNode` | — | Avatar element rendered to the left (or right, for user). |
| `name` | `ReactNode` | — | Display name. Position depends on variant. |
| `time` | `ReactNode` | — | Timestamp or relative time ('2m ago'). |
| `pending` | `boolean` | `false` | Mute the bubble while a message is being sent or streamed. |
| `footer` | `ReactNode` | — | Slot below the bubble — reactions, ToolCall, CitationList. |

### Slots

- children — message content (text, MarkdownMessage, CodeBlock, etc.)

### Tokens

`color.bg.action.brand.default`, `color.bg.action.neutral.default`, `color.text.primary`, `color.text.muted`, `color.text.on.brand`, `radius.lg`, `radius.sm`, `space.1`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.xs`, `font.size.sm`, `font.weight.semibold`

### Accessibility

Notes:
- The bubble itself is a styled `<div>`. Provide a sensible reading order; screen readers announce children + meta.
- For lists of messages, wrap in `<ChatList>` which is a `role="log"` container.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatList` | `parent` | Always inside a ChatList. |
| `Avatar` | `child` | Leading avatar. |
| `ToolCall` | `child` | Tool calls render inside an assistant message. |
| `ThinkingBlock` | `child` | Reasoning summary inside an assistant message. |
| `ChatComposer` | `sibling` |  |
| `TypingIndicator` | `sibling` |  |
| `ChatHeader` | `sibling` |  |

### Prompt examples

**user prompt** — _"a user message saying hello"_

```tsx
<ChatMessage role="user">Hello!</ChatMessage>
```

**streaming assistant reply** — _"show an assistant reply with a streaming caret"_

```tsx
<ChatMessage role="assistant">
  {streamedText}<StreamingIndicator />
</ChatMessage>
```

### Related

- ChatList
- ChatComposer
- TypingIndicator
- ChatHeader

---

<a id="prompt-suggestions"></a>

# PromptSuggestions

A row (chips) or grid (cards) of suggested prompts. Used at the start of an empty AI conversation or as follow-up suggestions after a response.

> category: chat · status: stable · since: 0.3.0

```ts
import { PromptSuggestions, type PromptSuggestion } from '@helixui/core'
```

### Tags

`ai`, `starters`, `follow-ups`, `chips`

### Anatomy

```
( Suggestion 1 ) ( Suggestion 2 ) ( Suggestion 3 )       ← chips
┌─────────────────┐ ┌─────────────────┐
│  Title          │ │  Title          │   ← cards
│  description    │ │  description    │
└─────────────────┘ └─────────────────┘
```

### Layout

- display: `flex`
- width: `fill`
- height: `content`
- intrinsicSize: `wraps; chip row or card grid`
- stackable: `false`
- fullBleed: `false`

### Visual

Either a wrapping row of pill-shaped chips (compact) or a 2-column card grid (richer). Tapping a suggestion fires `onSelect` with the prompt text.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `suggestions` | `PromptSuggestion[]` | — | Required. Each has `id`, `label`, optional `hint`, `icon`. |
| `onSelect` | `(s) => void` | — | Called when the user picks a suggestion. |
| `layout` | `'chips' \| 'cards'` | `chips` | Compact wrap-around chips or larger grid cards. |
| `label` | `string` | `Suggested prompts` | `aria-label` on the wrapping group. |

### Tokens

`color.bg.surface.default`, `color.bg.action.neutral.default`, `color.border.default`, `color.border.strong`, `color.border.focus`, `color.text.primary`, `color.text.muted`, `color.text.action.brand`, `radius.md`, `space.2`, `space.3`, `space.4`, `font.family.sans`, `font.size.sm`, `font.size.xs`, `font.weight.medium`

### Accessibility

Notes:
- The wrapper is `role="group"` with an `aria-label`.
- Each suggestion is a `<button>` so it's focusable and activatable with Enter / Space.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatComposer` | `sibling` | Sits above the composer in an empty state. |
| `EmptyState` | `alternative` | Use EmptyState for non-AI empty states. |

### Prompt examples

**AI conversation starters** — _"three suggested prompts as chips"_

```tsx
<PromptSuggestions
  variant="chips"
  suggestions={[{ id: '1', text: 'Summarize this' }, { id: '2', text: 'Translate to Korean' }]}
  onSelect={s => send(s.text)}
/>
```

### Related

- ChatComposer

---

<a id="streaming-indicator"></a>

# StreamingIndicator

An inline marker placed at the end of streaming LLM text — blinking caret, pulsing block, or three dots.

> category: chat · status: stable · since: 0.3.0

```ts
import { StreamingIndicator } from '@helixui/core'
```

### Tags

`ai`, `streaming`, `caret`, `inline`

### Anatomy

```
…some streamed text▍   ← blinking caret at the end
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `~10px wide caret / ~16px dots`
- stackable: `false`
- fullBleed: `false`

### Visual

A small inline marker placed at the end of streaming text. Variants: blinking caret, pulsing block, or three dots.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'caret' \| 'block' \| 'dots'` | `block` | Visual style. |

### Tokens

`color.text.action.brand`

### Accessibility

Role: `status`

Notes:
- The element has `aria-label=\"Streaming\"`. Animation respects `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatMessage` | `child` | Lives inside an in-flight assistant message. |
| `TypingIndicator` | `alternative` | TypingIndicator is shown while another participant types. |
| `ThinkingBlock` | `sibling` |  |

### Prompt examples

**show LLM streaming** — _"caret at the end of streamed text"_

```tsx
<>{text}<StreamingIndicator /></>
```

### Related

- ChatMessage
- ThinkingBlock

---

<a id="thinking-block"></a>

# ThinkingBlock

A collapsed reasoning / chain-of-thought block. Use to present an LLM's intermediate thought process in a non-distracting way.

> category: chat · status: stable · since: 0.3.0

```ts
import { ThinkingBlock } from '@helixui/core'
```

### Tags

`ai`, `reasoning`, `chain-of-thought`, `collapsible`

### Anatomy

```
[ ▶ Thinking…           ]   ← collapsed
[ ▼ Thinking…           ]
     reasoning paragraph 1
     reasoning paragraph 2
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, hugs content`
- stackable: `true`
- fullBleed: `false`

### Visual

A muted card with a small "Thinking…" header and a collapsible body. Used to show LLM internal reasoning without making it the main attraction.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `ReactNode` | — | Override the header label. Default depends on `thinking`/`duration`. |
| `thinking` | `boolean` | `false` | While true, shows a pulsing dot and the brand-colored rule. |
| `duration` | `ReactNode` | — | Append a duration to the default 'Thought' label (e.g. '4s'). |
| `defaultOpen` | `boolean` | `false` | Initially expanded. |
| `open` | `boolean` | — | Controlled state. |
| `onOpenChange` | `(open) => void` | — | Change handler. |

### Slots

- children — the reasoning text (whitespace preserved)

### Tokens

`color.bg.action.brand.default`, `color.border.default`, `color.border.focus`, `color.text.secondary`, `color.text.muted`, `radius.sm`, `space.1`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`

### Accessibility

Notes:
- Header button has `aria-expanded`. While `thinking` the pulsing dot animates; respect `prefers-reduced-motion` if you bring custom motion.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatMessage` | `child` | Inside an assistant message. |
| `ToolCall` | `sibling` | Often appears next to ToolCall blocks. |

### Prompt examples

**expose chain-of-thought** — _"collapsible reasoning block in a chat"_

```tsx
<ThinkingBlock summary="Planning the response">
  Step 1: identify the question.
  Step 2: gather facts…
</ThinkingBlock>
```

### Related

- ToolCall
- ChatMessage

---

<a id="tool-call"></a>

# ToolCall

A collapsible card representing a single tool / function call from an LLM — name, status, optional summary line, and expandable input / output sections.

> category: chat · status: stable · since: 0.3.0

```ts
import { ToolCall } from '@helixui/core'
```

### Tags

`ai`, `function-call`, `collapsible`, `tool`

### Anatomy

```
[ ▶ get_weather   running ]
[ ▼ get_weather   ok       ]
     input:  { city: "Seoul" }
     output: { temp: 17 }
```

### Layout

- display: `block`
- width: `fill`
- height: `content`
- intrinsicSize: `fills width, hugs content`
- stackable: `true`
- fullBleed: `false`

### Visual

A collapsible card showing a tool name, status pill (running / ok / error), an optional one-line summary, and expandable input/output sections rendered as code.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `ReactNode` | — | Tool name (e.g. `web_search`). Required. |
| `status` | `'running' \| 'done' \| 'failed'` | `done` | Current state. `running` shows a pulsing dot. |
| `summary` | `ReactNode` | — | One-line argument summary, shown next to the name when collapsed (e.g. the JSON args, single-line). |
| `defaultOpen` | `boolean` | `false` | Initially expanded. |
| `open` | `boolean` | — | Controlled open. |
| `onOpenChange` | `(open) => void` | — | Open change handler. |
| `input` | `ReactNode` | — | Slot for input args — typically `<CodeBlock language="json" />`. |
| `output` | `ReactNode` | — | Slot for the result — text, table, or another CodeBlock. |

### Slots

- children — extra body content rendered after `output`

### Tokens

`color.bg.surface.default`, `color.bg.surface.subtle`, `color.bg.action.brand.subtle`, `color.bg.action.success.subtle`, `color.bg.action.danger.subtle`, `color.border.default`, `color.border.focus`, `color.text.primary`, `color.text.secondary`, `color.text.muted`, `color.text.action.brand`, `color.text.action.success`, `color.text.action.danger`, `radius.md`, `radius.full`, `space.2`, `space.3`, `font.family.sans`, `font.family.mono`, `font.size.xs`, `font.size.sm`, `font.weight.medium`, `font.weight.semibold`

### Accessibility

Notes:
- The header button has `aria-expanded` reflecting the disclosure state.
- Use inside a ChatMessage's `footer` slot to attach tool calls to a specific assistant turn.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatMessage` | `child` | Inside an assistant message. |
| `CodeBlock` | `child` | Input/output rendered as CodeBlocks. |
| `ThinkingBlock` | `sibling` | Often interleaved with reasoning. |

### Prompt examples

**render a tool invocation** — _"show a get_weather tool call result"_

```tsx
<ToolCall
  name="get_weather"
  status="ok"
  input={{ city: 'Seoul' }}
  output={{ temp: 17, condition: 'cloudy' }}
/>
```

### Related

- ChatMessage
- CodeBlock
- ThinkingBlock

---

<a id="typing-indicator"></a>

# TypingIndicator

Three bouncing dots inside a pill — shown while a participant is composing a message.

> category: chat · status: stable · since: 0.3.0

```ts
import { TypingIndicator } from '@helixui/core'
```

### Tags

`typing`, `dots`, `pill`

### Anatomy

```
( ● ● ● )   ← bouncing dots
```

### Layout

- display: `inline-block`
- width: `content`
- height: `content`
- intrinsicSize: `~36×20px pill`
- stackable: `false`
- fullBleed: `false`

### Visual

A small pill containing three dots that bounce in sequence. Indicates the other participant is composing a message.

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `ReactNode` | — | Optional speaker name rendered to the left of the dots ('Alice'). |

### Tokens

`color.bg.action.neutral.default`, `color.text.secondary`, `color.text.muted`, `radius.full`, `space.2`, `space.3`, `font.family.sans`, `font.size.sm`

### Accessibility

Role: `status`

Notes:
- Container is `role="status"` with `aria-live="polite"` and an `aria-label` like "Alice is typing".
- Animation respects `prefers-reduced-motion`.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `ChatMessage` | `alternative` | Render in place of a ChatMessage when the participant is typing. |
| `StreamingIndicator` | `alternative` | StreamingIndicator is for the streaming token, not "is typing". |
| `ChatList` | `sibling` |  |

### Prompt examples

**show "is typing"** — _"three-dot typing indicator"_

```tsx
<TypingIndicator />
```

### Related

- ChatMessage
- ChatList

---

# other

<a id="price-tag"></a>

# PriceTag

A formatted currency price label with optional strike-through original price and sale-percentage chip.

> status: stable · since: 0.7.0

```ts
import { PriceTag } from '@helixui/core'
```

### Visual

Inline row of: current price (semibold, primary text) → strike-through original (muted) → small `-N%` chip (danger soft).

### Props

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `number` | — | Current price (the number actually being charged). |
| `original` | `number` | — | Original price. When higher than `value`, renders as a strike-through pre-discount price. |
| `currency` | `string` | `'USD'` | ISO 4217 currency code. |
| `locale` | `string` | — | BCP-47 locale used by `Intl.NumberFormat`. Defaults to runtime. |
| `size` | `'sm' \| 'md' \| 'lg' \| 'xl'` | `md` | Visual size. `xl` is bolded and slightly tighter for hero pricing. |
| `showSale` | `boolean` | `true` | Whether to render the `-N%` sale chip when `original` is supplied. |
| `fractionDigits` | `number` | — | Override min/max fraction digits. By default uses the currency's locale convention. |

### Tokens

`color.text.primary`, `color.text.muted`, `color.text.action.danger`, `color.bg.action.danger.subtle`, `font.size.sm`, `font.size.md`, `font.size.lg`, `font.size.2xl`, `font.weight.semibold`, `font.weight.bold`, `radius.sm`, `space.2`

### Accessibility

Notes:
- Sale chip exposes `aria-label='N% off'`.
- Original price exposes `aria-label='Original price …'` so screen readers get the discount context.
- Numbers use `tabular-nums` so price columns align.

### Composes with

| Component | Relation | Note |
| --- | --- | --- |
| `Card` | `contained-by` | Common in product cards. |
| `Sheet` | `contained-by` | Cart drawers / line items. |
| `Table` | `contained-by` | Pricing tables. |

### Prompt examples

**Plain price** — _"show $48"_

```tsx
<PriceTag value={48} />
```

**Sale price** — _"show $36 down from $48"_

```tsx
<PriceTag value={36} original={48} />
```

**Korean Won** — _"₩48,000 in Korean locale"_

```tsx
<PriceTag value={48000} currency="KRW" locale="ko-KR" />
```

**Hero pricing** — _"big bold price for the pricing page"_

```tsx
<PriceTag value={29} size="xl" />
```

---

