, var(--manti-radius-pill))` — a no-op at the default,
pill-shaped once a theme raises it. Control-class parts (button, input, select
and combobox triggers, number-input, toggle, segmented control) join `pill`;
switch and slider thumbs join `--manti-radius-thumb`. Checkbox joins neither,
so it is structurally incapable of rounding into a radio no matter how round
the theme gets — with no clamp involved, an explicit `--manti-checkbox-radius`
still applies exactly as written.
- **`[data-radius]` presets.** Set the attribute on any container to assign the
factor and every channel at once:
```html
…
```
The five modes are `none`, `sharp`, `default`, `round` and `pill`, typed as
`radiusModes` in `@manti-ui/tokens`.
Components now anchor every size on **one** ramp step and scale it, rather than
hopping to a coarser one — hopping is what makes a small control overshoot.
Button's `sm`/`md`/`lg` are `0.7 / 1 / 1.3 ×` the `md` step (pixels unchanged at
10/14/18), so retuning `--manti-radius-md` moves all three together and touches
nothing outside the control class.
The docs right rail and the Storybook toolbar both ship a radius picker, so you
can feel each preset before adopting one.
## Colour is now audited, not asserted
- **A contrast gate runs in the styles build.** `check-contrast.mjs` audits every
load-bearing pair with WCAG 2 and APCA and fails the build on a regression.
Colour maths moved to [colorjs.io](https://colorjs.io), replacing ~150 lines of
hand-rolled OKLCH/WCAG/APCA — the old clamp-to-sRGB was measuring the wrong
colour for the 11 stops that sit outside sRGB. The audit also reports gamut
coverage (11/72 outside sRGB, 0 outside Display-P3, max ΔEok 0.0106) and
re-runs every gated pair through CSS Color 4 gamut mapping.
- **The gate no longer passes what it cannot resolve.** A dangling `var()` used
to print `?` and count as a success, which is how the primary and danger
variants went unchecked after a rename.
- **`--variant-on-solid` is generated by measurement.** `gen-variant-ink.mjs`
resolves each variant's solid per theme, scores the candidate inks and writes
the winner into a checked region. Ranking is AA-first then APCA Lc: on the
primary orange the two metrics disagree (light ink scores Lc 65 but only
3.39:1; dark ink Lc 41 at 5.24:1), and AA is the floor the gate enforces. The
generator reproduced all five hand-authored choices.
## Tokens derive from a base
- Typography and spacing are derived from a single base value via `calc()`, so
`--manti-text-base` or `--manti-space-1` rescales its whole family.
- The neutral is unified on one cool hue (`--manti-cool-hue`, 280) — re-tint
every surface, border and text role from one property.
- Colour ramps are generated from compact specs (`rampFrom`) in
`@manti-ui/tokens` instead of being written out stop by stop.
- Neutral (`--manti-fill-*`) and variant (`--variant-fill-*`) alpha fill ladders
give rest / hover / pressed washes a single place to tune.
## Components
- **Select and Combobox** get a connected open-panel look; the panel border
follows the active variant via `data-variant` on the portalled positioner.
- **Combobox** renders removable chips in multi-select.
- **Input** drops the focus-ring glow in favour of a border-colour change alone.
---
URL: https://manti.design/components/
Summary: Browse all 53 accessible Manti UI React components - buttons, forms, overlays, navigation, and data display - each built on a Zag.js state machine.
# Components
Every component page includes live demos, props, public anatomy, and component
tokens.
Start with [Getting Started](/getting-started). For styling, use the
[plain CSS](/guides/plain-css) or [Tailwind](/guides/tailwind) guide.
---
URL: https://manti.design/typography/
Summary: The Manti UI type scale: font families, the xs-to-5xl size stops, weights, line heights, and the tracking that tightens as type grows.
# Typography
Manti UI uses a compact UI-first type scale.
[Text](/typography/text) and [Heading](/typography/heading) put that scale
behind a component API, with a neutral emphasis ladder and semantic color as two
independent axes. The remaining primitives add Manti's token-backed visual
language without giving up native HTML semantics:
[Blockquote](/typography/blockquote), [Code](/typography/code), and
[Kbd](/typography/kbd).
## Size
`--manti-text-xs` through `--manti-text-5xl` provide interface and display
sizes. Pair them with `--manti-leading-none`, `tight`, `snug`, `normal`, or
`relaxed`. `none` (`1`) is for single-line chrome such as a day-cell number or
a segmented-control label, where the box should hug the glyphs.
```css
.card-title {
font-size: var(--manti-text-xl);
line-height: var(--manti-leading-snug);
}
```
## Weight
Available weights are `regular` (400), `medium` (500), `semibold` (600), and
`bold` (700).
## Tracking
Optical letter-spacing. Large type reads as loose unless it is pulled in, and
small label-ish text reads as cramped unless it is pushed out. The stops are
`--manti-tracking-tighter` (`-0.02em`), `tight` (`-0.01em`), `normal`, `wide`
(`0.02em`), `wider` (`0.04em`), and `widest` (`0.06em`).
Because the values are in `em`, each stop scales with whatever font size it
lands on. Text and Heading step through them automatically as `size` grows.
```css
.hero-title {
font-size: var(--manti-text-5xl);
letter-spacing: var(--manti-tracking-tighter);
}
```
## Families
- `--manti-font-sans` — Inter with system fallbacks
- `--manti-font-mono` — system monospace stack
Inter is not bundled. Load it in the application or override
`--manti-font-sans`.
---
URL: https://manti.design/changelog/v0.4.0/
Summary: TextField is renamed to Input and PasswordInput folds into , plus panel material roles are centralized.
# v0.4.0
_Released 2026-07-19._
## Breaking changes
- **TextField → Input.** `TextField` is renamed to `Input`, and `PasswordInput`
is folded into it as ` `. The two always rendered the
same `field` shell; the password affordances (show/hide toggle, Caps Lock
warning) now belong to Input and apply to `type="password"` only — the same
rule the inherited native attributes already follow (`min`/`max` for
`type="number"`, `accept` for `type="file"`).
```diff
-import { TextField, PasswordInput } from '@manti-ui/react';
+import { Input } from '@manti-ui/react';
-
+
-
+
```
The password props are renamed to say which type they belong to, since names
like `visible` and `showLabel` are ambiguous next to Input's own `label`:
| `PasswordInput` | `Input` |
| ---------------------- | ---------------------------- |
| `showVisibilityToggle` | `showPasswordToggle` |
| `visible` | `passwordVisible` |
| `defaultVisible` | `defaultPasswordVisible` |
| `onVisibilityChange` | `onPasswordVisibilityChange` |
| `showLabel` | `showPasswordLabel` |
| `hideLabel` | `hidePasswordLabel` |
`showCapsLockWarning` is unchanged. `capsLockLabel` keeps its name but changes
meaning: it is now an assistive-tech-only string (see below).
- **CSS: the `password-input` scope is gone.** Its two parts moved onto the
`field` scope that Input already renders. Any custom CSS targeting them must be
retargeted:
```diff
-[data-scope='password-input'][data-part='visibility-trigger']
+[data-scope='field'][data-part='visibility-trigger']
-[data-scope='password-input'][data-part='caps-lock']
+[data-scope='field'][data-part='caps-lock']
```
The rest of the `field` anatomy, its component tokens (`--manti-field-*`), and
Textarea are unaffected.
## Changed
- **Input** — the Caps Lock warning is reduced to its icon so the amber "Caps
Lock is on" text no longer competes with the value being typed. The wording
moves into a visually-hidden `caps-lock-label` part — it still backs the
`role="status"` live region and the input's `aria-describedby`, so it is hidden
from the screen, not from the accessibility tree. `capsLockLabel` is therefore
now an assistive-tech-only string.
- **Panels** — repeated panel material values are centralized as semantic roles,
making the treatment consistent and adjustable from one place.
---
URL: https://manti.design/components/accordion/
Summary: Accordion stacks collapsible sections from an items array of value, title and content; set multiple for several open panels, defaultValue for initial state.
# Accordion
Pass `items` as `{ value, title, content }`. The Zag.js machine manages focus,
keyboard navigation, and open panels.
## Multiple panels
Set `multiple` to keep several panels open. Use `defaultValue` for the initial
uncontrolled state.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/button/
Summary: Button is an action control with seven variants plus a link treatment, sizes, leading and trailing icon parts, a loading state, and an as prop for anchors.
# Button
Button supports the seven built-in variants, custom `MantiVariant` strings, and
a Button-only `link` treatment.
Set `as="a"` for navigation without nesting interactive elements. Native props
and the ref type follow the selected root. Leading and trailing icons are
decorative and render in public `leading-icon` / `trailing-icon` anatomy parts;
the accessible name must come from children or `aria-label`.
## Sizes
## Loading
`loading` blocks interaction, shows a Spinner, and preserves the button width.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/typography/text/
Summary: Text renders token-backed body copy with a three-step neutral emphasis ladder, semantic color variants, alignment, truncation, and line clamping.
# Text
Text renders body copy from the shared type scale. It carries no layout of its
own beyond alignment and truncation, so it drops into a card, a form, or a table
cell without fighting the surrounding grid.
By default it renders a ``. Use `as` when the element should be something
else — a `` inside a sentence, a `` beside a field, an `` in a
list. The styling stays identical; only the semantics change.
## Size and weight
`size` selects a stop on the same scale the tokens expose, from `xs` through
`5xl`. Line height and tracking tighten automatically as the size grows, because
body leading on a display size reads as loose rather than generous.
Weight rides the same prop, after a slash:
```tsx
// stop only
// stop and weight
```
The two halves are not equivalent. Writing the stop alone leaves the weight to
the stylesheet, so a consumer who decides that `lg` means semibold in *their*
system says it once in CSS instead of at every call site:
```css
[data-scope='text'][data-part='root'][data-size='lg'] {
--manti-text-weight: var(--manti-weight-semibold);
}
```
Spelling out `lg/regular` overrides that again at the call site.
## Emphasis
`emphasis` walks the neutral ladder. It answers "how loud is this line?", not
"what color is it": all three rungs stay neutral and are contrast-checked in
both themes.
## Variant
`variant` is the separate, semantic color axis. Because the two axes are
independent, a message can be red *and* quiet at the same time. When both are
set, `variant` wins.
## Truncation
`truncate` clamps to a single line with an ellipsis; `lineClamp` clamps to a
given number of lines. Setting both leaves `lineClamp` in charge.
## API
Text accepts every native attribute of whatever element `as` resolves to, in
addition to the props below.
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.3.0/
Summary: A framework-agnostic keyboard-shortcut primitive — useShortcut / useShortcuts — bindable to any component, plus a softer Button soft-variant highlight.
# v0.3.0
_Released 2026-07-13._
## Added
- **useShortcut** — a new framework-agnostic keyboard-shortcut primitive.
`useShortcut(combo, handler, options)` and `useShortcuts(map, options)` bind
key combinations to actions on **any** component — Manti UI or your own. It
supports modifier combos (`mod+k`, `ctrl+shift+p`, where `mod` resolves to ⌘
on macOS and Ctrl elsewhere) and key **sequences** (`g d`). Global by default
(listens on `window`, so it fires regardless of focus with zero wiring) or
scoped to a `ref`. Includes a form-element guard (won't fire while you type in
an input/textarea/contenteditable unless `enableOnFormElements` is set),
`preventDefault` on by default, plus `stopPropagation` and `enabled`. It is
SSR-safe and backed by a pure-DOM engine in `@manti-ui/folds`, and is exposed
standalone at `@manti-ui/react/shortcut` so it can be imported without pulling
in any Manti UI component.
## Changed
- **Button** — the `soft` variant's panel highlight is now a subtle inset glow
rather than a top highlight line, for a softer raised feel.
---
URL: https://manti.design/components/switch/
Summary: Switch is an on and off control using role=switch, with defaultChecked or checked plus onCheckedChange, two sizes, and children or inputProps for its label.
# Switch
Use `defaultChecked` for uncontrolled state or `checked` with
`onCheckedChange` for controlled state. The actual input uses `role="switch"`.
`children` renders a visible label; use `inputProps` for `aria-label` or
`aria-labelledby` when the label lives elsewhere.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/typography/heading/
Summary: Heading keeps semantic rank and visual size independent, so an h2 can render at any stop on the Manti type scale without reaching for a div.
# Heading
Heading renders a real `h1`–`h6` element with Manti's title treatment: tighter
leading than body copy, semibold weight, and optical tracking that pulls in as
the type grows.
## Level
`level` picks both the element and a sensible default size, so plain markup
already reads correctly.
## Level and size are independent
Document outline and visual hierarchy are different problems. `size` overrides
the stop `level` implies, which means a section can stay an `h2` for screen
readers while laying out small, and a hero can be an `h1` at display size —
without anyone reaching for a styled ``.
If you genuinely need the look without the rank, `as` overrides the element and
leaves the styling in place.
## Weight
Weight rides the `size` prop after a slash, the same way [Text](/typography/text)
does. Leaving it off keeps the stylesheet's default, which is bold at `level={1}`
and semibold everywhere else:
```tsx
// bold, from the level
// same stop, weight overridden
```
## Emphasis and variant
Heading shares [Text](/typography/text)'s two color axes: `emphasis` for the
neutral ladder and `variant` for semantic color.
## API
Heading accepts every native attribute of the rendered heading element in
addition to the props below.
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.2.0/
Summary: A month-grid Calendar, a ColorPicker copy area with eyedropper and format tabs, a compact Tabs size, new Button and Checkbox tokens, and two anatomy changes.
# v0.2.0
_Released 2026-07-04._
## Breaking changes
- **ColorPicker** — the editable hex `channel-input` part has been removed. The
panel now shows the selected color in a read-only Clipboard field (see Added
below), so any custom CSS targeting `[data-scope='color-picker']
[data-part='channel-input']` no longer matches.
- **TagsInput** — each tag now renders as a single `item-preview` span; the outer
`data-part='item'` wrapper is no longer rendered. Custom CSS targeting
`[data-scope='tags-input'] [data-part='item']` no longer matches — target
`[data-part='item-preview']` instead.
## Added
- **Calendar** — a new standalone **month-grid** component: a weekday header plus
a six-row day grid that shows an entire month at once, distinct from the
popover DatePicker. It reuses the Zag.js `date-picker` machine in inline mode
for date math, month navigation, locale/week-start, and grid a11y. Supports
`selectionMode` (`single` / `multiple` / `range`) with a `tone` highlight,
`readOnly` for a display-only month, `fixedWeeks` for constant height, and a
`renderDay(day)` slot for per-day content such as event badges. Ships the
component tokens `--manti-calendar-day-min-height`,
`--manti-calendar-day-padding`, and `--manti-calendar-radius`.
- **ColorPicker** — a new copy area in the panel: small `soft` Tabs switch the
format (**HEX / RGBA / HSLA**) over a full-width Clipboard field showing the
selected value, with one-click copy, alongside an **eyedropper** button wired
to the machine's `getEyeDropperTriggerProps` (Chromium-only; a no-op where the
EyeDropper API is unsupported).
- **Tabs** — a `size` prop (`'sm' | 'md'`, default `'md'`, emitted as
`data-size`). `sm` tightens the gap, trigger padding, and font for compact,
embedded usage such as panels and toolbars.
- **Button** — a `--manti-button-cursor` component token (default `default`), so
an app can opt every button into `cursor: pointer` (or any other cursor) with
one variable instead of overriding the rule.
- **Checkbox** — a `--manti-checkbox-indicator-size` component token controlling
the check indicator's size within the control, with per-size defaults.
## Changed
- **Switch** — the thumb squishes (shrinks in height) while the control is
pressed, for a more tactile press, staying vertically centered in the track.
- **Button** — the pressed state is a crisper `translateY(1px)` nudge, dropping
the previous subpixel scale.
- **TagsInput** — the control padding tightens so the tag chips sit closer to the
field edge.
---
URL: https://manti.design/components/card/
Summary: Card is a composable surface built from Card.Header, Card.Title, Card.Description, Card.Body and Card.Footer, with elevated and interactive variants.
# Card
Compose Card with `Card.Header`, `Card.Title`, `Card.Description`, `Card.Body`,
and `Card.Footer`.
## Elevated and interactive
`elevated` strengthens the surface tint. `interactive` adds hover and focus
movement; pair it with real link or button semantics.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/typography/blockquote/
Summary: Blockquote renders a semantic block quotation with a quiet Manti accent rule, an optional citation, and type drawn entirely from the scale tokens.
# Blockquote
Blockquote renders the native `
` element for quotations from another
source. Its leading accent, spacing, type, and color all resolve through Manti
tokens.
## Attribution
The native `cite` attribute stores a source URL but does not display it. Put
visible attribution next to the Blockquote in your own `` element when
readers need to see the source.
## API
Blockquote accepts every native `` attribute in addition to the
props below.
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.1.5/
Summary: Two fixes: Tabs no longer leak trigger and indicator styles into embedded components, and Clipboard keeps a neutral focus border until a copy succeeds.
# v0.1.5
_Released 2026-07-03._
## Fixed
- **Tabs** — variant rules for the `trigger` and `indicator` parts matched any
descendant under the root, so components rendered inside tab content (for
example a Clipboard's copy/check icon wrappers, which are `indicator` parts)
picked up the sliding-thumb chrome and rendered as a stray box. Both parts are
now anchored through `> [data-part='list'] >`, so only the tabs' own anatomy is
styled and embedded components are left alone. No visual change to the tabs.
- **Clipboard** — `:focus-within` used the tone ring for its border, so with the
default `tone="success"` simply clicking into the field turned it green,
indistinguishable from the copied confirmation. Focus now uses the neutral
`--manti-focus-ring`, and the tone tint applies only while `data-copied` is set
(during the copied timeout).
---
URL: https://manti.design/components/avatar/
Summary: Avatar renders a user image from src and falls back to children initials when it fails, with sm to xl sizes and a circle or square shape.
# Avatar
Avatar shows `src` when it loads and renders `children` as the fallback. Use
`size` from `sm` to `xl` and `shape="circle"` or `"square"`.
## Fallback and shape
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/badge/
Summary: Badge is a compact label or status chip in primary, secondary, success, info, danger and outline variants, with sizes and an optional leading dot marker.
# Badge
Badge supports every built-in variant except `tertiary`: `primary`, `secondary`,
`success`, `info`, `danger`, and `outline`.
## Dot
Set `dot` to add a leading status marker.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/typography/code/
Summary: Code renders semantic inline code with a token-backed Manti treatment: monospace family, a subtle surface, and a size that tracks the copy around it.
# Code
Code renders the native inline `` element. Use it for identifiers,
commands, package names, and short code fragments inside prose; use a dedicated
code block for multiline source.
## API
Code accepts every native `` attribute in addition to the props below.
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.1.4/
Summary: A reworked Splitter resize handle that widens without reflowing panels, plus three Splitter component tokens.
# v0.1.4
_Released 2026-07-01._
## Changed
- **Splitter** — the resize handle no longer reflows the panels when it grows.
The trigger is now a fixed-width grab track holding a thin line that tones and
widens via an outline on hover/drag, rather than animating the track's own
width. The active state is keyed on hover/drag instead of focus, so the handle
no longer stays stuck in the active tone after a mouse drag ends.
## Added
- **Splitter** — three component tokens for the handle:
`--manti-splitter-handle-size` (the grab-track thickness),
`--manti-splitter-line-size` (the resting line), and
`--manti-splitter-line-size-active` (the widened band on hover/drag).
---
URL: https://manti.design/components/alert/
Summary: Alert is an inline status message in primary, secondary, success, info or danger variants, using role=status by default and role=alert for danger.
# Alert
Alert supports `primary`, `secondary`, `success`, `info`, and `danger`. It uses
`role="status"` by default and `role="alert"` for danger.
## Dismissal
Provide `onDismiss` to show a close button. Your application owns whether the
Alert remains rendered.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/typography/kbd/
Summary: Kbd renders a semantic keyboard-input label styled as a compact key cap, for documenting shortcuts and the keys a component responds to.
# Kbd
Kbd renders the native `` element for keyboard input while applying Manti
typography, surface, radius, spacing, and elevation tokens.
The command symbol (`⌘`) automatically renders as `Ctrl` on non-Mac platforms.
Use separate Kbd elements for each key in a combination so assistive technology
and copied text preserve the shortcut structure.
## API
Kbd accepts every native `` attribute in addition to the props below.
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.1.3/
Summary: A centered ColorPicker slider thumb and an optional swatch-only trigger.
# v0.1.3
_Released 2026-07-01._
## Fixed
- **ColorPicker** — the hue and alpha slider thumbs now sit centered on the
track. They previously hung low because Zag positions the channel-slider thumb
with `top: 50%` but, unlike the area thumb, adds no centering transform; the
track also no longer clips the taller thumb.
## Added
- **ColorPicker** — a `showValueText` prop (default `true`). Set it to `false` to
show only the color swatch in the trigger, hiding the formatted value text
(e.g. `rgba(124, 58, 237, 1)`).
---
URL: https://manti.design/components/tabs/
Summary: Tabs renders items of value, label, content, icon and disabled in line, pill or soft variants, managing focus, arrow keys, selection and panels across sizes.
# Tabs
Pass items as `{ value, label, content, icon?, disabled? }`. The machine manages
focus, arrow keys, selection, and panels.
## Variants
Use `line`, `pill`, or `soft`.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.1.2/
Summary: A new Textarea multiline field, per-node TreeView icons, scrollable TimePicker columns, a tonal Listbox selection, and Combobox and TagsInput refinements.
# v0.1.2
_Released 2026-06-29._
## Added
- **Textarea** — a new multiline text field. It renders the shared `field` shell,
so label, hint/description, error/invalid state, sizes (`sm`/`md`/`lg`), and
focus-ring `tone` all match `TextField`. Adds `autoResize` to grow with its
content (bounded by `maxHeight`), `fullWidth`, and a `resize` affordance.
- **TreeView** — an `icon` render prop for per-node leading icons. It receives
the node and its live state, so the icon can react to expansion/selection
(e.g. folder/file icons).
## Changed
- **TimePicker** — its columns now scroll inside a Manti `ScrollArea`, and the
panel is wider so the hour/minute/second columns stay comfortable.
- **Listbox** — the selected item now gets a tonal background, making the current
selection easier to spot.
## Fixed
- **Combobox** — the selection now stays in sync with the typed text.
- **TagsInput** — refined the spacing of the item preview.
---
URL: https://manti.design/components/dialog/
Summary: Dialog is a modal panel opened from a trigger element, with title, description, a footer receiving close, sizes, focus trapping, dismissal and scroll locking.
# Dialog
Pass a React element as `trigger`, then provide `title`, `description`, and body
content. The machine manages focus, dismissal, and scroll locking.
## Footer actions
`footer` may be a function receiving `{ close }`.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.1.1/
Summary: A TanStack-backed DataTable, a categorized collapsible docs sidebar, the panel token rename, scrollable Combobox and Select listboxes, and overlay fixes.
# v0.1.1
_Released 2026-06-26._
## Breaking changes
- **Frosted-panel tokens renamed** from `--manti-glass-*` to `--manti-panel-*`
(e.g. `--manti-glass-tint` → `--manti-panel-tint`, `--manti-glass-border` →
`--manti-panel-border`). Update any custom CSS that referenced the old names.
## Added
- **DataTable** — a new data grid, and Manti's first component built on
**TanStack** rather than Zag.js. The framework-agnostic `@tanstack/table-core`
contract is re-exported through `@manti-ui/folds`, with the
`@tanstack/react-table` runtime in the React adapter. It supports:
- **Sorting** — click-to-sort headers (`sortable`) with `aria-sort` and a
direction arrow.
- **Filtering** — a global search box (`filterable`), composing `TextField`.
- **Pagination** — client-side (`paginated` / `pageSize`), composing
`Pagination`.
- **Selection** — a leading checkbox column (`selectable` /
`onSelectionChange`), composing `Checkbox`.
- Density sizes, sticky header, zebra striping, row hover, per-column alignment
via `meta.align`, and an optional toolbar `title`.
- **Checkbox** gains an `aria-label` prop for controls without a visible label.
- **Carousel** exposes a `slide-gap` component token
(`--manti-carousel-slide-gap`) for the space between slides.
## Changed
- **Combobox** and **Select** now scroll their listbox inside a Manti
`ScrollArea`, so long option lists stay tidy.
## Fixed
- **Combobox** and **Select** only mount their portal listbox while it is open.
- **Overlay panels** — floating panels, popovers and other portaled surfaces are
now opaque enough to keep the UI beneath them hidden and legible.
- **FileUpload** squares its delete trigger and renders each file's size.
## Docs
- The **component sidebar is now categorized** into Inputs, Buttons & Actions,
Navigation, Overlays, Feedback, Data Display, and Layout — and each category is
**collapsible**.
- A **"New" badge** marks freshly added components in the sidebar.
- A dedicated **Changelog** section (this page), newest release first.
- The **NavigationMenu** demo flyout no longer gets clipped inside the playground.
- Per-route **SEO**: titles, descriptions, canonical URLs, Open Graph / Twitter
cards, a sitemap, and robots.txt.
- Docs and **Storybook now ship from a single Netlify deploy** — Storybook lives
at [`/storybook`](/storybook/).
---
URL: https://manti.design/components/calendar/
Summary: Calendar is an inline month grid taking ISO date strings, with single or range selectionMode, a renderDay prop for per-day content, and a readOnly mode.
# Calendar
Calendar is an inline month surface. Use [DatePicker](/components/date-picker)
when selection should open from a compact field. Values are ISO date strings.
## Selection
Use `selectionMode="single"` or `"range"`. Controlled and uncontrolled values
are arrays of ISO dates.
## Day content
Use `renderDay(day)` for events or other day details. Pair it with `readOnly` for
a display-only calendar.
## API
## Styling
### Anatomy
Calendar's inner grid keeps `data-scope="date-picker"`. Scope grid overrides
under `[data-scope="calendar"]` to avoid changing DatePicker.
### Tokens
---
URL: https://manti.design/components/carousel/
Summary: Carousel renders a slides array with drag, keyboard navigation, snapping, arrows and page indicators, plus slidesPerPage for multi-item pages and loop.
# Carousel
Pass a `slides` array. The machine manages drag, keyboard navigation, snapping,
arrows, and page indicators.
## Several slides per page
Use `slidesPerPage` for multi-item pages and `loop` to wrap.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/tooltip/
Summary: Tooltip shows a short label on pointer hover or keyboard focus around a focusable trigger, with placement, delays, controlled open, and portalled rendering.
# Tooltip
Wrap a focusable trigger and pass `content`. The machine manages placement,
delays, focus, hover, and dismissal.
Set `interactive` only when the pointer must enter the tooltip content.
Use `placement`, controlled `open` state, and `portalled` when the trigger lives
inside overflow or stacking contexts. `portalContainer` targets a specific
portal host.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/changelog/v0.1.0/
Summary: The first public release of Manti UI — the design-token contract, the monochrome design signature, and the initial component set, published to npm.
# v0.1.0
_Released 2026-06-23._
The first public release of Manti UI — a framework-agnostic design system built on
[Zag.js](https://zagjs.com) behavior machines.
## Highlights
- **Framework-agnostic foundation.** Behavior lives in Zag.js machines; tokens and
CSS are framework-free. A React renderer ships today, with Vue, Svelte and Solid
able to reuse the same foundations.
- **Three-tier design tokens.** Primitive ramps → semantic roles & tones →
per-component tokens, themeable entirely from CSS variables (and bound to
Tailwind v4).
- **A full React component library**, with keyboard support, focus management and
screen-reader semantics owned by the machines.
- **This documentation site**, built end-to-end with Manti UI itself.
## Install
```bash
npm install @manti-ui/react @manti-ui/styles
```
See [Getting Started](/getting-started) to render your first component, or browse
the [Components](/components).
---
URL: https://manti.design/components/checkbox/
Summary: Checkbox is a boolean control with checked, unchecked and indeterminate states, defaultChecked for uncontrolled use, onCheckedChange, and sm to lg sizes.
# Checkbox
Use `defaultChecked` for uncontrolled state or `checked` with
`onCheckedChange` for controlled state. `indeterminate` shows a mixed value.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/foundations/
Summary: The foundations of Manti UI: the design token contract, color ramps and semantic roles, the type scale, motion levels, and the four-layer architecture.
# Foundations
Understand the visual language and system decisions behind Mantı UI before
adapting them to your product.
Looking for implementation steps? Continue with the
[Guides](/guides/plain-css).
---
URL: https://manti.design/components/clipboard/
Summary: Clipboard is a copy-to-clipboard field: pass the text as value and use timeout to control how long the copied confirmation state stays visible.
# Clipboard
Pass the text to copy as `value`. `timeout` controls how long the copied state
remains visible.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/foundations/design-signature/
Summary: The design signature of Manti UI: sleek monochrome panels, no gradients and no box shadows, with color reserved for semantic variants alone.
# Design signature
Manti UI aims to feel **smooth**: quiet surfaces, clear state changes, and
predictable interaction.
## Material
The default interface is cool, near-neutral, and monochrome. Color appears
through semantic variants instead of decoration.
Floating surfaces share one panel treatment:
- translucent surface tint;
- subtle border;
- blur when the browser and layout support it.
The signature surface
{/* An expression, not markdown: prose on its own lines inside a JSX element
is parsed as a markdown block and wrapped in a , which would nest
inside the
that Card.Description renders. A browser un-nests that
while parsing the prerendered HTML, breaking hydration for the route. */}
{'A rounded panel with a quiet border and clear surface contrast.'}
Use .manti-panel for application-owned menus, sheets, or command
palettes. Manti falls back to an opaque surface when blur is unavailable.
## Main controls
```css
.manti-app {
--manti-panel-tint: oklch(0.2 0.008 280 / 0.55);
--manti-panel-border: oklch(1 0 0 / 0.09);
--manti-panel-blur: blur(16px) saturate(160%);
}
```
For broader customization, continue to [Color & variants](/foundations/color-and-tones),
[Design tokens](/foundations/tokens), and [Motion](/foundations/motion).
---
URL: https://manti.design/components/collapsible/
Summary: Collapsible shows and hides a single region from a trigger, controlled with open and onOpenChange; indicator accepts false or a React node to replace it.
# Collapsible
Pass the button content as `trigger` and the revealed region as `children`. Use
`open` with `onOpenChange` to control it.
The default indicator follows state. Pass `indicator={false}` to hide it or a
React node to replace it.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/foundations/color-and-tones/
Summary: Manti UI color: ordered 1-12 primitive ramps, theme-aware semantic roles, the rest/hover/active interaction ladder, and the seven semantic variants.
# Color & variants
Manti UI separates fixed color ramps from the semantic roles components use.
## Primitive ramps
Six OKLCH ramps run from `1` (lightest) to `12` (darkest):
| Ramp | Purpose | Use it for |
| -------- | ----------- | ------------------------------------------------------ |
| `gray` | Neutral UI | Surfaces, borders, text, and secondary controls |
| `orange` | Primary | Main actions, selected states, and the product accent |
| `green` | Success | Positive feedback, completed states, and confirmations |
| `blue` | Information | Informational feedback, notices, and helpful context |
| `amber` | Warning | Caution, attention, and states that need review |
| `red` | Danger | Errors, destructive actions, and critical feedback |
Each stop is available as `--manti-{ramp}-{step}`. Component CSS should use
semantic tokens or variants instead of choosing a stop directly.
## Primitive scale contract
This mapping comes directly from `colorScaleRoles` in `@manti-ui/tokens`. Every
color ramp uses the same contract:
| Stop | Source role | Exact purpose |
| ---- | ---------------------------- | ------------------------------------------------- |
| `1` | `appBackground[0]` | Lighter page or panel background position |
| `2` | `appBackground[1]` | Next page or panel background position |
| `3` | `componentBackground.rest` | Resting component background |
| `4` | `componentBackground.hover` | Hovered component background |
| `5` | `componentBackground.active` | Active, pressed, or selected component background |
| `6` | `border.subtle` | Subtle borders and separators |
| `7` | `border.interactive` | Interactive borders |
| `8` | `border.strong` | Strong borders and focus chrome |
| `9` | `solid.rest` | Resting solid fill |
| `10` | `solid.hover` | Hovered solid fill |
| `11` | `text.lowContrast` | Supporting or lower-contrast text |
| `12` | `text.highContrast` | Primary or highest-contrast text |
This is the palette's intended role contract, not a promise that every component
reads the primitive stop literally. Components consume semantic tokens or
`--variant-*` roles, and `tokens.css` adapts them for theme and contrast.
The current `--variant-solid*` mappings are:
| Variant | Rest | Hover | Active |
| ------------------------------- | ------------------------ | ------------------------- | ------------------------- |
| `primary` | `orange-7` | theme-aware `color-mix()` | theme-aware `color-mix()` |
| `success`, `info`, and `danger` | matching hue at step `8` | theme-aware `color-mix()` | theme-aware `color-mix()` |
| `secondary` | `gray-11` / `gray-3` | `gray-10` / `gray-4` | `gray-9` / `gray-5` |
| `tertiary` and `outline` | semantic neutral value | semantic neutral value | semantic neutral value |
Values separated by `/` mean light theme / dark theme. These mappings deliberately
depart from the nominal `9 → 10` solid pair when contrast requires it.
Input-like controls are the main exception to the colored-border progression.
They use the neutral border at rest and hover, then introduce the variant color
at focus or open.
## Built-in variants
Manti ships seven variant palettes:
- `primary` — orange, highest emphasis;
- `secondary` — neutral soft surface;
- `success` — green feedback;
- `info` — blue feedback;
- `tertiary` — neutral ghost;
- `danger` — red feedback;
- `outline` — neutral bordered treatment.
Individual components may expose a subset. Alert supports `primary`,
`secondary`, `success`, `info`, and `danger`. Badge omits `tertiary`. Button also
adds `link`.
Every variant defines the same roles:
```text
--variant-solid
--variant-solid-hover
--variant-solid-active
--variant-on-solid
--variant-soft-bg
--variant-soft-bg-hover
--variant-soft-bg-active
--variant-soft-text
--variant-border
--variant-text
--variant-ring
```
## Custom variant
Components typed with `MantiVariant` accept custom strings:
```css
[data-variant='brand'] {
--variant-solid: var(--manti-blue-9);
--variant-solid-hover: var(--manti-blue-10);
--variant-solid-active: color-mix(in oklab, var(--manti-blue-10) 88%, black);
--variant-on-solid: var(--manti-text-on-accent);
--variant-soft-bg: var(--manti-blue-2);
--variant-soft-bg-hover: var(--manti-blue-3);
--variant-soft-bg-active: var(--manti-blue-4);
--variant-soft-text: var(--manti-blue-9);
--variant-border: var(--manti-blue-7);
--variant-text: var(--manti-blue-9);
--variant-ring: var(--manti-blue-8);
}
```
```tsx
Save
```
## Contributor checks
Use semantic roles in component CSS, keep foregrounds explicit, and verify both
themes:
```bash
pnpm check:color-scale
pnpm --filter @manti-ui/styles check:contrast
pnpm --filter @manti-ui/styles build
```
---
URL: https://manti.design/components/color-picker/
Summary: ColorPicker accepts hex, rgba, hsla, hsba and oklch strings and opens an area, channel sliders, format tabs, an eyedropper and an editable copy field.
# ColorPicker
ColorPicker accepts `hex`, `rgba`, `hsla`, `hsba`, and `oklch` CSS color strings.
Its panel includes a color-space area, channel sliders, format tabs, an
eyedropper, and an editable copy field. `format` controls the output string;
`colorSpace="oklch"` keeps palette interaction in native OKLCH channels, so
changing the area or sliders does not round-trip through sRGB. `defaultFormat`
sets the initial format when `format` is uncontrolled. Use `formats` to limit
the copy tabs; the selected format is included automatically.
## Sizes
`size` sets the trigger's height, padding, type, and swatch. The panel keeps its
own canvas; its channel controls use the same size channel as the trigger.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/combobox/
Summary: Combobox is a typeahead select that filters an options array by label, supports single or multiple selection, a fill variant, and size-matched popup rows.
# Combobox
Pass options as `{ value, label, disabled? }`. Filtering runs by label while the
Zag.js machine manages focus, keyboard navigation, and selection.
## Appearance
Use `variant="fill"` for a neutral filled control. `size` uses the shared size
scale: the portalled list follows the control, so a `sm` Combobox filters into
`sm` rows.
## Multiple selection
Set `multiple` to collect several values.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/foundations/tokens/
Summary: The three token tiers of Manti UI - primitive ramps, theme-aware semantic roles, and public --manti-{component}-{property} override tokens.
# Design tokens
Every visual value in Manti UI comes from the `@manti-ui/tokens` contract.
## Three tiers
### 1. Primitives
Fixed color ramps and scale values for radius, control height, spacing,
typography, elevation, and motion.
These values are generated into `@manti-ui/styles`. Contributors edit
`packages/tokens/src/index.ts`, then run `pnpm gen:tokens`.
### 2. Semantic roles and variants
Purpose-based values such as:
```text
--manti-bg
--manti-surface
--manti-border
--manti-text
--manti-text-muted
--manti-focus-ring
--variant-solid
--variant-soft-bg
--variant-ring
```
Use this tier for system-wide theming.
### 3. Component tokens
Public per-component overrides named
`--manti-{component}-{property}`:
```css
:root {
--manti-button-radius: var(--manti-radius-full);
--manti-switch-track-width: 3rem;
}
```
Use a component token only when that component should intentionally differ.
Derived geometry stays private as `--_*`.
## Scales
- Radius: `--manti-radius-xs` through `--manti-radius-2xl`, plus `full`
- Control height: `--manti-control-height-sm | md | lg`
- Spacing: `--manti-space-0` through `--manti-space-16`
- Type: `--manti-text-xs` through `--manti-text-5xl`
- Weight: `--manti-weight-regular | medium | semibold | bold`
- Motion: `--manti-duration-*` and `--manti-ease-*`
`--manti-radius-factor` rescales the radius ramp. Use `data-radius="none"`,
`"sharp"`, `"default"`, `"round"`, or `"pill"` for presets. `none` is the
square mode; the other four are positive shape profiles.
## Override scope
Custom properties can be changed globally or on a subtree:
```css
.marketing {
--manti-surface: var(--manti-surface-raised);
--manti-radius-factor: 1.4;
}
```
See [Theming with tokens](/guides/theming-tokens) for the decision guide and
[plain CSS](/guides/plain-css) for selector overrides.
---
URL: https://manti.design/components/context-menu/
Summary: ContextMenu opens on right-click or long press over a wrapped region, taking Menu-style items with recursive submenu entries and a size-driven row rhythm.
# ContextMenu
Wrap a region in `children` and pass Menu-style `items`. ContextMenu uses the
same Zag.js machine and styling scope as [Menu](/components/menu).
Nested items use the same recursive `{ type: 'submenu', value, label, items }`
shape as Menu. No separate nested context-menu component is required.
## Sizes
`size` sets the panel's row rhythm, matching the scale every other control uses.
Submenus inherit it.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/foundations/motion/
Summary: Motion in Manti UI: the data-motion levels, duration and easing tokens, and how every animation collapses under a reduced-motion preference.
# Motion
Set `data-motion` on any container:
```html
…
```
| Value | Result |
| --------- | ----------------------------------- |
| `default` | Standard component motion |
| `none` | Decorative Manti motion is removed |
| `full` | Expressive spring and bounce motion |
Nested values override their ancestor. The Spinner keeps its functional
rotation in `none`.
## Tokens
Durations:
```text
--manti-duration-fast
--manti-duration-base
--manti-duration-slow
--manti-duration-slower
```
Easing:
```text
--manti-ease-smooth
--manti-ease-soft
--manti-ease-spring
--manti-ease-bounce
```
```css
.panel {
transition:
transform var(--manti-duration-base) var(--manti-ease-smooth),
opacity var(--manti-duration-fast) var(--manti-ease-soft);
}
```
`prefers-reduced-motion: reduce` overrides every tier, including `full`.
---
URL: https://manti.design/components/date-picker/
Summary: DatePicker is a date field using ISO YYYY-MM-DD strings, with a popover calendar grid, month navigation, keyboard selection and a range selectionMode.
# DatePicker
DatePicker uses ISO strings (`YYYY-MM-DD`). The Zag.js machine manages the
popover, calendar grid, month navigation, and keyboard selection.
## Sizes
`size` sets the control's height, padding, and type, and the portalled calendar
follows it down to the day cells.
## Range
Set `selectionMode="range"` and provide two dates for a controlled or default
value.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/foundations/architecture/
Summary: How Manti UI separates its four layers - design tokens, layered CSS, framework-agnostic Zag.js behavior, and the thin React renderer - and why.
# Architecture
Manti UI splits each concern into one package:
| Package | Responsibility |
| ------------------ | ------------------------------------------- |
| `@manti-ui/tokens` | Typed design-token contract |
| `@manti-ui/styles` | Layered CSS for public component anatomy |
| `@manti-ui/folds` | Zag.js adapters and Manti-authored behavior |
| `@manti-ui/react` | React components and hooks |
Only the React renderer is available today. Tokens, CSS, and behavior remain
framework-agnostic.
## Component flow
```text
behavior machine
↓
React adapter
↓
data-scope / data-part / data-state
↓
shared CSS and tokens
```
Behavioral components connect a machine and render its prop getters:
```tsx
const service = useMachine(component.machine, { id: useId(), ...props });
const api = component.connect(service, normalizeProps);
return
;
```
Static components render the same anatomy without a machine.
## Public styling contract
Target documented `data-scope`, `data-part`, variant, size, and state
attributes. Class names and DOM between documented parts are private.
```html
…
```
`@manti-ui/react` has no CSS side effects. Import a stylesheet explicitly so the
app controls cascade order or can run headlessly.
---
URL: https://manti.design/components/drawer/
Summary: Drawer is a modal panel anchored to the left, right, top or bottom edge, reusing Dialog focus trapping, scroll locking and dismissal; size sets width or height.
# Drawer
Drawer reuses Dialog behavior for focus, scroll locking, and dismissal. Pass a
React element as `trigger` and content as `children`.
## Placement and size
`placement` is `left`, `right`, `top`, or `bottom`. `size` controls width for
left/right and height for top/bottom.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/editable/
Summary: Editable is inline text that switches between preview and edit modes, with activationMode controlling how editing starts and submitMode how a value commits.
# Editable
`activationMode` controls how editing starts. `submitMode` controls how the
value is committed.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/file-upload/
Summary: FileUpload is a dropzone with a browse button and removable file rows, validating selection through the accept, maxFiles and maxFileSize props.
# FileUpload
Drop files or use the browse button. Accepted files appear as removable rows.
## Restrictions
Use `accept`, `maxFiles`, and `maxFileSize` to validate selection.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/floating-panel/
Summary: FloatingPanel is a window-style surface opened from a trigger that users can drag, resize, minimize, maximize and restore, with its own title and body.
# FloatingPanel
Pass a `trigger`, title, and body. The panel can be dragged, resized, minimized,
maximized, and restored.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/guides/themes/
Summary: Adopt a shipped Manti UI theme with a single import, or scope several themes on one page, without touching a component's own styles.
# Theme presets
Manti ships six themes. Five of them are a stylesheet you import after
`index.css`; the sixth is what you already have.
```js
import '@manti-ui/styles/index.css';
import '@manti-ui/styles/themes/ocean.css';
```
That is the whole adoption cost. Every component re-skins: the variant palettes,
the neutral hue, the progress fill, and the text selection.
## What a preset moves
A preset is a palette and nothing else. Each one expands its base colors into
the full `--variant-*` vocabulary, re-points `--manti-accent-fill` and
`--manti-selection-*` (the two branded roles no `[data-variant]` block can
reach), and sets `--manti-cool-hue`, the single hue behind every gray, surface,
border and text role.
Shape, density and type are deliberately out. Those are product decisions, and a
theme you adopt for its color must not quietly resize your controls or round
your corners: swap Ocean for Forest and only the color changes. Retune the
radius ramp with `--manti-radius-factor`, or the whole shape profile with
`data-radius`, as its own decision.
The definitions live in `presets` in `@manti-ui/tokens`, and
`packages/styles/scripts/gen-preset-css.mjs` generates the stylesheets from
them. The contrast floor and the interaction progression are checked per preset
in the styles build, so a theme that fails either never ships.
## Override on top of one
Theme files sit in `@layer manti.theme`, above the token defaults and below
anything unlayered. Adopt a preset and retune a role on top of it:
```css
@import '@manti-ui/styles/index.css';
@import '@manti-ui/styles/themes/forest.css';
:root {
--manti-cool-hue: 280;
}
```
Import order between the two stylesheets does not matter — the layer decides.
## More than one theme on a page
For a gallery, a themed section, or a preview pane, import the scoped file once
and set `data-manti-theme` on any container:
```js
import '@manti-ui/styles/themes.css';
```
```html
```
Nested scopes re-resolve the neutral ramp and every surface, border and text
role locally, so a scoped preset looks the same as its `:root` twin.
`data-manti-theme` is independent of `data-theme` — light and dark still follow
the OS or whatever you force.
## When a preset is not enough
Reach for [theming with tokens](/guides/theming-tokens) for a targeted change,
or the [Theme Studio](https://studio.manti.design) to tune every role on a live
product surface and export the result.
---
URL: https://manti.design/components/hover-card/
Summary: HoverCard opens a rich preview from a trigger element on pointer hover or keyboard focus, with the machine managing open delays, focus behavior and placement.
# HoverCard
Pass a React element as `trigger` and the preview as `children`. The machine
manages delays, focus behavior, and placement.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/input/
Summary: Input is a labeled native input wiring helper text, error text, aria-describedby and aria-invalid, with left and right slots, sizes and password controls.
# Input
Input accepts native input attributes and wires label, helper text, error text,
`aria-describedby`, and `aria-invalid`.
## Left and right content
Use `left` and `right` to place text or any React node inside the input frame.
Both slots share the control's focus, invalid, filled, and disabled states. This
makes them suitable for units, currency symbols, icons, badges, shortcuts, or
small actions.
Spacing follows the kind of content. A text slot reads as part of the value and
keeps the control's `padding-x`. Anything else is an element that paints its own
box, so the control hands that side's padding to the slot, which insets it by
`--manti-field-addon-padding-x` instead. Buttons, icons, and shortcut keys land
near the frame edge without stacking two paddings.
Give icon-only interactive content its own accessible label. `left` and `right`
replace the deprecated `leadingAddon` and `trailingAddon` names; the old props
remain available for backwards compatibility.
## Appearance and state
Use `variant="fill"` for a neutral filled control. `size`, `error`, `disabled`,
and native attributes work across both appearances.
`requiredIndicator={null}` keeps native required semantics without adding a
visible marker. When another product shell owns the visible focus treatment,
set `focusRing="none"`. The forwarded ref always targets the native input.
## Passwords
`type="password"` adds a reveal button and Caps Lock warning. Control them with
the password-specific props; those props are ignored for other input types.
## API
## Styling
### Anatomy
Input and [Textarea](/components/textarea) share the `field` scope.
### Tokens
---
URL: https://manti.design/guides/plain-css/
Summary: Restyle Manti UI with ordinary CSS: override component tokens, target the stable data-scope and data-part anatomy, and never fork a component.
# Customizing with plain CSS
## Import order
Import Manti first and your overrides second:
```ts
import '@manti-ui/styles/index.css';
import './theme.css';
```
Manti CSS is layered. Ordinary unlayered CSS wins without `!important`.
## Prefer tokens
Use semantic tokens for changes that should affect the system:
```css
:root {
--manti-bg: light-dark(#fafafb, #0c0c10);
--manti-surface: light-dark(#ffffff, #15151b);
--manti-text: light-dark(#16161a, #f4f4f6);
--manti-border: light-dark(#e6e6ea, #2a2a33);
--manti-radius-factor: 0.8;
}
```
Use a component token for one intentional exception:
```css
:root {
--manti-button-radius: var(--manti-radius-full);
}
```
## Target anatomy
When tokens are not enough, use public data attributes:
```css
[data-scope='button'][data-part='root'] {
letter-spacing: 0.02em;
}
[data-scope='button'][data-part='root'][data-variant='primary']:hover {
translate: 0 -1px;
}
```
Stable selectors include:
- `data-scope` — component name;
- `data-part` — anatomy part;
- `data-variant` and `data-size`;
- documented state attributes such as `data-state` or `data-loading`.
Class names, private `--_*` variables, and undocumented DOM are not public API.
## Add a variant
```css
[data-variant='brand'] {
--variant-solid: var(--manti-blue-9);
--variant-solid-hover: var(--manti-blue-10);
--variant-solid-active: color-mix(in oklab, var(--manti-blue-10) 88%, black);
--variant-on-solid: var(--manti-text-on-accent);
--variant-soft-bg: var(--manti-blue-2);
--variant-soft-bg-hover: var(--manti-blue-3);
--variant-soft-bg-active: var(--manti-blue-4);
--variant-soft-text: var(--manti-blue-9);
--variant-border: var(--manti-blue-7);
--variant-text: var(--manti-blue-9);
--variant-ring: var(--manti-blue-8);
}
```
```tsx
Save
```
Continue to [Theming with tokens](/guides/theming-tokens) for token-selection
guidance or [Tailwind v4](/guides/tailwind) for utility integration.
---
URL: https://manti.design/components/listbox/
Summary: Listbox is a selectable list of value and label options with roving focus, typeahead, single or multiple selectionMode, and sizes shared with Select and Menu.
# Listbox
Pass options as `{ value, label, disabled? }`. The machine manages roving focus,
typeahead, and selection.
## Sizes
`size` sets the row rhythm: type, padding, and icon size. It is the same scale
Select, Combobox, and Menu use, so a list next to a `sm` control reads at the
same size.
## Multiple selection
Set `selectionMode="multiple"` and use array values.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/guides/theming-tokens/
Summary: Which Manti UI token to override: primitive ramps, semantic roles, the variant vocabulary, or a public per-component token - and when each applies.
# Theming with tokens
Use the broadest token that matches the design decision.
Before writing any of this, check whether a [shipped preset](/guides/themes)
already gets you there — adopting one is a single import. Reach for the tokens
below to retune a preset, or to build a theme none of them cover.
Prefer to see it before you write it? The
[Theme Studio](https://studio.manti.design) tunes these same tokens live on a
full product surface, then hands the result back as CSS, as an agent prompt, or
as a shareable link.
| Need | Use |
| --------------------------------------- | --------------- |
| Replace a palette or scale | Primitive token |
| Change a system-wide purpose | Semantic token |
| Change color and emphasis | Variant roles |
| Make one component intentionally differ | Component token |
## Start with semantic roles
```css
:root {
--manti-bg: light-dark(#fafafb, #0c0c10);
--manti-surface: light-dark(#ffffff, #15151b);
--manti-surface-raised: light-dark(#ffffff, #1b1b22);
--manti-text: light-dark(#16161a, #f4f4f6);
--manti-text-muted: light-dark(#5c5c66, #b6b6c0);
--manti-border: light-dark(#e6e6ea, #2a2a33);
--manti-radius-factor: 0.8;
--manti-duration-base: 180ms;
}
```
Keep theme-aware colors in `light-dark(light, dark)` form.
## Use variants for color
Remap a built-in variant on the whole app or within a subtree:
```css
.marketing [data-variant='primary'] {
--variant-solid: var(--manti-blue-9);
--variant-solid-hover: var(--manti-blue-10);
--variant-ring: var(--manti-blue-8);
}
```
See [Color & variants](/foundations/color-and-tones) for the full role list.
## Use component tokens for exceptions
```css
:root {
--manti-button-radius: var(--manti-radius-full);
}
```
If the same override appears on several components, move it to a semantic token
instead. Do not override private `--_*` variables.
## Retune a size step
`sm | md | lg` is one shared rhythm. A control and the surface it opens resolve
the same `--manti-size-*` channel, so a `sm` Select opens a `sm` listbox and a
`lg` Menu lays out `lg` rows. Popups are portalled, so each adapter re-stamps
`data-size` on its positioner rather than relying on inheritance.
Retune a step once and every control and popup on it follows:
```css
[data-size='sm'] {
--manti-size-item-padding-y: 0.125rem;
--manti-size-text: 0.8125rem;
}
```
The channel carries `text`, `text-sub`, `icon`, `control-height`,
`control-padding-x`, `panel-padding`, `panel-gap`, `item-padding-y`,
`item-padding-x`, `item-gap`, `item-radius`, and `cell`. Every component token
above defaults to one of them, so a per-component override still wins.
Continue to [plain CSS](/guides/plain-css) for anatomy selectors or
[Tailwind](/guides/tailwind) for utility integration.
---
URL: https://manti.design/components/marquee/
Summary: Marquee loops children in a seamless CSS animation running left, right, up or down, hides the duplicate from assistive tech, and stops under reduced motion.
# Marquee
Marquee duplicates `children` for a seamless CSS loop and hides the duplicate
from assistive technology. It stops under reduced motion.
## Direction
Use `left`, `right`, `up`, or `down`. Vertical marquees need a bounded height.
`speed` is the duration of one pass.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/guides/tailwind/
Summary: Use Manti UI with Tailwind CSS v4: import Manti first so utilities win, then bridge the --manti-* tokens into Tailwind's theme variables.
# Using with Tailwind v4
## Styled components
Import Manti before Tailwind:
```css
@import '@manti-ui/styles/tailwind.css';
@import 'tailwindcss';
```
The order keeps Tailwind utilities above Manti component styles:
```tsx
Save
```
If Tailwind is imported first, utility overrides may lose to the Manti layer.
## Theme bridge
The bridge maps Manti tokens to Tailwind v4 theme namespaces:
| Utility | Uses |
| ------------------------------- | -------------------------- |
| `bg-surface`, `text-text-muted` | Semantic roles |
| `bg-orange-500`, `text-red-700` | Primitive ramps |
| `bg-primary-600` | Semantic ramp aliases |
| `text-lg`, `font-semibold` | Typography |
| `rounded-lg` | Radius |
| `p-4`, `gap-2`, `h-control-md` | Spacing and control height |
| `ease-spring` | Motion |
Utilities resolve to `var(--manti-*)` at runtime, so token overrides and
`data-theme` changes continue to work.
```css
:root {
--manti-radius-factor: 0.8;
--manti-surface: light-dark(#ffffff, #15151b);
}
```
## Headless use
Skip component CSS and keep only tokens plus the theme bridge:
```css
@import '@manti-ui/styles/tokens.css';
@import '@manti-ui/styles/tailwind-theme.css';
@import 'tailwindcss';
```
Then style public state attributes directly:
```tsx
Save
```
Tailwind v3 can reference `var(--manti-*)` from its config, but the `@theme`
bridge is v4-only.
---
URL: https://manti.design/components/menu/
Summary: Menu is a floating command list with actions, checkbox and radio items, groups, separators, shortcut hints and nested submenus, driven by items and onSelect.
# Menu
Menu displays a floating list of actions or choices. Pass the trigger element,
describe the rows with `items`, and handle a selected action with `onSelect`.
Manti manages positioning, focus, keyboard navigation, and dismissal.
Use [Popover](/components/popover) instead when the floating panel contains form
controls or arbitrary interactive content.
## Basic usage
Start with an array of commands. Each command needs a unique `value` and a
visible `label`. `onSelect` receives the selected value.
Add `shortcut` to display a keyboard hint. It only displays the hint; register
the actual shortcut separately with `useShortcut`.
## Sizes
`size` sets the panel's row rhythm: type, padding, and icon size. It matches the
scale every other control uses, so a `sm` trigger can open a `sm` menu. Submenus
inherit the size of the menu that opened them.
## Groups and item states
Use a group to label related actions and a separator to divide different sets.
An item can also be disabled or use `tone: 'danger'` for a destructive action.
Useful item properties:
- `icon`: leading visual affordance;
- `shortcut`: trailing keyboard hint;
- `disabled`: visible but unavailable action;
- `tone: 'danger'`: destructive action styling;
- `onSelect`: handler for only that item.
## Checkable items
Checkbox items represent independent settings. Radio items represent one choice
from a set. Both are controlled: pass `checked` and update application state in
`onCheckedChange`.
Set `closeOnSelect: false` when a choice should leave the menu open. Radio
exclusivity comes from application state rather than the group itself.
## Submenus
A submenu is another `items` array nested inside an item. No separate submenu
component is required.
Submenus may contain more submenus. Keep every `value` unique across the whole
tree. Selecting a leaf closes the complete tree; placement and keyboard routing
are handled automatically. If the submenu label is not plain text, provide
`ariaLabel`.
## Item reference
`MenuItem[]` accepts these shapes:
| Shape | Use for |
| ------------------------------------------ | ------------------------- |
| `{ value, label }` | Action |
| `{ type: 'checkbox', … }` | Independent choice |
| `{ type: 'radio', … }` | One choice from a set |
| `{ type: 'group', label, items }` | Labelled group |
| `{ type: 'separator' }` | Divider |
| `{ type: 'submenu', value, label, items }` | Another level of commands |
## State and events
The root `onSelect` observes every selectable item, including leaves inside a
submenu. An item's own `onSelect` runs after the root handler.
The root menu is uncontrolled by default. Use `open` with `onOpenChange` only
when application state must own whether it is open:
```tsx
Account}
items={items}
/>
```
`itemProps` adds DOM props to one item. `getItemProps` applies props to every
action and submenu trigger. Prefer semantic properties such as `disabled` and
`tone` before reaching for these lower-level escape hatches.
## Menu or Popover?
Use Menu when every row is an action, checkbox, radio, or submenu trigger. Use
Popover for ToggleGroup, Input, Select, Slider, forms, explanatory content, or
a mixture of controls and commands.
## API
## Styling
### Anatomy
### Tokens
---
# Working with AI
URL: https://manti.design/working-with-ai/
Summary: Give coding agents what they need to write correct Manti UI code: the llms.txt project guide, a ready prompt, and the rules agents get wrong.
Manti UI publishes a machine-readable project guide at
[manti.design/llms.txt](https://manti.design/llms.txt). It covers installation,
public APIs, components, tokens, styling rules, accessibility, and verification.
When an agent needs the prose rather than the map, the whole documentation
corpus is served as one plain-text file at
[manti.design/llms-full.txt](https://manti.design/llms-full.txt), so it can be
read in a single fetch instead of by crawling 93 pages.
Give the following prompt to a coding agent. Replace the final task placeholder
with what you want it to build.
## Copy this prompt
```text
Build the following React interface with Manti UI.
Before writing code, read https://manti.design/llms.txt and treat it as the
source of truth for Manti UI installation, components, public APIs, styling,
accessibility, and verification. Follow the relevant component documentation
linked from that file and verify real exported props and types instead of
inventing APIs.
After implementation, run the project's available validation commands and
summarize the changes and assumptions.
Task:
[Describe the interface or change you want the agent to implement.]
```
## Keep the reference available
Agents work best when they can access the URL directly. If network access is
blocked, download [llms.txt](https://manti.design/llms.txt) and add it to the
agent's context with your task.
---
URL: https://manti.design/components/navigation-menu/
Summary: NavigationMenu builds site navigation from items of value, label and links, opening keyboard-accessible dropdowns of href, label and description entries.
# NavigationMenu
Pass top-level items as `{ value, label, links }`. Links use
`{ href, label, description? }`.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/number-input/
Summary: NumberInput is a numeric field with keyboard and button stepping, constrained by min, max and step; onValueChange reports the string and parsed number.
# NumberInput
Use `min`, `max`, and `step` to constrain the value. `onValueChange` reports the
string value and parsed number.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/guides/integration/
Summary: Integrate Manti UI with an existing codebase: global resets, focus shells, dense layouts, native form submission, and testing against the anatomy.
# Application integration
## Cascade layers and application resets
Manti styles live in cascade layers. Unlayered application CSS wins regardless
of selector specificity, so a broad reset such as `button { padding: 0 }` can
erase the geometry of Button, ToggleGroup, Menu, and other button-backed
anatomies.
Import Manti before application CSS and keep native resets away from Manti
parts:
```css
button:not([data-scope][data-part]) {
padding: 0;
}
```
When overriding anatomy, prefer low-specificity selectors:
```css
:where([data-scope='button'][data-part='root']).compact-action {
--manti-button-height: var(--app-compact-control-height);
--manti-button-padding-x: var(--app-compact-control-padding);
}
```
Component variables define control geometry. Setting only `height` does not
override a component's token-backed `min-height`.
## Focus ownership
Input and Textarea put the visible focus treatment on the outer `control` part;
the native input is intentionally outline-free. If an existing search shell or
composite widget already paints focus, use `focusRing="none"` and keep one
visible owner:
```tsx
```
Do not remove both focus indicators. Global `input:focus-visible` rules should
either exclude Manti field inputs or be placed in a controlled layer.
## Inline SVG
Manti's reset makes SVG replaced media block-level. Wrap application icons or
restore inline flow for text-adjacent SVG:
```css
.app-inline-icon {
display: inline-block;
vertical-align: middle;
}
```
Button's `leadingIcon` and `trailingIcon` slots already render inside inline-flex
anatomy parts.
## Vitest and jsdom
Zag/Floating UI components expect `PointerEvent` and `ResizeObserver`. Add small
test-environment shims when jsdom does not provide them:
```ts
class ResizeObserverMock implements ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
}
globalThis.ResizeObserver ??= ResizeObserverMock;
globalThis.PointerEvent ??= MouseEvent as typeof PointerEvent;
```
Test pointer, keyboard, and direct click activation independently for menus and
other composite controls.
## Native forms
Manti fields compose with the platform form element; a state-owning Form
primitive is not required:
```tsx
```
Use `requiredIndicator={null}` when native required semantics should remain
without a visual marker.
## Combined local date and time
For a single native local datetime value, Input remains the smallest contract:
```tsx
```
When product requirements need separate DatePicker and TimePicker surfaces,
place both under one visible field label and combine their values in application
state. Keep one accessible group name and one validation message.
---
URL: https://manti.design/components/pagination/
Summary: Pagination renders page buttons with ellipses from a total count and pageSize, with siblingCount for nearby pages, sizes, and controlled or uncontrolled state.
# Pagination
`count` is the total item count and `pageSize` is the number per page.
`siblingCount` controls nearby page buttons.
## Many pages
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/pin-input/
Summary: PinInput is a segmented code field set by length and type, handling focus movement, paste, completion and form behavior, with a mask option and sizes.
# PinInput
Set `length` and `type`. The machine manages focus, paste, completion, and form
behavior.
## Masking
Set `mask` for secret values.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/popover/
Summary: Popover is a floating panel anchored to a trigger element, with a placement prop that flips when space runs out and an optional internal close button.
# Popover
Pass a React element as `trigger` and the panel body as `children`. The machine
manages placement, focus, and dismissal.
## Placement
`placement` anchors the panel to a side of the trigger, optionally aligned to its
start or end edge. It defaults to `bottom`, and the machine flips the panel when
there is not enough room on the requested side.
## Close button
Set `showCloseButton` to add an internal dismiss control.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/progress/
Summary: Progress shows determinate or indeterminate completion as a linear bar or a circular ring, with sizes; omit value for the indeterminate state.
# Progress
The default `linear` view fills a horizontal track. Omit `value` for
indeterminate progress.
## Circular
Use `variant="circular"` for a ring.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/reference/zag-coverage/
Summary: Which Zag.js machines Manti UI has adapted, which are still to come, and which were built and then shelved, with the reason for each.
# Zag.js coverage
Manti UI adapts Zag.js machines through `@manti-ui/folds`. React components
connect those machines and render the public anatomy; CSS owns appearance.
```tsx
const service = useMachine(component.machine, { id: useId(), ...props });
const api = component.connect(service, normalizeProps);
```
## Status
✅ shipped · ⬜ not implemented · 📦 built, then shelved
| Area | Components |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Inline behavior | ✅ Toggle, Switch, Checkbox, RadioGroup, Collapsible, Accordion, Tabs, Tooltip |
| Overlays | ✅ Dialog, Popover, HoverCard, Menu, Toast |
| Form inputs | ✅ NumberInput, PinInput, Slider, TagsInput, Editable, ToggleGroup |
| Selection | ✅ Select, Combobox, Listbox, TreeView, Pagination |
| Display and media | ✅ Avatar, Progress, RatingGroup, Carousel, Clipboard, FileUpload, SignaturePad · 📦 QrCode |
| Date and advanced | ✅ DatePicker, TimePicker, Steps, Tour, Splitter, ColorPicker, NavigationMenu, FloatingPanel · 📦 Timer · ⬜ AngleSlider |
## Reused machines
Some components reuse an existing adapter:
| Component | Machine |
| ---------------- | ---------- |
| Calendar | DatePicker |
| ContextMenu | Menu |
| Drawer | Dialog |
| SegmentedControl | RadioGroup |
Manti also authors framework-agnostic behavior for Shortcut, Swipe, and
DataTable. Marquee and ScrollArea are Manti components without Zag machines.
Shelved source remains under `backlog/` and ships in no package. See the
[component catalog](/components) for currently available React components.
---
URL: https://manti.design/components/radio-group/
Summary: RadioGroup is a single-choice group of value and label options with arrow keys, roving focus and form behavior, in a vertical or horizontal layout.
# RadioGroup
Pass options as `{ value, label, disabled? }`. The machine manages arrow keys,
roving focus, selection, and form behavior.
## Horizontal layout
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/rating-group/
Summary: RatingGroup is a star rating set by count, with keyboard input, hover preview, optional half values, form behavior, and size and variant options.
# RatingGroup
Set the star `count`, value, size, and variant. The machine manages keyboard
input, hover preview, and form behavior.
## Half values
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/select/
Summary: Select is a listbox control taking value and label options with string array values for single or multiple selection, a fill variant, and size-matched rows.
# Select
Pass options as `{ value, label, disabled? }`. Values are string arrays for both
single and multiple selection.
## Appearance
Use `variant="fill"` for a neutral filled trigger. `size` uses the shared size
scale: the portalled listbox follows the trigger, so a `sm` Select opens `sm`
rows.
## Multiple selection
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/signature-pad/
Summary: SignaturePad is a pointer and touch drawing surface that records paths as controlled or uncontrolled state, with a clear button that resets the canvas.
# SignaturePad
The machine records drawn paths. Use controlled or uncontrolled `paths`; the
clear button resets the surface.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/slider/
Summary: Slider is a value selector driven by min, max and step, with pointer dragging, keyboard steps, form state, two values for a range, and labeled marks.
# Slider
Set `min`, `max`, and `step`. The machine manages pointer dragging, keyboard
steps, and form state.
## Range and marks
Pass two values for a range. Add `marks` for labeled positions.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/spinner/
Summary: Spinner is an indeterminate loading indicator that inherits currentColor in sm, md and lg sizes; set label when no visible loading text accompanies it.
# Spinner
Spinner inherits `currentColor` and exposes `sm`, `md`, and `lg` sizes. Set
`label` when it is not accompanied by visible loading text.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/splitter/
Summary: Splitter creates resizable panes from a panels array with default percentages, handling resize math, keyboard controls and panel constraints for two or more.
# Splitter
Pass a `panels` array and matching default percentages. The machine manages
resize math, keyboard controls, and panel constraints.
## Several panels
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/steps/
Summary: Steps is a multi-step flow from items of title, description and content, tracking the active step with built-in controls, in vertical or horizontal layout.
# Steps
Pass items as `{ title, description, content }`. The machine tracks the active
step and built-in controls move through the flow.
## Vertical layout
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/scroll-area/
Summary: ScrollArea is a bounded viewport with draggable theme-aware scrollbars, a type prop for auto, hover or always visibility, and vertical, horizontal or both axes.
# ScrollArea
Give the root a bounded height or width. `type` controls scrollbar visibility:
`auto`, `hover`, or `always`.
## Orientation
Use `vertical`, `horizontal`, or `both`.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/tags-input/
Summary: TagsInput is multi-value text entry where Enter adds a tag and Backspace removes the last, with editable and removable tags plus max, invalid and readOnly.
# TagsInput
Press Enter to add a tag and Backspace to remove the last one. The machine
manages editing, navigation, and hidden form values.
## State and limits
Use `max`, `invalid`, `disabled`, `readOnly`, and `required` as needed.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/textarea/
Summary: Textarea is a labeled native textarea wiring helper text, error text and ARIA relationships, with a fill variant, autoResize, maxHeight and focusRing controls.
# Textarea
Textarea accepts native attributes and wires label, helper text, error text, and
ARIA relationships.
## Appearance and state
Use `variant="fill"` for a neutral filled control. Set `autoResize` to grow with
content and `maxHeight` to cap it.
`requiredIndicator={null}` hides only the visual marker. Use
`focusRing="none"` when an outer product shell owns focus styling.
## API
## Styling
### Anatomy
Textarea and [Input](/components/input) share the `field` scope.
### Tokens
---
URL: https://manti.design/components/time-picker/
Summary: TimePicker is a time field opening a floating panel of hour, minute and period columns, with parsing, keyboard navigation, and a size the panel inherits.
# TimePicker
The machine manages parsing, the floating panel, and keyboard navigation across
time columns.
## Sizes
`size` sets the control's height, padding, and type, and the portalled panel
follows it down to the hour and minute cells.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/toast/
Summary: Toast sends transient notifications imperatively: create a toaster and Toaster host once with createToaster, then call semantic types with swipe dismissal.
# Toast
Create a store and host once, then send notifications from anywhere:
```tsx
const { toaster, Toaster } = createToaster();
function App() {
return ;
}
toaster.success({ title: 'Saved' });
```
## API
The table describes `createToaster(options)`.
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/toggle/
Summary: Toggle is a pressable two-state button using defaultPressed for uncontrolled state or pressed with onPressedChange when application state owns the value.
# Toggle
Use `defaultPressed` for uncontrolled state or `pressed` with
`onPressedChange` for controlled state.
## Controlled state
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/toggle-group/
Summary: ToggleGroup is a set of pressed buttons with roving focus and arrow keys, typed by type=single for a string value or type=multiple for a string array.
# ToggleGroup
Pass items as `{ value, label, disabled? }`. The machine manages roving focus,
arrow keys, and pressed values.
Use the discriminated API for type-safe values: `type="single"` uses a string,
while `type="multiple"` uses a string array. The former array-only API remains
available for compatibility. Give a single-select group an accessible name
through `rootProps`.
## Multiple selection
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/segmented-control/
Summary: SegmentedControl is a single-select group of value items with a moving active indicator, built on the RadioGroup machine for keyboard and form behavior.
# SegmentedControl
Pass items as `{ value, label, disabled? }`. The RadioGroup machine provides
keyboard and form behavior while the indicator follows the selected item.
## Sizes
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/tour/
Summary: Tour runs a guided product walkthrough from an ordered steps array and a trigger, where each step spotlights an element by CSS selector or appears centered.
# Tour
Pass an ordered `steps` array and a `trigger`. A step can target an element with
a CSS selector or appear in the center.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/utilities/use-shortcut/
Summary: useShortcut binds keyboard combinations and multi-key sequences, either globally or scoped to a region, with the platform modifier resolved for you.
# useShortcut
`useShortcut` works with Manti components or any other element.
## Import
```tsx
import { useShortcut, useShortcuts } from '@manti-ui/react/shortcut';
```
The hooks are also exported from `@manti-ui/react`.
## One shortcut
```tsx
useShortcut('mod+k', () => setOpen(true));
```
Pass a ref as `scope` to fire only while focus is inside a region:
## Several shortcuts
```tsx
useShortcuts({
'mod+k': openSearch,
'mod+/': toggleHelp,
'g d': goToDashboard,
});
```
## Form fields
Shortcuts are ignored in `input`, `textarea`, `select`, and `contenteditable`
elements by default. Set `enableOnFormElements` to opt in.
## Syntax
| Form | Example |
| -------- | ----------------------- |
| Modifier | `mod+k`, `ctrl+shift+p` |
| Key | `escape`, `enter`, `/` |
| Sequence | `g d` |
`mod` means Command on macOS and Control elsewhere.
## API
```ts
useShortcut(combo, handler, options?): void
useShortcuts(map, options?): void
```
| Option | Default | Purpose |
| ---------------------- | ---------- | ---------------------------------- |
| `scope` | `'global'` | Window or a ref-scoped subtree |
| `preventDefault` | `true` | Stop the browser's matching action |
| `enabled` | `true` | Toggle the binding |
| `enableOnFormElements` | `false` | Allow shortcuts while typing |
| `stopPropagation` | `false` | Stop event propagation |
| `sequenceTimeout` | `1000` | Sequence timeout in milliseconds |
The implementation is SSR-safe and attaches listeners only in an effect.
---
URL: https://manti.design/components/tree-view/
Summary: TreeView renders nested items where branches carry children, managing expansion, selection and arrow keys, with an icon render prop for state-aware icons.
# TreeView
Pass nested items; branches contain `children` and leaves do not. The machine
manages expansion, selection, and arrow keys.
Use the `icon` render prop to display node and state-aware icons.
## API
## Styling
### Anatomy
### Tokens
---
URL: https://manti.design/components/data-table/
Summary: DataTable is a typed grid built on TanStack table-core, with sortable columns, filtering, pagination, row selection, getRowProps hooks and sizes.
# DataTable
Pass `columns` and `data`. DataTable uses TanStack table-core for row models and
renders semantic table markup.
## Columns and sorting
Columns use the re-exported `DataTableColumn` type. Use `accessorKey` for
plain values, `cell` for custom rendering, and `meta.align` for alignment.
Set `sortable` to add accessible sort buttons.
## Entity stores and row props
Use `getRowProps`, `getCellProps`, and `getRowId` for native, ARIA, and data
attributes. When each row must resolve a live entity reference with hooks, pass
`rowComponent`. It is a real React component boundary, unlike a render callback,
so hooks remain valid. Spread `rowProps` onto its semantic `` and render
`children` for the generated cells.
## Filtering, pagination, and selection
Enable `filterable`, `paginated`, or `selectable` independently or together.
## Sizes
## API
## Styling
### Anatomy
### Tokens