# dotUI
> Full documentation for dotUI — a design system platform and component registry built on React Aria Components, Tailwind CSS 4, and TypeScript 5. Each section below is the complete markdown source of one documentation page.
---
# Chart examples
## Bar charts [#bar-charts]
## Line charts [#line-charts]
## Area charts [#area-charts]
## Pie charts [#pie-charts]
## Radar charts [#radar-charts]
## Radial charts [#radial-charts]
## Heatmaps [#heatmaps]
---
# Components
## Buttons [#buttons]
## Inputs, controls and form [#inputs-controls-and-form]
## Pickers [#pickers]
## Dates [#dates]
## Feedback [#feedback]
## Collections [#collections]
## Navigation [#navigation]
## Data display [#data-display]
## Chat [#chat]
## Colors [#colors]
## Overlays [#overlays]
## Charts [#charts]
---
# Overview
**dotUI is a design-system builder, not a component library.** There is no default look to install. You compose your system in the [studio](/studio) — colors, typography, icons, density, radius, the style of each component — and leave with code that is yours.
Component libraries ship with a look, and every app built on them shares it. Copy-paste libraries let you own the files, but the design inside is still someone else's. dotUI exists so that anyone can build a real design system without a design team, and without spending months on it.
## Use the studio [#use-the-studio]
Everything happens in the studio. Build your system there, preview every change on real components, then hit **Export**: it hands you the exact commands for your project, with your design system baked in, or opens it directly in v0. Nothing to configure by hand.
Open the studio
## Requirements [#requirements]
Your project needs [React 19](https://react.dev), [Tailwind CSS 4](https://tailwindcss.com) and [TypeScript 5](https://www.typescriptlang.org/).
## Get involved [#get-involved]
Found a bug? Have an idea? Open an issue on [GitHub](https://github.com/mehdibha/dotUI/issues) or DM [@mehdibha](https://x.com/mehdibha) on X. Contributions are welcome.
---
# Accordion
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/accordion
```
```bash
pnpm dlx shadcn@latest add @dotui/accordion
```
```bash
yarn dlx shadcn@latest add @dotui/accordion
```
```bash
bun x shadcn@latest add @dotui/accordion
```
## Anatomy [#anatomy]
```tsx
import {
Accordion,
AccordionItem,
AccordionPanel,
AccordionTrigger,
} from "@/components/ui/accordion"
```
```tsx
Heading
Content
Heading
Content
```
`AccordionTrigger` renders the heading, the button, and the marker; `AccordionPanel` holds the collapsible content. For a single section with a trigger of your own, use [Collapsible](/docs/components/collapsible).
## Open state [#open-state]
Expanded items are tracked by each `AccordionItem`'s `id`. Give the group `defaultExpandedKeys` for uncontrolled state, or `expandedKeys` with `onExpandedChange` to control it — both are a `Set` of ids. Pass `allowsMultipleExpanded` to let the set hold more than one id at a time.
```tsx
How do I get started?
…
```
## Examples [#examples]
## API Reference [#api-reference]
### Accordion [#accordion]
### AccordionItem [#accordionitem]
### AccordionTrigger [#accordiontrigger]
### AccordionPanel [#accordionpanel]
---
# Alert
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/alert
```
```bash
pnpm dlx shadcn@latest add @dotui/alert
```
```bash
yarn dlx shadcn@latest add @dotui/alert
```
```bash
bun x shadcn@latest add @dotui/alert
```
## Usage [#usage]
Use alerts to display important messages that require user attention.
```tsx
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
```
```tsx
Alert Title
Alert description
```
## Anatomy [#anatomy]
An alert composes a title, a description, and an optional action. To add an icon, place an icon element as the alert's first child — styles pick it up positionally, there is no icon prop.
```tsx
import {
Alert,
AlertTitle,
AlertDescription,
AlertAction,
} from "@/components/ui/alert"
import { CircleAlert } from "lucide-react"
```
```tsx
Title
Description
Action
```
`AlertAction` renders at the end and typically wraps a `Button` or `Badge`.
## Examples [#examples]
## API Reference [#api-reference]
### Alert [#alert]
### AlertTitle [#alerttitle]
### AlertDescription [#alertdescription]
### AlertAction [#alertaction]
---
# Attachment
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/attachment
```
```bash
pnpm dlx shadcn@latest add @dotui/attachment
```
```bash
yarn dlx shadcn@latest add @dotui/attachment
```
```bash
bun x shadcn@latest add @dotui/attachment
```
## Usage [#usage]
```tsx
import {
Attachment,
AttachmentContent,
AttachmentDescription,
AttachmentMedia,
AttachmentTitle,
} from "@/components/ui/attachment"
```
```tsx
quarterly-report.pdf
1.2 MB · PDF
```
## Anatomy [#anatomy]
`Attachment` is the card; its `state` walks the upload lifecycle — `idle`
renders a dashed outline, `uploading` and `processing` pulse the title, and
`error` switches to the danger treatment. `AttachmentMedia` holds a file-type
icon or an image thumbnail, `AttachmentActions` holds icon buttons that stay
pressable even when an `AttachmentTrigger` stretches a click target over the
whole card. A scrolling row of attachments goes in an `AttachmentGroup`.
```tsx
import {
Attachment,
AttachmentAction,
AttachmentActions,
AttachmentGroup,
AttachmentTrigger,
} from "@/components/ui/attachment"
```
```tsx
{/* media, content… */}
```
## Examples [#examples]
## API Reference [#api-reference]
### Attachment [#attachment]
### AttachmentMedia [#attachmentmedia]
### AttachmentContent [#attachmentcontent]
### AttachmentTitle [#attachmenttitle]
### AttachmentDescription [#attachmentdescription]
### AttachmentActions [#attachmentactions]
### AttachmentAction [#attachmentaction]
### AttachmentTrigger [#attachmenttrigger]
### AttachmentGroup [#attachmentgroup]
---
# Avatar
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/avatar
```
```bash
pnpm dlx shadcn@latest add @dotui/avatar
```
```bash
yarn dlx shadcn@latest add @dotui/avatar
```
```bash
bun x shadcn@latest add @dotui/avatar
```
## Usage [#usage]
Use avatars to represent users or entities with an image or initials.
```tsx
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"
```
```tsx
MB
```
## Anatomy [#anatomy]
```tsx
import {
Avatar,
AvatarImage,
AvatarFallback,
AvatarBadge,
AvatarGroup,
AvatarGroupCount,
} from "@/components/ui/avatar"
```
```tsx
{/* ... */}
```
`Avatar` is the container. `AvatarImage` renders the picture, `AvatarFallback` the initials or icon shown in its place, and `AvatarBadge` a status indicator overlaid on the corner. `AvatarGroup` stacks avatars with an overlapping layout, and `AvatarGroupCount` shows the remaining count.
## Fallback [#fallback]
`AvatarImage` and `AvatarFallback` share loading state, so you always render both. `AvatarImage` appears only once its `src` finishes loading; until then — and if loading fails — `AvatarFallback` is shown instead.
## Examples [#examples]
## API Reference [#api-reference]
### Avatar [#avatar]
### AvatarImage [#avatarimage]
### AvatarFallback [#avatarfallback]
### AvatarBadge [#avatarbadge]
### AvatarGroup [#avatargroup]
### AvatarGroupCount [#avatargroupcount]
---
# Badge
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/badge
```
```bash
pnpm dlx shadcn@latest add @dotui/badge
```
```bash
yarn dlx shadcn@latest add @dotui/badge
```
```bash
bun x shadcn@latest add @dotui/badge
```
## Usage [#usage]
Use badges to highlight status, categorize items, or show counts.
```tsx
import { Badge } from "@/components/ui/badge"
```
```tsx
Badge
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Breadcrumbs
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/breadcrumbs
```
```bash
pnpm dlx shadcn@latest add @dotui/breadcrumbs
```
```bash
yarn dlx shadcn@latest add @dotui/breadcrumbs
```
```bash
bun x shadcn@latest add @dotui/breadcrumbs
```
## Usage [#usage]
Use breadcrumbs to display a hierarchy of links showing the user's location in a site or application.
```tsx
import {
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbSeparator,
Breadcrumbs,
} from "@/components/ui/breadcrumbs"
```
```tsx
Home
Components
Breadcrumbs
```
## Anatomy [#anatomy]
Each `BreadcrumbItem` wraps a `BreadcrumbLink` and its own `BreadcrumbSeparator`. The separator lives inside the item, so omit it on the last one. It defaults to a chevron; pass `children` to override.
```tsx
Home
/
Current
```
## Framework Setup [#framework-setup]
By default, `BreadcrumbLink` renders a plain `` tag. To integrate with your framework's router, override the component in your project's `breadcrumbs.tsx`.
### Next.js [#nextjs]
```tsx title="ui/breadcrumbs.tsx"
import RouterLink from "next/link"; // [!code highlight]
// ..
const BreadcrumbLink = ({ className, ...props }: BreadcrumbLinkProps) => {
return (
{
"href" in domProps ? (
}
href={href}
{...domProps}
/>
) : (
} {...domProps} />
)
}
className={composeRenderProps(className, (className) =>
link({ className }),
)}
{...props}
/>
);
};
```
### TanStack Start [#tanstack-start]
```tsx title="ui/breadcrumbs.tsx"
// [!code highlight:2]
import { Link as RouterLink } from "@tanstack/react-router"
import type { ToOptions } from "@tanstack/react-router"
// ..
interface BreadcrumbLinkProps extends Omit<
React.ComponentProps,
"href"
> {
href?: string | ToOptions // [!code highlight]
}
const BreadcrumbLink = ({ className, ...props }: BreadcrumbLinkProps) => {
return (
{
if (typeof href === "object") {
return (
}
{...href}
{...domProps}
/>
)
}
if (typeof href === "string") {
return (
}
href={href}
{...domProps}
/>
)
}
return
}}
className={composeRenderProps(className, (className) =>
link({ className }),
)}
{...props}
/>
)
}
```
## Examples [#examples]
## API Reference [#api-reference]
### Breadcrumbs [#breadcrumbs]
### BreadcrumbItem [#breadcrumbitem]
### BreadcrumbLink [#breadcrumblink]
### BreadcrumbSeparator [#breadcrumbseparator]
---
# Bubble
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/bubble
```
```bash
pnpm dlx shadcn@latest add @dotui/bubble
```
```bash
yarn dlx shadcn@latest add @dotui/bubble
```
```bash
bun x shadcn@latest add @dotui/bubble
```
## Usage [#usage]
```tsx
import { Bubble, BubbleContent } from "@/components/ui/bubble"
```
```tsx
Shipping it this week 🚀
```
## Anatomy [#anatomy]
`Bubble` positions one message on a side of the conversation and styles the
`BubbleContent` inside it — `variant` picks the surface (primary, neutral,
muted, tinted, outline, ghost or danger), `align` picks the side. Consecutive
bubbles from the same sender stack inside a `BubbleGroup`, and
`BubbleReactions` pins emoji reactions to a corner of the bubble.
```tsx
import {
Bubble,
BubbleContent,
BubbleGroup,
BubbleReactions,
} from "@/components/ui/bubble"
```
```tsx
We just passed 10k stars!
🎉 3
```
## Examples [#examples]
## API Reference [#api-reference]
### BubbleGroup [#bubblegroup]
### Bubble [#bubble]
### BubbleContent [#bubblecontent]
### BubbleReactions [#bubblereactions]
---
# Button
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/button
```
```bash
pnpm dlx shadcn@latest add @dotui/button
```
```bash
yarn dlx shadcn@latest add @dotui/button
```
```bash
bun x shadcn@latest add @dotui/button
```
## Usage [#usage]
A button triggers an action. Its label names the action; add an icon for extra context.
```tsx
import { Button } from "@/components/ui/button"
```
```tsx
```
## Variants [#variants]
Use the `variant` prop to set the visual style of the button.
## Sizes [#sizes]
Use the `size` prop to set the size of the button.
## With icon [#with-icon]
Add the `data-icon="inline-start"` or `data-icon="inline-end"` attribute to the icon for the correct spacing.
## Icon buttons [#icon-buttons]
Use the `isIconOnly` prop for icon-only buttons.
Provide an `aria-label` to give the button an accessible name.
## Pending [#pending]
Use the `isPending` prop to show a loading indicator while an action completes.
## Link buttons [#link-buttons]
The Button component always represents a button semantically. To create a link that visually looks like a button, use the `LinkButton` component instead.
## API Reference [#api-reference]
### Button [#button]
### LinkButton [#linkbutton]
---
# Calendar
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/calendar
```
```bash
pnpm dlx shadcn@latest add @dotui/calendar
```
```bash
yarn dlx shadcn@latest add @dotui/calendar
```
```bash
bun x shadcn@latest add @dotui/calendar
```
## Usage [#usage]
Use `Calendar` to allow users to select a single date value.
```tsx
import { Calendar } from "@/components/ui/calendar"
```
```tsx
```
Use `RangeCalendar` to let users select a contiguous range of dates.
```tsx
import { RangeCalendar } from "@/components/ui/calendar"
```
```tsx
```
## Composition [#composition]
For full control, compose the calendar from its parts.
```tsx
import {
Calendar,
CalendarHeader,
CalendarHeading,
CalendarGrid,
CalendarGridHeader,
CalendarHeaderCell,
CalendarGridBody,
CalendarCell,
} from "@/components/ui/calendar"
```
```tsx
{(day) => {day}}
{(date) => }
```
## Value [#value]
Calendar values use [`@internationalized/date`](https://react-spectrum.adobe.com/internationalized/date/) objects. Pass `defaultValue` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
import { parseDate } from "@internationalized/date"
```
```tsx
```
```tsx
import { useState } from "react"
import { parseDate } from "@internationalized/date"
import type { DateValue } from "react-aria-components"
function Example() {
const [value, setValue] = useState(parseDate("2020-02-03"))
return
}
```
## Date availability [#date-availability]
Constrain the selectable range with `minValue` and `maxValue`, or disable individual dates with `isDateUnavailable`. All take [`@internationalized/date`](https://react-spectrum.adobe.com/internationalized/date/) values, so derive them from `today(getLocalTimeZone())`.
```tsx
import { getLocalTimeZone, today } from "@internationalized/date"
const now = today(getLocalTimeZone())
```
```tsx
[0, 6].includes(date.toDate(getLocalTimeZone()).getDay())
}
/>
```
## Examples [#examples]
## API Reference [#api-reference]
### Calendar [#calendar]
### RangeCalendar [#rangecalendar]
### CalendarHeader [#calendarheader]
### CalendarGrid [#calendargrid]
### CalendarGridHeader [#calendargridheader]
### CalendarHeaderCell [#calendarheadercell]
### CalendarGridBody [#calendargridbody]
### CalendarCell [#calendarcell]
---
# Card
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/card
```
```bash
pnpm dlx shadcn@latest add @dotui/card
```
```bash
yarn dlx shadcn@latest add @dotui/card
```
```bash
bun x shadcn@latest add @dotui/card
```
## Usage [#usage]
```tsx
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
```
```tsx
Card Title
Card Description
Card Action
Card Content
Card Footer
```
## Anatomy [#anatomy]
```tsx
```
`CardHeader` holds the `CardTitle`, `CardDescription`, and an optional `CardAction` pinned at the end of the header row. `CardContent` is the main body and `CardFooter` sits below it, usually for actions.
## Size [#size]
Pass `size="sm"` to `Card` for a more compact card with tighter spacing.
```tsx
{/* ... */}
```
## Section borders [#section-borders]
Add `border-b` to `CardHeader` or `border-t` to `CardFooter` to visually separate them from the content.
```tsx
{/* ... */}
```
## Examples [#examples]
## API Reference [#api-reference]
### Card [#card]
### CardHeader [#cardheader]
### CardTitle [#cardtitle]
### CardDescription [#carddescription]
### CardAction [#cardaction]
### CardContent [#cardcontent]
### CardFooter [#cardfooter]
---
# Area Chart
An area chart is a line chart whose fill carries meaning: distance from a baseline, or the span between two boundaries. Reach for it when the reader should compare magnitude or composition — not just because a filled chart looks stronger. When only the trend matters, use the [line chart](/docs/components/chart-line).
`AreaChart` takes your rows and the names of the fields to read. Colors, typography, grid, tooltip, and legend all come from your design system.
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/chart-area
```
```bash
pnpm dlx shadcn@latest add @dotui/chart-area
```
```bash
yarn dlx shadcn@latest add @dotui/chart-area
```
```bash
bun x shadcn@latest add @dotui/chart-area
```
It brings the `chart` core — the host, the palette, and the shared frame — along with it.
## Usage [#usage]
```tsx
import { AreaChart } from "@/components/ui/chart-area"
```
Point `x` at the category or time field and `y` at the value field. A chart is a figure, so `ariaLabel` is required.
```tsx
const data = [
{ month: "Jan", desktop: 186 },
{ month: "Feb", desktop: 305 },
{ month: "Mar", desktop: 237 },
]
export function Example() {
return (
)
}
```
`data` is compared by identity, so define it outside your component — or memoize it. Every other prop is a flat scalar and can change freely.
## Data shape [#data-shape]
Two shapes work, and both draw the same chart.
**Wide** rows carry one column per series. Pass the columns as an array, and name them with `labels`:
```tsx
```
**Long** rows carry one row per series per x value, with the series key in its own field. Pass that field as `series`, and set `seriesOrder` to lead the color slots and the legend — series the data carries but `seriesOrder` omits follow in the order they first appear:
```tsx
```
Series take colors from `--chart-1` through `--chart-8` in order. A `null` value leaves a gap rather than dropping to zero.
## Stacking [#stacking]
`stacked` stacks the series on one another, in `seriesOrder`; the tooltip still reports each band's own value.
```tsx
```
Positive values stack up from zero and negative values down from it, so a mixed-sign group never overlaps itself. `stacked="normalize"` divides each band by its own x-group total for a 100% stack — format the value axis as a percentage with `formatY`.
## Shape [#shape]
`curve` sets the interpolation: `natural` (the default), `monotone`, `linear`, or `step`. `fill` takes an opacity, or `'gradient'` for a fade toward the baseline. `strokeWidth` and `points` control the upper edge.
Interpolation only changes the path drawn between observations. It does not smooth the data or create evidence between samples.
## Annotations [#annotations]
`marks` and `marksBefore` accept raw [TanStack Charts](https://tanstack.com/charts) mark layers, painted over and under the areas on the same scales. Use them for a target rule, a highlighted band, or end labels.
```tsx
import { ruleY } from "@tanstack/charts/rule"
const target = ruleY([200], { strokeDasharray: "4 4" })
```
```tsx
```
## Accessibility [#accessibility]
* `ariaLabel` is required and names the figure; add `ariaDescription` when the takeaway needs a sentence.
* The chart surface is in the tab order. Arrow keys move between points, `Home` and `End` jump to the first and last, `Enter` and Space pin the tooltip, and `Escape` dismisses it.
* Color alone never carries the distinction — the legend, tooltip, and axis labels all name the series.
* `tooltip={false}` keeps the focus stops but removes their live region, so screen readers land on silent points. Turn it off only for a decorative chart.
## Examples [#examples]
## API Reference [#api-reference]
### AreaChart [#areachart]
---
# Bar Chart
`BarChart` plots one bar per category, or one bar per series inside each category band. It builds its own scales, axes, grid, legend, and tooltip from the fields you name, and paints series from your design system's chart palette.
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/chart-bar
```
```bash
pnpm dlx shadcn@latest add @dotui/chart-bar
```
```bash
yarn dlx shadcn@latest add @dotui/chart-bar
```
```bash
bun x shadcn@latest add @dotui/chart-bar
```
It brings the `chart` core — the host, the palette, and the shared frame — along with it.
## Usage [#usage]
```tsx
import { BarChart } from "@/components/ui/chart-bar"
```
```tsx
const data = [
{ month: "Jan", desktop: 186, mobile: 80 },
{ month: "Feb", desktop: 305, mobile: 200 },
{ month: "Mar", desktop: 237, mobile: 120 },
]
export function Example() {
return (
)
}
```
`x` names the category field and `y` names one field per series. Series take palette slots — `--chart-1`, `--chart-2`, … — in the order you list them, and `labels` renames the keys wherever they surface: legend, tooltip, and screen readers.
Keep `data` out of the render body. It is compared by identity, so a fresh array on every render rebuilds the chart instead of animating it.
## Wide and long data [#wide-and-long-data]
Rows come in two shapes, and the chart reads both.
**Wide** rows carry one field per series — pass them as a `y` array, as above.
**Long** rows carry one value and name their own series. Pass a single `y` and a `series` field, and set `seriesOrder` to lead the color slots and the legend — series the data carries but `seriesOrder` omits follow in the order they first appear:
```tsx
const data = [
{ browser: "chrome", visitors: 275 },
{ browser: "safari", visitors: 200 },
]
```
```tsx
```
Naming the category field as `series` is also how each bar gets its own color, as in the [Per-category color](#examples) example.
## Stacked bars [#stacked-bars]
`stacked` stacks the series inside each band, in `seriesOrder`. Positive values stack up from zero and negative values down from it, so a mixed-sign group never overlaps itself, and only the outer end of each stack is rounded.
```tsx
```
`stacked="normalize"` divides each band by its own total for a 100% stack — format the value axis as a percentage with `formatY`.
## Orientation and grouping [#orientation-and-grouping]
`horizontal` moves the categories to the y axis and the values to x, which is what long category names want. The value axis is still `x`, so `formatX` formats the numbers, and focus groups along the categories automatically.
Multi-series wide data is grouped side by side by default. Set `grouped` to group long-format series too; without grouping or stacking, series that share a category stack from zero.
## Labels and annotations [#labels-and-annotations]
`marks` paints layers over the bars and `marksBefore` under them — any mark from `@tanstack/charts`, on the same scales:
```tsx
import { text } from "@tanstack/charts/text"
// Same `z` as the bars, so grouped focus keeps one tooltip row per category.
const labels = [
text(data, {
x: "month",
y: "desktop",
text: "desktop",
z: () => "Desktop",
fill: "var(--color-fg-muted)",
dy: -10,
}),
]
```
```tsx
```
Both props are compared by identity, like `data`. A layer that depends on state belongs in a `useMemo`.
## Accessibility [#accessibility]
* `ariaLabel` is required and names the figure: describe what the bars measure, not the chart type. Add `ariaDescription` when the takeaway needs a sentence.
* The chart surface is in the tab order. Arrow keys walk the bars, `Home` and `End` jump to the ends, `Enter` and Space pin the tooltip and fire `onSelect`, and `Escape` dismisses it. Grouped focus reads one representative per category, so a grouped or stacked chart announces the whole category at once.
* Color alone never carries the meaning — pass `labels` so every series has a name in the legend and tooltip, and keep the legend on when a chart has more than one series.
* `tooltip={false}` keeps the focus stops but removes their live region, so screen readers land on silent points. Turn it off only for a decorative chart.
## Examples [#examples]
## API Reference [#api-reference]
### BarChart [#barchart]
---
# Heatmap
A heatmap answers where something concentrates. Two categorical axes place every cell exactly, and color carries the one value that belongs to that pair — the shape of a week, a season, or a service's bad month, read in one pass.
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/chart-heatmap
```
```bash
pnpm dlx shadcn@latest add @dotui/chart-heatmap
```
```bash
yarn dlx shadcn@latest add @dotui/chart-heatmap
```
```bash
bun x shadcn@latest add @dotui/chart-heatmap
```
It brings the `chart` core — the host, the palette, and the shared frame — along with it.
## Usage [#usage]
```tsx
import { HeatmapChart } from "@/components/ui/chart-heatmap"
```
A heatmap reads long rows: one row per cell, with the column field, the row field, and the value. `ariaLabel` is required — a chart is a figure, not decoration.
```tsx
const sessions = [
{ day: "Mon", hour: "09", sessions: 32 },
{ day: "Mon", hour: "10", sessions: 58 },
{ day: "Tue", hour: "09", sessions: 30 },
]
export function Example() {
return (
)
}
```
Both axes are band scales, so the categories appear in the order the rows first mention them — sort your data, and the matrix follows. `label` names what the value means: it titles the legend and labels the value in the tooltip. `labelX` and `labelY` do the same for the two coordinates.
Cells tile the plot, so the heatmap has no `grid` prop — the cell edges are the grid.
## Color [#color]
Color is the whole reading, so it is binned rather than continuous: each bin is a distinct step, and the legend prints the boundaries between them. `colors` is the ramp, low to high, and its length is the number of bins.
```tsx
import { heatmapColors, HeatmapChart } from "@/components/ui/chart-heatmap"
```
```tsx
```
`heatmapColors` builds a ramp from a single palette slot: the low steps fade into the surface and the high steps toward the foreground, so the ramp stays sequential in light and dark without a second set of values. Any array of CSS colors works in its place.
Without `thresholds`, the bins split the observed extent evenly. Pass `thresholds` when the cuts are a policy rather than an extent — one incident is already worth seeing, ten is an outage week:
```tsx
```
There is always one more color than cut.
## Values in cells [#values-in-cells]
`values` writes each number inside its cell, and `formatValue` formats it — in the cells, the legend, and the tooltip at once. Each label picks black or white from the lightness of the cell under it, so it stays readable at both ends of the ramp.
```tsx
`${Math.round(Number(value) * 100)}%`}
ariaLabel="Feature adoption by region and quarter"
/>
```
Only turn it on when the cells are large enough to hold a number — a dozen cells, not a hundred. Everywhere else the tooltip is the place for exact figures.
## Accessibility [#accessibility]
* `ariaLabel` is required and names the figure; add `ariaDescription` when the takeaway needs a sentence.
* The chart surface is in the tab order. Arrow keys move between cells, `Home` and `End` jump to the first and last, `Enter` and Space pin the tooltip, and `Escape` dismisses it.
* A heatmap encodes its measure in color alone, which is exactly the encoding a reader may not perceive. The legend is visual guidance and is hidden from assistive technology, so give the value a `label` and turn on `values` whenever the cells can hold the numbers.
* `tooltip={false}` keeps the focus stops but removes their live region, so screen readers land on silent points. Turn it off only for a decorative chart — and never on a heatmap, where the tooltip is the only place the exact value is spoken.
## Examples [#examples]
## API Reference [#api-reference]
### HeatmapChart [#heatmapchart]
---
# Line Chart
`LineChart` answers how a value changes across an ordered domain. Give it rows and the fields to read — it builds the scales, the axes, the legend, the tooltip, and the keyboard navigation for you, all colored from your palette.
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/chart-line
```
```bash
pnpm dlx shadcn@latest add @dotui/chart-line
```
```bash
yarn dlx shadcn@latest add @dotui/chart-line
```
```bash
bun x shadcn@latest add @dotui/chart-line
```
It brings the `chart` core — the host, the palette, and the shared frame — along with it.
## Usage [#usage]
```tsx
import { LineChart } from "@/components/ui/chart-line"
```
```tsx
const chartData = [
{ month: "Jan", desktop: 186 },
{ month: "Feb", desktop: 305 },
{ month: "Mar", desktop: 237 },
]
export function Example() {
return (
)
}
```
`x` and `y` name fields on the row; `labels` gives each series a display name for the legend and the tooltip. `data` is compared by identity, so define it outside your component — or memoize it — and the chart rebuilds only when the rows actually change.
## Wide and long data [#wide-and-long-data]
Two data shapes, one component. **Wide** rows carry one field per series:
```tsx
```
**Long** rows repeat the x value and name their series in a field. Set `seriesOrder` to lead the color slots and the legend — series the data carries but `seriesOrder` omits follow in the order they first appear:
```tsx
```
Either way, series are colored in order from `--chart-1` through `--chart-8`.
## Curve [#curve]
`curve` chooses the path between points: `natural` (the default), `monotone`, `step`, or `linear`.
```tsx
```
Interpolation only changes how the line travels between observations — it does not smooth the data or claim anything about the values in between. A `null` value is a gap, not a zero: the line stops and restarts on the far side.
## Annotations [#annotations]
`marks` paints extra layers over the lines, `marksBefore` under them. Both take marks straight from `@tanstack/charts`, so labels, reference rules, and custom dots compose with the same scales:
```tsx
import { text } from "@tanstack/charts/text"
const labels = text(chartData, {
x: "month",
y: "desktop",
text: "desktop",
z: () => "Desktop",
dy: -12,
})
```
```tsx
```
Give an annotation the same `z` as the series it belongs to — the series' display name, or its field name when you pass no `labels`. That keeps it in one focus group with the line, so the tooltip stays a single row instead of growing one per layer. Build marks outside render: like `data`, they are compared by identity.
## Accessibility [#accessibility]
* `ariaLabel` is required and names the figure; add `ariaDescription` when the takeaway needs a sentence.
* The chart surface is in the tab order. Arrow keys move between points, `Home` and `End` jump to the first and last, `Enter` and Space pin the tooltip, and `Escape` dismisses it.
* Color alone never carries the distinction — the legend, tooltip, and axis labels all name the series.
* When exact values matter, put a real table or a short summary next to the chart — HTML the reader can select, translate, and print.
* `tooltip={false}` keeps the focus stops but removes their live region, so screen readers land on silent points. Turn it off only for a decorative chart.
## Examples [#examples]
## API Reference [#api-reference]
### LineChart [#linechart]
---
# Pie Chart
A pie chart answers one question: how does this total break down? It reads well with a handful of slices and a clear leader, and badly with a dozen near-equal ones — comparing angles is harder than comparing lengths. When the ranking matters more than the share, use a [bar chart](/docs/components/chart-bar).
`PieChart` takes your rows and the names of the fields to read. Colors, typography, tooltip, and legend all come from your design system.
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/chart-pie
```
```bash
pnpm dlx shadcn@latest add @dotui/chart-pie
```
```bash
yarn dlx shadcn@latest add @dotui/chart-pie
```
```bash
bun x shadcn@latest add @dotui/chart-pie
```
It brings the `chart` core — the host, the palette, and the shared frame — along with it.
## Usage [#usage]
```tsx
import { PieChart } from "@/components/ui/chart-pie"
```
One row per slice. `value` names the field holding the magnitude, `name` the field holding the slice key. A chart is a figure, so `ariaLabel` is required.
```tsx
const data = [
{ browser: "chrome", visitors: 275 },
{ browser: "safari", visitors: 200 },
{ browser: "firefox", visitors: 187 },
]
export function Example() {
return (
)
}
```
`data` is compared by identity, so define it outside your component — or memoize it. Every other prop is a flat scalar and can change freely.
Slices are drawn in data order and take colors from `--chart-1` through `--chart-8` in the same order. Set `seriesOrder` to lead the color slots and the legend — slices the data carries but `seriesOrder` omits follow in the order they first appear.
## Geometry [#geometry]
Radii are ratios, never pixels, so a pie keeps its proportions at every size.
* `innerRadius` above `0` makes it a donut. `0.55` is a good starting point.
* `outerRadius` shrinks the ring inside the available radius; `radiusRatio` reserves room around the whole chart for labels and the legend.
* `startAngle` and `endAngle` are radians clockwise from twelve o'clock. `endAngle={Math.PI}` draws a semicircle.
* `padAngle` opens a gap between slices, `cornerRadius` rounds their corners.
Slices are separated by a stroke in the page background; `strokeWidth={0}` lets them touch, and `stroke` changes the color.
```tsx
```
`activeIndex` pushes one slice out of the ring by `activeOffset`, for calling out the slice the surrounding copy is about.
## Labels and center content [#labels-and-center-content]
`sliceLabel` draws text on each slice — `'value'` for the magnitude, `'name'` for the key — positioned with `sliceLabelRadius` and styled with `sliceLabelFill` and `sliceLabelFontSize`. Slice labels are decorative: they paint on the surface but never become keyboard stops or tooltip targets — the arc beneath them carries the interaction.
The hole in a donut is best filled with plain HTML: anything passed as `children` renders as an overlay above the surface and ignores pointer events.
```tsx
{total}
Visitors
```
## Concentric rings [#concentric-rings]
A second series is a second ring, not a stack. `pieRing` builds one, and `polarMarks` splices it inside the chart's polar container — plain `marks` would land outside the transform. Build it outside your component so it keeps its identity across renders.
```tsx
import { pieRing, PieChart } from "@/components/ui/chart-pie"
const mobileRing = pieRing({
id: "mobile",
data: mobile,
value: "mobile",
name: "month",
innerRadius: 0.7,
outerRadius: 0.95,
})
```
```tsx
```
Both rings key their colors off the same field, so one month is one color from the middle out.
## Animation [#animation]
Slices sweep in through their angles on first client paint, one after another, and spring between data states — server-rendered charts replay the entrance once hydration lands. `animate` takes `false` for an immediate repaint, or a tween or spring configuration to change the feel.
## Accessibility [#accessibility]
* `ariaLabel` is required and names the figure; add `ariaDescription` when the takeaway needs a sentence.
* The chart surface is in the tab order. Arrow keys move between slices, `Home` and `End` jump to the first and last, `Enter` and Space pin the tooltip, and `Escape` dismisses it.
* Color alone never carries the distinction — the legend, tooltip, and slice labels all name the slice.
* `tooltip={false}` keeps the focus stops but removes their live region, so screen readers land on silent points. Turn it off only for a decorative chart.
## Examples [#examples]
## API Reference [#api-reference]
### PieChart [#piechart]
---
# Radar Chart
A radar chart wraps a category axis into a circle and draws each series as a closed shape. Reach for it when the reader should judge a *profile* — the balance across five to eight categories — and compare two of them at a glance. It is a poor tool for reading exact values or for ranking: the eye compares areas, and area grows with the square of the value. When precision matters, use the [bar chart](/docs/components/chart-bar).
`RadarChart` takes your rows and the names of the fields to read. Colors, typography, grid, tooltip, and legend all come from your design system.
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/chart-radar
```
```bash
pnpm dlx shadcn@latest add @dotui/chart-radar
```
```bash
yarn dlx shadcn@latest add @dotui/chart-radar
```
```bash
bun x shadcn@latest add @dotui/chart-radar
```
It brings the `chart` core — the host, the palette, and the shared frame — along with it.
## Usage [#usage]
```tsx
import { RadarChart } from "@/components/ui/chart-radar"
```
Point `x` at the category field and `y` at the value field — one row per category. A chart is a figure, so `ariaLabel` is required.
```tsx
const data = [
{ month: "Jan", desktop: 186 },
{ month: "Feb", desktop: 305 },
{ month: "Mar", desktop: 237 },
]
export function Example() {
return (
)
}
```
`data` is compared by identity, so define it outside your component — or memoize it. Every other prop is a flat scalar and can change freely.
## Data shape [#data-shape]
Two shapes work, and both draw the same chart.
**Wide** rows carry one column per series. Pass the columns as an array, and name them with `labels`:
```tsx
```
**Long** rows carry one row per series per category, with the series key in its own field. Pass that field as `series`, and set `seriesOrder` to lead the color slots and the legend — series the data carries but `seriesOrder` omits follow in the order they first appear:
```tsx
```
Series take colors from `--chart-1` through `--chart-8` in order. Every series is drawn on one shared radius scale running from zero to the largest value — a radar with two units on it is a chart with two meanings, so normalize first.
## Grid and labels [#grid-and-labels]
The rings, the spokes, and the circumference labels are three separate switches: `grid` draws the rings, `spokes` the lines running out to each category, and `axes` the labels. `gridShape` makes the rings circles instead of polygons, `gridTicks` sets how many there are, and `gridFill` tints the area inside the outer one.
```tsx
```
`formatX` rewrites the circumference labels, and `axisDetail` adds a second, muted line above each one — the value at that spoke, a share, a delta.
## Annotations [#annotations]
`polarMarks` accepts raw [TanStack Charts](https://tanstack.com/charts) polar mark layers, spliced into the polar container on the same angle and radius scales. Cartesian marks would land outside the circle, so this is the escape hatch a radar uses. `children` renders as HTML above the chart, ignoring pointer events.
## Animation [#animation]
The polygon grows from the center on first client paint and springs between data states — server-rendered charts replay the entrance once hydration lands. `animate` takes `false` for an immediate repaint, or a tween or spring configuration to change the feel.
## Accessibility [#accessibility]
* `ariaLabel` is required and names the figure; add `ariaDescription` when the takeaway needs a sentence.
* The chart surface is in the tab order. Arrow keys move between spokes, `Home` and `End` jump to the first and last, `Enter` and Space pin the tooltip, and `Escape` dismisses it.
* Hovering or focusing a spoke reports every series at that category, named and valued — color alone never carries the distinction.
* `tooltip={false}` keeps the focus stops but removes their live region, so screen readers land on silent points. Turn it off only for a decorative chart.
## Examples [#examples]
## API Reference [#api-reference]
### RadarChart [#radarchart]
---
# Radial Chart
A radial bar chart trades the precision of a straight axis for a compact, recognizable shape. It reads well for a single value against a target — a gauge — and for a handful of categories where the ranking matters more than the exact gap. Past five or six rings, or when the values must be compared closely, use the [bar chart](/docs/components/chart-bar).
`RadialBarChart` takes your rows, the field holding each value, and the field naming it. Colors, typography, and the tooltip all come from your design system.
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/chart-radial
```
```bash
pnpm dlx shadcn@latest add @dotui/chart-radial
```
```bash
yarn dlx shadcn@latest add @dotui/chart-radial
```
```bash
bun x shadcn@latest add @dotui/chart-radial
```
It brings the `chart` core — the host, the palette, and the shared frame — along with it.
## Usage [#usage]
```tsx
import { RadialBarChart } from "@/components/ui/chart-radial"
```
Each row becomes one ring, drawn from the inside out. A chart is a figure, so `ariaLabel` is required.
```tsx
const data = [
{ browser: "chrome", visitors: 275 },
{ browser: "safari", visitors: 200 },
{ browser: "firefox", visitors: 187 },
]
export function Example() {
return (
)
}
```
`data` is compared by identity, so define it outside your component — or memoize it. Every other prop is a flat scalar and can change freely.
## Geometry [#geometry]
Angles are radians, clockwise from twelve o'clock; radii are ratios of the circle the chart resolves for its box, so a chart keeps its proportions at any size.
```tsx
```
`max` sets the value that fills the whole sweep — without it the largest value fills it. Give a gauge an explicit `max` so the arc reads as a share of a target, and turn on `track` to draw the unfilled remainder.
## Stacking [#stacking]
Pass an array of fields as `value` to stack one row's values into a single ring, laid end to end from `startAngle`. It is the radial equivalent of a stacked bar: the ring is the whole, the arcs are the parts.
```tsx
```
## Center label [#center-label]
The middle of a ring is the place for the number it summarizes. `children` render as an HTML overlay covering the chart and ignoring pointer events — center the label with flex, as below, and it uses your real typography while staying out of the keyboard path.
```tsx
1,260
Visitors
```
## Annotations [#annotations]
`polarMarks` and `polarMarksBefore` accept raw [TanStack Charts](https://tanstack.com/charts) polar marks — `radialArc`, `radialText`, `radialRule` — painted over and under the bars, inside the circle's own transform. Cartesian marks would land outside it, so reach for the polar ones here.
```tsx
import { radialRule } from "@tanstack/charts/polar"
const target = radialRule([{ angle: Math.PI }], {
angle: "angle",
radius1: 0,
radius2: 1,
strokeDasharray: "4 4",
})
```
```tsx
```
## Animation [#animation]
Bars sweep in through their angles on first client paint, one after another, and spring between data states — the background track stays put, and server-rendered charts replay the entrance once hydration lands. `animate` takes `false` for an immediate repaint, or a tween or spring configuration to change the feel.
## Accessibility [#accessibility]
* `ariaLabel` is required and names the figure; add `ariaDescription` when the takeaway needs a sentence.
* The chart surface is in the tab order. Arrow keys move between arcs, `Home` and `End` jump to the first and last, `Enter` and Space pin the tooltip, and `Escape` dismisses it.
* Color alone never carries the distinction — the tooltip and the legend name every ring, and `barLabels` prints the names on the arcs themselves.
* A ring's angle is harder to compare than a bar's length. Print the numbers when the exact values matter.
* `tooltip={false}` keeps the focus stops but removes their live region, so screen readers land on silent points. Turn it off only for a decorative chart.
## Examples [#examples]
## API Reference [#api-reference]
### RadialBarChart [#radialbarchart]
---
# Checkbox Group
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/checkbox-group
```
```bash
pnpm dlx shadcn@latest add @dotui/checkbox-group
```
```bash
yarn dlx shadcn@latest add @dotui/checkbox-group
```
```bash
bun x shadcn@latest add @dotui/checkbox-group
```
## Usage [#usage]
Use `CheckboxGroup` to allow users to select multiple items from a list of options.
```tsx
import { CheckboxGroup } from "@/components/ui/checkbox-group"
import { Checkbox, CheckboxControl } from "@/components/ui/checkbox"
import { FieldGroup, Label } from "@/components/ui/field"
```
```tsx
```
## Selection [#selection]
Use `defaultValue` for uncontrolled checkbox groups, or `value` and `onChange` for controlled checkbox groups.
```tsx
{/* ... */}
```
```tsx
function Example() {
const [frameworks, setFrameworks] = useState(["nextjs"])
return (
{/* ... */}
)
}
```
## Validation [#validation]
Set `isRequired` to require a selection, or drive `isInvalid` yourself. Render errors with `FieldError` — with the default `validationBehavior="native"` it surfaces the browser's message on form submit; use `validationBehavior="aria"` to validate live without native form semantics.
```tsx
import { CheckboxGroup } from "@/components/ui/checkbox-group"
import { FieldError, FieldGroup, Label } from "@/components/ui/field"
```
```tsx
{/* ... */}
Please select a framework.
```
## Examples [#examples]
## API Reference [#api-reference]
### CheckboxGroup [#checkboxgroup]
### Checkbox [#checkbox]
---
# Checkbox
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/checkbox
```
```bash
pnpm dlx shadcn@latest add @dotui/checkbox
```
```bash
yarn dlx shadcn@latest add @dotui/checkbox
```
```bash
bun x shadcn@latest add @dotui/checkbox
```
## Usage [#usage]
Use `Checkbox` to allow users to select multiple items from a list of individual items, or to mark one individual item as selected.
```tsx
import { Checkbox, CheckboxControl } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
Pass a plain string and `Checkbox` wraps it in a `CheckboxControl` and `Label` for you. Pass elements instead and you compose the tree yourself — `CheckboxControl` renders the `CheckboxIndicator` (the box) and can hold `FieldContent` with a `Label` and `Description`.
```tsx
import {
Checkbox,
CheckboxControl,
CheckboxIndicator,
} from "@/components/ui/checkbox"
import { Description, FieldContent, Label } from "@/components/ui/field"
```
```tsx
Please read them before proceeding
```
## Selection [#selection]
The checkbox is selected or not. Use `defaultSelected` for uncontrolled state, or `isSelected` with `onChange` to control it.
```tsx
const [isSelected, setIsSelected] = React.useState(false)
Accept terms
```
## Examples [#examples]
## API Reference [#api-reference]
### Checkbox [#checkbox]
### CheckboxControl [#checkboxcontrol]
### CheckboxIndicator [#checkboxindicator]
---
# Collapsible
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/collapsible
```
```bash
pnpm dlx shadcn@latest add @dotui/collapsible
```
```bash
yarn dlx shadcn@latest add @dotui/collapsible
```
```bash
bun x shadcn@latest add @dotui/collapsible
```
## Anatomy [#anatomy]
```tsx
import {
Collapsible,
CollapsiblePanel,
CollapsibleTrigger,
} from "@/components/ui/collapsible"
```
```tsx
Show details
Content
```
A collapsible carries no look of its own: `CollapsibleTrigger` is a bare button for custom layouts, and any `Button` with `slot="trigger"` works in its place. Style the open state from the root's `group-expanded/collapsible` variant. For a stack of headed sections, use [Accordion](/docs/components/accordion).
```tsx
import { Button } from "@/components/ui/button"
import { ChevronDownIcon } from "your-icon-library"
```
```tsx
Content
```
## Open state [#open-state]
Use `defaultExpanded` for uncontrolled state, or `isExpanded` with `onExpandedChange` to control it.
```tsx
const [isExpanded, setExpanded] = React.useState(false)
Show details
…
```
## Examples [#examples]
## API Reference [#api-reference]
### Collapsible [#collapsible]
### CollapsibleTrigger [#collapsibletrigger]
### CollapsiblePanel [#collapsiblepanel]
---
# Color Area
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/color-area
```
```bash
pnpm dlx shadcn@latest add @dotui/color-area
```
```bash
yarn dlx shadcn@latest add @dotui/color-area
```
```bash
bun x shadcn@latest add @dotui/color-area
```
## Usage [#usage]
Use color areas to allow users to select a color from a two-dimensional gradient.
```tsx
import { ColorArea } from "@/components/ui/color-area"
import { ColorThumb } from "@/components/ui/color-thumb"
```
```tsx
```
## Anatomy [#anatomy]
A `ColorArea` renders the gradient and positions a `ColorThumb`. If you omit children, a default `ColorThumb` is rendered for you.
```tsx
import { ColorArea } from "@/components/ui/color-area"
import { ColorThumb } from "@/components/ui/color-thumb"
```
```tsx
```
## Value [#value]
Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it. Uncontrolled values accept a color string; controlled values are `Color` objects created with `parseColor`.
```tsx
import { parseColor } from 'react-aria-components'
const [value, setValue] = React.useState(parseColor('hsl(0, 100%, 50%)'))
```
## Channels [#channels]
`xChannel` and `yChannel` map two channels of the color to the horizontal and vertical axes of the gradient.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### ColorArea [#colorarea]
### ColorThumb [#colorthumb]
---
# Color Editor
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/color-editor
```
```bash
pnpm dlx shadcn@latest add @dotui/color-editor
```
```bash
yarn dlx shadcn@latest add @dotui/color-editor
```
```bash
bun x shadcn@latest add @dotui/color-editor
```
## Usage [#usage]
Use a color editor to let users adjust a color with a saturation/brightness area, channel sliders, and format-aware fields. Standalone, it manages its own color value; inside a [Color Picker](/docs/components/color-picker), it edits the picker's color instead.
```tsx
import { ColorEditor } from "@/components/ui/color-editor"
```
```tsx
```
## Anatomy [#anatomy]
`ColorEditor` renders a saturation/brightness area with channel sliders, then a row of format-aware fields. Omit children for the default layout, or compose the parts yourself.
```tsx
import {
ColorEditor,
ColorEditorArea,
ColorEditorFields,
} from "@/components/ui/color-editor"
```
```tsx
```
* `ColorEditorArea` — the color area, hue slider, and optional alpha slider.
* `ColorEditorFields` — channel inputs for the current format, with an optional format selector.
## Composition [#composition]
The default children render an area row and a fields row. Pass your own children to reorder, drop, or extend them — for example, dropping a swatch picker between the two parts.
```tsx
{/* ... */}
```
## Value [#value]
The value is a React Aria `Color`. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it. Pass a hex string (including alpha, e.g. `#5100FF80`) or a `Color` from `parseColor`.
```tsx
```
Inside a [Color Picker](/docs/components/color-picker), the editor adopts the
picker's color — `value`, `defaultValue`, and `onChange` are ignored.
## Color format [#color-format]
`ColorEditorFields` picks its channel inputs from the current format. Set the initial format with `defaultFormat` (`hex`, `rgb`, `hsl`, or `hsb`), or control it with `format` and `onFormatChange`.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### ColorEditor [#coloreditor]
### ColorEditorArea [#coloreditorarea]
### ColorEditorFields [#coloreditorfields]
---
# Color Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/color-field
```
```bash
pnpm dlx shadcn@latest add @dotui/color-field
```
```bash
yarn dlx shadcn@latest add @dotui/color-field
```
```bash
bun x shadcn@latest add @dotui/color-field
```
## Usage [#usage]
Use color fields to allow users to edit a color value using a text field.
```tsx
import { ColorField } from "@/components/ui/color-field"
import { Label } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
```
```tsx
```
## Anatomy [#anatomy]
A `ColorField` wraps a `Label` and an `Input`. To attach an icon, replace the bare `Input` with an `InputGroup` and place an `InputGroupAddon` on either side.
```tsx
import { ColorField } from "@/components/ui/color-field"
import { Label } from "@/components/ui/field"
import { Input, InputGroup, InputGroupAddon } from "@/components/ui/input"
```
```tsx
```
## Value [#value]
The value is a `Color` object. Pass a hex string to `defaultValue` for uncontrolled state, or control it with `value` + `onChange` using `parseColor`, and read it back with `color.toString('hex')`.
```tsx
import { type Color, parseColor } from 'react-aria-components'
const [color, setColor] = React.useState(parseColor('#7f007f'))
```
## Channels [#channels]
Set `colorSpace` and `channel` to bind the field to a single channel of a color space instead of the full hex value.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Color Picker
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/color-picker
```
```bash
pnpm dlx shadcn@latest add @dotui/color-picker
```
```bash
yarn dlx shadcn@latest add @dotui/color-picker
```
```bash
bun x shadcn@latest add @dotui/color-picker
```
## Usage [#usage]
Use color pickers to allow users to select a color from a palette or input a custom color value. The editing surface inside the popover is a [Color Editor](/docs/components/color-editor).
```tsx
import { Button } from "@/components/ui/button"
import { ColorEditor } from "@/components/ui/color-editor"
import { ColorPicker } from "@/components/ui/color-picker"
import { DialogContent } from "@/components/ui/dialog"
import { Popover } from "@/components/ui/popover"
```
```tsx
```
## Anatomy [#anatomy]
`ColorPicker` wraps a `Button` trigger and a `Popover` holding the editing surface. A `Button` with no children auto-fills with a `ColorSwatch` reflecting the current value.
```tsx
```
## Value [#value]
`ColorPicker` syncs a `Color` value across its children. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it. Both accept a hex string or a `Color` from `parseColor`.
```tsx
import { parseColor } from 'react-aria-components'
const [value, setValue] = React.useState(parseColor('hsl(26, 33%, 78%)'))
{/* ... */}
```
## Open state [#open-state]
The popover is uncontrolled by default. Use `defaultOpen`, or `isOpen` with `onOpenChange` to control it; `ColorPicker` forwards these to its internal dialog.
```tsx
{/* ... */}
```
## Examples [#examples]
## API Reference [#api-reference]
### ColorPicker [#colorpicker]
See [Color Editor](/docs/components/color-editor) for the editing surface API.
---
# Color Slider
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/color-slider
```
```bash
pnpm dlx shadcn@latest add @dotui/color-slider
```
```bash
yarn dlx shadcn@latest add @dotui/color-slider
```
```bash
bun x shadcn@latest add @dotui/color-slider
```
## Usage [#usage]
Use color sliders to allow users to adjust an individual channel of a color value.
```tsx
import { ColorSlider, ColorSliderControl } from "@/components/ui/color-slider"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
`ColorSlider` wraps a `ColorSliderControl` (the draggable track) and, optionally, a `ColorSliderOutput` (the current value as text) and a `Label`. If you render no children, `ColorSlider` falls back to a bare `ColorSliderControl`.
```tsx
import {
ColorSlider,
ColorSliderControl,
ColorSliderOutput,
} from "@/components/ui/color-slider"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Value [#value]
The value is a `Color` object. Use `defaultValue` for uncontrolled state — it accepts a color string like `#f00` or `hsl(0, 100%, 50%)`. For controlled state, pass `value` + `onChange`, where `value` is a parsed `Color` from `parseColor` and `onChange` receives a `Color`.
```tsx
import { parseColor } from 'react-aria-components'
const [value, setValue] = React.useState(parseColor('hsl(0, 100%, 50%)'))
```
Use `channel` to pick which channel the slider edits (`hue`, `saturation`, `lightness`, `alpha`…), and `colorSpace` (`rgb`, `hsl`, `hsb`) to interpret the value in a given space.
## Examples [#examples]
## API Reference [#api-reference]
### ColorSlider [#colorslider]
### ColorSliderControl [#colorslidercontrol]
### ColorSliderOutput [#colorslideroutput]
---
# Color Swatch Picker
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/color-swatch-picker
```
```bash
pnpm dlx shadcn@latest add @dotui/color-swatch-picker
```
```bash
yarn dlx shadcn@latest add @dotui/color-swatch-picker
```
```bash
bun x shadcn@latest add @dotui/color-swatch-picker
```
## Usage [#usage]
Use color swatch pickers to allow users to select a color from a list of swatches.
```tsx
import {
ColorSwatchPicker,
ColorSwatchPickerItem,
} from "@/components/ui/color-swatch-picker"
```
```tsx
```
## Anatomy [#anatomy]
```tsx
import {
ColorSwatchPicker,
ColorSwatchPickerItem,
} from "@/components/ui/color-swatch-picker"
```
```tsx
```
`ColorSwatchPicker` is the selectable list; each `ColorSwatchPickerItem` declares one swatch via its `color` prop and renders the color internally.
## Value [#value]
The value is the selected color. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it. Values are `Color` objects (via `parseColor`) or color strings, and `onChange` receives a `Color`.
```tsx
import { parseColor } from 'react-aria-components'
const [color, setColor] = React.useState(parseColor('#f80'))
```
## Examples [#examples]
## API Reference [#api-reference]
### ColorSwatchPicker [#colorswatchpicker]
### ColorSwatchPickerItem [#colorswatchpickeritem]
---
# Color Swatch
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/color-swatch
```
```bash
pnpm dlx shadcn@latest add @dotui/color-swatch
```
```bash
yarn dlx shadcn@latest add @dotui/color-swatch
```
```bash
bun x shadcn@latest add @dotui/color-swatch
```
## Usage [#usage]
Use color swatches to display a color sample.
```tsx
import { ColorSwatch } from "@/components/ui/color-swatch"
```
```tsx
```
## Value [#value]
The `color` prop accepts a hex or CSS color string, or a `Color` object from `parseColor`. Translucent colors render over a checkerboard so their transparency shows through.
```tsx
import { parseColor } from "react-aria-components"
```
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### ColorSwatch [#colorswatch]
---
# Combobox
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/combobox
```
```bash
pnpm dlx shadcn@latest add @dotui/combobox
```
```bash
yarn dlx shadcn@latest add @dotui/combobox
```
```bash
bun x shadcn@latest add @dotui/combobox
```
## Usage [#usage]
Use `Combobox` to allow users to filter a list of options to items matching a query and select an item from the list.
```tsx
import { Combobox } from "@/components/ui/combobox"
import { Input, InputGroup, InputGroupAddon } from "@/components/ui/input"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
import { Popover } from "@/components/ui/popover"
```
```tsx
Canada
France
```
## Anatomy [#anatomy]
`Combobox` is assembled from the field, input, list-box, and popover primitives. `InputGroup` wraps the text `Input` and an `InputGroupAddon` trigger; the `Popover` holds a `ListBox` of `ListBoxItem` options.
```tsx
```
## Value [#value]
The value is the selected item's key. Use `defaultSelectedKey` for uncontrolled state, or `selectedKey` with `onSelectionChange` to control it.
```tsx
const [country, setCountry] = React.useState('tn')
{/* ... */}
```
## Multiple selection [#multiple-selection]
Set `selectionMode="multiple"` to select several items; the value becomes an array of keys via `defaultValue`/`value`. Render `ComboboxValue` with a function to display the selected items as a `TagGroup`.
```tsx
selectionMode="multiple"
defaultValue={["next"]}
>
>
{({ selectedItems, state }) => (
state.setValue(state.value.filter((k) => !keys.has(k)))
}
>
{(item) => {item.name}}
)}
{/* ... */}
```
## Content [#content]
Pass static `ListBoxItem` children, or render options from data with `items` and a render function. Give each item a stable `id`, and a `textValue` when its content isn't a plain string.
```tsx
{(item) => (
{item.label}
)}
```
## Sections [#sections]
Group options with `ListBoxSection` and `ListBoxSectionHeader` — see the [Sections](#examples) demo.
## Async loading [#async-loading]
Source items from `useAsyncList` and pass `isLoading` to the `ListBox` to show a loading state while fetching.
```tsx
const list = useAsyncList({ async load({ signal }) { /* ... */ } })
{(item) => {item.name}}
```
## Custom values [#custom-values]
Set `allowsCustomValue` to let users submit text that doesn't match any option.
```tsx
{/* ... */}
```
## Examples [#examples]
## API Reference [#api-reference]
### Combobox [#combobox]
### ComboboxValue [#comboboxvalue]
---
# Command
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/command
```
```bash
pnpm dlx shadcn@latest add @dotui/command
```
```bash
yarn dlx shadcn@latest add @dotui/command
```
```bash
bun x shadcn@latest add @dotui/command
```
## Usage [#usage]
`Command` is a thin wrapper around React Aria's [Autocomplete](https://react-spectrum.adobe.com/react-aria/Autocomplete.html). It ships no input or list of its own — you compose it from primitives you already have: a [`SearchField`](/docs/components/search-field) for the query and a [`ListBox`](/docs/components/list-box) for the commands. As the user types, the list is filtered down to the items whose text matches the query.
```tsx
import { SearchIcon } from "lucide-react"
import { Command } from "@/components/ui/command"
import { Input, InputGroup, InputGroupAddon } from "@/components/ui/input"
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
import { SearchField } from "@/components/ui/search-field"
```
```tsx
console.log(key)}>
Calendar
Search Emoji
Calculator
```
Filtering matches against each item's **`textValue`**. String children set it automatically, but items with rich content — an icon, a keyboard shortcut — need an explicit `textValue` to stay searchable. Group related commands with `ListBoxSection` and `ListBoxSectionHeader`, and respond to a selection with the list's `onAction` callback.
Because the input and the list are ordinary primitives, anything they support works here too: put the `Command` inside a `Modal` for a `⌘K` palette, inside a `Popover` to filter a `Select`, or swap the `ListBox` for a `TagGroup`. See the [examples](#examples) below.
## Anatomy [#anatomy]
`Command` re-exports the underlying primitives under `Command*` aliases so the whole palette imports from one place: `CommandInput` is a `SearchField`, `CommandContent` is a `ListBox`, and `CommandItem`, `CommandSection`, and `CommandSectionHeader` map to their `ListBox*` counterparts.
```tsx
import {
Command,
CommandContent,
CommandInput,
CommandItem,
CommandSection,
CommandSectionHeader,
} from "@/components/ui/command"
```
```tsx
```
## Filtering [#filtering]
Matching is case- and punctuation-insensitive by default (`sensitivity: 'base'`, `ignorePunctuation: true`). Pass `filter` with any [`Intl.CollatorOptions`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Collator/Collator#options) to tune it — for example make matching accent-sensitive.
```tsx
{/* … */}
```
## Examples [#examples]
## API Reference [#api-reference]
`Command` renders only the autocomplete wrapper. The input is a [`SearchField`](/docs/components/search-field) and the list is a [`ListBox`](/docs/components/list-box) — `CommandInput` and `CommandContent` are re-exported aliases for those primitives, so refer to their pages for the full set of props.
### Command [#command]
### CommandInput [#commandinput]
### CommandContent [#commandcontent]
---
# Date Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/date-field
```
```bash
pnpm dlx shadcn@latest add @dotui/date-field
```
```bash
yarn dlx shadcn@latest add @dotui/date-field
```
```bash
bun x shadcn@latest add @dotui/date-field
```
## Usage [#usage]
Use `DateField` to allow users to enter and edit date values using a keyboard.
```tsx
import { DateField } from "@/components/ui/date-field"
import { DateInput } from "@/components/ui/input"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
`DateField` wraps a `Label`, a `DateInput` that renders the individually editable segments, and optionally a `Description` and `FieldError`.
```tsx
import { DateField } from "@/components/ui/date-field"
import { DateInput } from "@/components/ui/input"
import { Description, FieldError, Label } from "@/components/ui/field"
```
```tsx
```
## Value [#value]
Values are [`@internationalized/date`](https://react-spectrum.adobe.com/internationalized/date/index.html) objects. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
import { parseDate } from "@internationalized/date"
```
```tsx
```
Set `granularity` (`day`, `hour`, `minute`, or `second`) to control which segments render, and constrain the range with `minValue` and `maxValue`.
## Validation [#validation]
Mark the field with `isRequired`, or drive it with `isInvalid` and a custom `validate`. Errors surface through `FieldError`.
```tsx
Please select a date.
```
## Examples [#examples]
## API Reference [#api-reference]
### DateField [#datefield]
### DateInput [#dateinput]
### DateSegment [#datesegment]
---
# Date Picker
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/date-picker
```
```bash
pnpm dlx shadcn@latest add @dotui/date-picker
```
```bash
yarn dlx shadcn@latest add @dotui/date-picker
```
```bash
bun x shadcn@latest add @dotui/date-picker
```
## Usage [#usage]
Use date pickers to allow users to select a date using a field and a calendar popover.
```tsx
import { CalendarIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { DatePicker } from "@/components/ui/date-picker"
import { DialogContent } from "@/components/ui/dialog"
import { Label } from "@/components/ui/field"
import { DateInput, InputGroup, InputGroupAddon } from "@/components/ui/input"
import { Popover } from "@/components/ui/popover"
```
```tsx
```
## Anatomy [#anatomy]
A date picker assembles a date field and a calendar overlay. The `InputGroup` holds the `DateInput` and a trigger `Button`; the `Popover` reveals a `Calendar`. `Label`, `Description`, and `FieldError` are optional field parts.
```tsx
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import { DatePicker } from "@/components/ui/date-picker"
import { DialogContent } from "@/components/ui/dialog"
import { Description, FieldError, Label } from "@/components/ui/field"
import { DateInput, InputGroup, InputGroupAddon } from "@/components/ui/input"
import { Popover } from "@/components/ui/popover"
```
```tsx
```
## Value [#value]
The value is an [`@internationalized/date`](https://react-spectrum.adobe.com/internationalized/date/) object. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it. `granularity` (`"day"`, `"hour"`, `"minute"`, `"second"`) sets the smallest editable unit, and `minValue`/`maxValue` bound the selectable range.
```tsx
import { parseDate } from "@internationalized/date"
```
```tsx
```
## Date range [#date-range]
`DateRangePicker` selects a start and end date as a `{ start, end }` value. Use two `DateInput`s with `slot="start"` and `slot="end"`, and a `RangeCalendar` in the popover.
```tsx
import { parseDate } from "@internationalized/date"
import { RangeCalendar } from "@/components/ui/calendar"
import { DateRangePicker } from "@/components/ui/date-picker"
```
```tsx
–
```
## Examples [#examples]
## API Reference [#api-reference]
### DatePicker [#datepicker]
### DateRangePicker [#daterangepicker]
---
# Dialog
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/dialog
```
```bash
pnpm dlx shadcn@latest add @dotui/dialog
```
```bash
yarn dlx shadcn@latest add @dotui/dialog
```
```bash
bun x shadcn@latest add @dotui/dialog
```
## Usage [#usage]
Use dialog to grab the user's attention for critical tasks, like confirming actions, providing additional details, or capturing input.
```tsx
import { Button } from "@/components/ui/button"
import {
Dialog,
DialogBody,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
} from "@/components/ui/dialog"
import { Modal } from "@/components/ui/modal"
```
```tsx
```
## Anatomy [#anatomy]
The trigger `Button` and the overlay are siblings inside `Dialog`. The overlay (`Modal`, `Drawer`, or `Popover`) is a separate component the dialog does not ship, and `DialogContent` renders inside it. Pass `showCloseButton` to `DialogContent` for a built-in close button.
```tsx
```
## Role [#role]
Pass `role="alertdialog"` to `DialogContent` for destructive confirmations that interrupt the user and require a response.
```tsx
Delete project
This action cannot be undone.
```
## Open state [#open-state]
The dialog opens when the trigger is pressed. Control it with `isOpen` and `onOpenChange` (or set `defaultOpen`), and close it from inside with a `Button` that has `slot="close"`.
```tsx
const [isOpen, setOpen] = React.useState(false)
```
## Examples [#examples]
## API Reference [#api-reference]
### Dialog [#dialog]
### DialogContent [#dialogcontent]
### DialogHeader [#dialogheader]
### DialogTitle [#dialogtitle]
### DialogDescription [#dialogdescription]
### DialogBody [#dialogbody]
### DialogFooter [#dialogfooter]
---
# Drawer
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/drawer
```
```bash
pnpm dlx shadcn@latest add @dotui/drawer
```
```bash
yarn dlx shadcn@latest add @dotui/drawer
```
```bash
bun x shadcn@latest add @dotui/drawer
```
## Usage [#usage]
Use drawers to display content that slides in from the edge of the screen.
```tsx
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import { Drawer } from "@/components/ui/drawer"
```
```tsx
```
## Anatomy [#anatomy]
A `Drawer` has no built-in trigger. Wrap it in a `Dialog` with a `Button` child as the trigger, and put your content inside `DialogContent`.
```tsx
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import {
Drawer,
DrawerHandle,
DrawerSwipeArea,
DrawerProvider,
DrawerIndent,
DrawerIndentBackground,
} from "@/components/ui/drawer"
```
```tsx
```
`DrawerHandle` is a visible drag affordance. `DrawerSwipeArea` is an edge region that opens the drawer by swiping. `DrawerIndent` and `DrawerIndentBackground` wrap page content that scales and translates behind an open drawer, and `DrawerProvider` scopes visual state explicitly — most apps don't need it.
## Open state [#open-state]
Rendered under a `Dialog`, the drawer shares the dialog's open state, so the trigger `Button` opens it with no wiring. To drive it yourself, pass `isOpen` with `onOpenChange` (or `defaultOpen` for uncontrolled).
```tsx
const [isOpen, setIsOpen] = React.useState(false)
...
```
## Dismissal [#dismissal]
The drawer dismisses on swipe, outside interaction, and Escape. Disable each with `swipeToDismiss`, `isDismissable`, and `isKeyboardDismissDisabled` respectively.
```tsx
...
```
## Examples [#examples]
## API Reference [#api-reference]
### Drawer [#drawer]
### DrawerHandle [#drawerhandle]
### DrawerSwipeArea [#drawerswipearea]
### DrawerProvider [#drawerprovider]
### DrawerIndent [#drawerindent]
### DrawerIndentBackground [#drawerindentbackground]
---
# Drop Zone
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/drop-zone
```
```bash
pnpm dlx shadcn@latest add @dotui/drop-zone
```
```bash
yarn dlx shadcn@latest add @dotui/drop-zone
```
```bash
bun x shadcn@latest add @dotui/drop-zone
```
## Usage [#usage]
Use drop zones to allow users to drag and drop files or content into a designated area.
```tsx
import { DropZone, DropZoneLabel } from "@/components/ui/drop-zone"
```
```tsx
Drop files here
```
## Anatomy [#anatomy]
`DropZoneLabel` nests inside `DropZone` and provides its accessible name.
```tsx
```
## Handling drops [#handling-drops]
Read dropped data in `onDrop` from `e.items`, filtering by `kind` and `types`, and call `getText` on text items.
```tsx
import type { TextDropItem } from "react-aria-components"
```
```tsx
{
const items = await Promise.all(
e.items
.filter((item) => item.kind === "text" && item.types.has("text/plain"))
.map((item) => (item as TextDropItem).getText("text/plain")),
)
}}
>
Droppable
```
## Accepted drop types [#accepted-drop-types]
Restrict what the zone accepts by returning `'copy'` or `'cancel'` from `getDropOperation` based on the dragged `types`.
```tsx
(types.has("image/png") ? "copy" : "cancel")}
onDrop={handleDrop}
/>
```
## Pairing with FileTrigger [#pairing-with-filetrigger]
Add a `FileTrigger` with a `Button` so users can drop files or click to browse.
```tsx
Drag and drop files here
```
## Examples [#examples]
## API Reference [#api-reference]
### DropZone [#dropzone]
### DropZoneLabel [#dropzonelabel]
---
# Empty
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/empty
```
```bash
pnpm dlx shadcn@latest add @dotui/empty
```
```bash
yarn dlx shadcn@latest add @dotui/empty
```
```bash
bun x shadcn@latest add @dotui/empty
```
## Usage [#usage]
```tsx
import {
Empty,
EmptyDescription,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
```
```tsx
No projects
Get started by creating a new project.
```
## Anatomy [#anatomy]
`EmptyHeader` groups the media, title, and description; `EmptyContent` holds the actions below. Pass `variant="icon"` to `EmptyMedia` to render its child inside a bordered icon container.
```tsx
import {
Empty,
EmptyHeader,
EmptyMedia,
EmptyTitle,
EmptyDescription,
EmptyContent,
} from "@/components/ui/empty"
```
```tsx
{/* icon */}
{/* heading */}
{/* supporting text */}
{/* actions */}
```
## Examples [#examples]
## API Reference [#api-reference]
### Empty [#empty]
### EmptyHeader [#emptyheader]
### EmptyMedia [#emptymedia]
### EmptyTitle [#emptytitle]
### EmptyDescription [#emptydescription]
### EmptyContent [#emptycontent]
---
# Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/field
```
```bash
pnpm dlx shadcn@latest add @dotui/field
```
```bash
yarn dlx shadcn@latest add @dotui/field
```
```bash
bun x shadcn@latest add @dotui/field
```
## Usage [#usage]
```tsx
import { Field, Label, Description, FieldError } from "@/components/ui/field"
```
```tsx
We'll never share your email.
```
## Anatomy [#anatomy]
```tsx
import {
Field,
FieldContent,
Label,
Description,
FieldError,
FieldGroup,
Fieldset,
Legend,
} from "@/components/ui/field"
```
```tsx
```
`Field` wraps a control with its `Label`, `Description`, and `FieldError`. `FieldContent` stacks the label and description so they can sit beside the control. `FieldGroup` spaces stacked fields, and `Fieldset` with `Legend` semantically groups related fields.
## Accessible wiring [#accessible-wiring]
`Field` links the `Label` (`htmlFor`), the control (`id`), and the `Description` (`aria-describedby`) through context, so no manual ids are needed. Input-specific wrappers like `TextField`, `Select`, and `Checkbox` do this themselves — reach for `Field` only around standalone controls like `Switch`.
```tsx
Send me product updates.
```
`FieldError` renders validation messages and accepts a render function for the current validation state.
## Orientation [#orientation]
Set `orientation="horizontal"` to place the control beside its label, using `FieldContent` to stack the label and description on the left.
```tsx
Disable all connections.
```
## Examples [#examples]
## API Reference [#api-reference]
### Field [#field]
### Fieldset [#fieldset]
### Legend [#legend]
### FieldGroup [#fieldgroup]
### FieldContent [#fieldcontent]
### Label [#label]
### Description [#description]
### FieldError [#fielderror]
---
# File Trigger
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/file-trigger
```
```bash
pnpm dlx shadcn@latest add @dotui/file-trigger
```
```bash
yarn dlx shadcn@latest add @dotui/file-trigger
```
```bash
bun x shadcn@latest add @dotui/file-trigger
```
## Usage [#usage]
Use file triggers to allow users to upload files using any pressable element.
```tsx
import { Button } from "@/components/ui/button"
import { FileTrigger } from "@/components/ui/file-trigger"
```
```tsx
console.log(e)}>
```
## File selection [#file-selection]
`onSelect` receives a `FileList` (or `null`), so wrap it in `Array.from` to work with the files. Restrict what users can pick with `acceptedFileTypes`, allow multiple with `allowsMultiple`, pick whole folders with `acceptDirectory`, or open a device camera with `defaultCamera` (`user` or `environment`).
```tsx
{
if (e) console.log(Array.from(e).map((file) => file.name))
}}
>
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Form
## Installation [#installation]
`Form` isn't published as a standalone item yet — it's on the way.
## Usage [#usage]
Use forms to wrap groups of form elements and handle form submission with validation.
```tsx
import { Form } from "@/components/ui/form"
import { Button } from "@/components/ui/button"
import { TextField } from "@/components/ui/text-field"
import { Label } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
```
```tsx
```
## Validation [#validation]
Mark fields `isRequired` (or add `validate` per field) to enforce validation. By default `validationBehavior` is `'native'`, using the browser's constraint validation; set it to `'aria'` to keep the DOM valid and surface errors purely through ARIA. Pass server-side errors keyed by field `name` via `validationErrors`.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
| Prop | Type | Default | Description |
| -------------------- | --------------------------------------------------------- | ---------- | --------------------------------------------------- |
| `validationBehavior` | `'native' \| 'aria'` | `'native'` | Whether to use native HTML form validation or ARIA. |
| `validationErrors` | `ValidationErrors` | - | Validation errors to display on form fields. |
| `action` | `string \| FormHTMLAttributes['action']` | - | The URL to submit the form to. |
| `encType` | `string` | - | The encoding type to use for form submission. |
| `method` | `string` | - | The HTTP method to use for form submission. |
| `target` | `string` | - | The target window for form submission. |
| `autoComplete` | `string` | - | Whether the browser should autocomplete the form. |
| `autoCapitalize` | `string` | - | Whether text should be auto-capitalized. |
| `children` | `ReactNode` | - | The form content. |
| Event | Type | Description |
| ----------- | ----------------------------------------- | -------------------------------------------------- |
| `onSubmit` | `(e: FormEvent) => void` | Handler that is called when the form is submitted. |
| `onReset` | `(e: FormEvent) => void` | Handler that is called when the form is reset. |
| `onInvalid` | `(e: FormEvent) => void` | Handler that is called when validation fails. |
---
# Group
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/group
```
```bash
pnpm dlx shadcn@latest add @dotui/group
```
```bash
yarn dlx shadcn@latest add @dotui/group
```
```bash
bun x shadcn@latest add @dotui/group
```
## Usage [#usage]
```tsx
import { Group } from "@/components/ui/group"
```
```tsx
```
## Anatomy [#anatomy]
`Group` is the container; `GroupText` renders an inline text segment between controls (prefixes, suffixes, labels).
```tsx
import { Group, GroupText } from "@/components/ui/group"
```
```tsx
Label
```
Set `orientation` to `"vertical"` to stack children instead of the default `"horizontal"` row.
## Examples [#examples]
## API Reference [#api-reference]
---
# Input Group
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/input
```
```bash
pnpm dlx shadcn@latest add @dotui/input
```
```bash
yarn dlx shadcn@latest add @dotui/input
```
```bash
bun x shadcn@latest add @dotui/input
```
## Usage [#usage]
```tsx
import { Input, InputGroup, InputGroupAddon } from "@/components/ui/input"
```
```tsx
https://
```
## Anatomy [#anatomy]
An `InputGroup` wraps an `Input` or `TextArea` together with one or more `InputGroupAddon` parts. Order the children to place an addon before or after the control.
```tsx
import {
Input,
InputGroup,
InputGroupAddon,
TextArea,
} from "@/components/ui/input"
```
```tsx
```
* `InputGroup` — the wrapper; clicking anywhere inside focuses the control.
* `InputGroupAddon` — a slot for buttons, icons, labels, or `Kbd` alongside the control.
* `Input` / `TextArea` — the wrapped control.
## Sizes [#sizes]
Set `size` on the `InputGroup` to scale the group and its control. Available sizes are `sm`, `md` (default), and `lg`.
```tsx
…
…
…
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Input
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/input
```
```bash
pnpm dlx shadcn@latest add @dotui/input
```
```bash
yarn dlx shadcn@latest add @dotui/input
```
```bash
bun x shadcn@latest add @dotui/input
```
## Usage [#usage]
Use `Input` to allow users to enter text. Combine with `InputGroup` and `InputGroupAddon` to add icons, buttons, or labels alongside the input.
```tsx
import { Input } from "@/components/ui/input"
```
```tsx
```
## Sizes [#sizes]
Use the `size` prop to control the input height. Available sizes are `sm`, `md` (default), and `lg`.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Kbd
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/kbd
```
```bash
pnpm dlx shadcn@latest add @dotui/kbd
```
```bash
yarn dlx shadcn@latest add @dotui/kbd
```
```bash
bun x shadcn@latest add @dotui/kbd
```
## Usage [#usage]
```tsx
import { Kbd } from "@/components/ui/kbd"
```
```tsx
⌘K
```
## Anatomy [#anatomy]
Use `Kbd` for a single key. Wrap several in `KbdGroup` to present a key combination as one unit.
```tsx
import { Kbd, KbdGroup } from "@/components/ui/kbd"
```
```tsx
⌘
K
```
## Examples [#examples]
## API Reference [#api-reference]
### Kbd [#kbd]
### KbdGroup [#kbdgroup]
---
# Link
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/link
```
```bash
pnpm dlx shadcn@latest add @dotui/link
```
```bash
yarn dlx shadcn@latest add @dotui/link
```
```bash
bun x shadcn@latest add @dotui/link
```
## Usage [#usage]
```tsx
import { Link } from "@/components/ui/link"
```
```tsx
Documentation
```
## As a link [#as-a-link]
Passing `href` renders a real ``; add `target="_blank"` (with `rel`) to open a new tab. To route internal `href`s through your app router, override `Link` in your project the same way [Breadcrumbs](/docs/components/breadcrumbs) does for `BreadcrumbLink`.
```tsx
dotUI
```
## Examples [#examples]
## API Reference [#api-reference]
---
# List Box
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/list-box
```
```bash
pnpm dlx shadcn@latest add @dotui/list-box
```
```bash
yarn dlx shadcn@latest add @dotui/list-box
```
```bash
bun x shadcn@latest add @dotui/list-box
```
## Usage [#usage]
Use list boxes to display a list of options and allow users to select one or more of them.
```tsx
import { ListBox, ListBoxItem } from "@/components/ui/list-box"
```
```tsx
Option 1
Option 2
Option 3
```
## Anatomy [#anatomy]
```tsx
import {
ListBox,
ListBoxItem,
ListBoxItemLabel,
ListBoxItemDescription,
ListBoxSection,
ListBoxSectionHeader,
} from "@/components/ui/list-box"
```
```tsx
```
`ListBox` is the container. Each `ListBoxItem` is an option; give it a `ListBoxItemLabel` and optional `ListBoxItemDescription` when it holds more than a string. Group options under a `ListBoxSection` with a `ListBoxSectionHeader`.
## Content [#content]
Pass items statically as children, or dynamically via `items` plus a render function. Each item needs a stable `id`.
```tsx
{(item) => {item.name}}
```
## Selection [#selection]
`selectionMode` sets whether options are selectable and how many. Control the selection with `selectedKeys` and `onSelectionChange`, or use `defaultSelectedKeys` for uncontrolled state. Pass `onAction` to make rows pressable without selecting them.
```tsx
Option A
Option B
```
## Disabled items [#disabled-items]
Disable individual options by passing their keys to `disabledKeys` — the rest of the list stays interactive.
```tsx
Option A
Option B
```
## Async loading [#async-loading]
Load items on scroll with `isLoading` and `onLoadMore`, typically driven by `useAsyncList`, and render an empty state via `renderEmptyState`. See the [Async Loading](#examples) example.
## Links [#links]
Give a `ListBoxItem` an `href` to render it as a link. With a client router configured, links use client-side navigation.
```tsx
Home
Settings
```
## Examples [#examples]
## API Reference [#api-reference]
### ListBox [#listbox]
### ListBoxItem [#listboxitem]
### ListBoxSection [#listboxsection]
### ListBoxSectionHeader [#listboxsectionheader]
### ListBoxLoader [#listboxloader]
### ListBoxVirtualizer [#listboxvirtualizer]
---
# Loader
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/loader
```
```bash
pnpm dlx shadcn@latest add @dotui/loader
```
```bash
yarn dlx shadcn@latest add @dotui/loader
```
```bash
bun x shadcn@latest add @dotui/loader
```
## Usage [#usage]
```tsx
import { Loader } from "@/components/ui/loader"
```
```tsx
```
## Accessibility [#accessibility]
`Loader` renders a React Aria `ProgressBar` and has no visible text, so pass `aria-label` to name the operation for screen readers.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Marker
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/marker
```
```bash
pnpm dlx shadcn@latest add @dotui/marker
```
```bash
yarn dlx shadcn@latest add @dotui/marker
```
```bash
bun x shadcn@latest add @dotui/marker
```
## Usage [#usage]
```tsx
import { Marker, MarkerContent } from "@/components/ui/marker"
```
```tsx
Today
```
## Anatomy [#anatomy]
`Marker` is the row; `variant` picks its treatment — `separator` centers the
content between two hairlines, `border` underlines the row, and the default
renders it plain. `MarkerIcon` holds an optional leading icon, hidden from
assistive technology.
```tsx
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"
```
```tsx
3 unread messages
```
## Examples [#examples]
## API Reference [#api-reference]
### Marker [#marker]
### MarkerIcon [#markericon]
### MarkerContent [#markercontent]
---
# Mention
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/mention
```
```bash
pnpm dlx shadcn@latest add @dotui/mention
```
```bash
yarn dlx shadcn@latest add @dotui/mention
```
```bash
bun x shadcn@latest add @dotui/mention
```
## Usage [#usage]
`Mention` wires a mention experience onto the [TokenField](/docs/components/token-field) component: compose a `TokenInput` for the editable area plus a `Popover` + `Menu` for the suggestions, and `Mention` injects the wiring (value, caret-anchored popover, filtering, keyboard navigation, insertion) through context. Typing the trigger character (`@` by default) opens the list at the caret and filters as you type; selecting an item inserts it as an inline token.
```tsx
import { Mention } from "@/components/ui/mention"
import { MenuContent, MenuItem } from "@/components/ui/menu"
import { Popover } from "@/components/ui/popover"
import { TokenInput } from "@/components/ui/token-field"
```
```tsx
{(person) => }
```
Add a `Label` before the input when you want a visible label; otherwise give the input an `aria-label`. Without `allowsNewlines` the field stays single-line.
```tsx
{/* ...suggestions */}
```
## Anatomy [#anatomy]
```tsx
import { Mention } from "@/components/ui/mention"
import { MenuContent, MenuItem } from "@/components/ui/menu"
import { Popover } from "@/components/ui/popover"
import { TokenInput } from "@/components/ui/token-field"
```
```tsx
```
`Mention` owns the value and caret-anchored popover, the [TokenField](/docs/components/token-field)'s `TokenInput` renders the text and inline tokens, and the `Popover` + `MenuContent` render the suggestions. These are children, not props — there are no bespoke sub-components.
## Value [#value]
The value is a `TokenFieldValue` — a list of plain-text and token segments, imported from `react-aria-components`. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it; `toString()` joins the segments back into plain text, and each token segment carries the inserted item's key as its `value`.
```tsx
import { TokenFieldValue } from "react-aria-components"
const [value, setValue] = React.useState(
() =>
new TokenFieldValue([
{ type: "text", text: "Hey " },
{ type: "token", text: "@alexmiller" },
]),
)
{/* ... */}
```
## Triggers [#triggers]
The `trigger` prop changes the character that opens the list, and `getItemText` maps a selected item's key to the text inserted after the trigger.
```tsx
String(key)}>
{/* ... */}
```
Pass a regular expression to support several triggers at once. Children may be a function receiving the active trigger and query, so the suggestions can depend on which trigger the user typed.
```tsx
{({ trigger }) => (
<>
{(item) => }
>
)}
```
## Placement [#placement]
Set `placement` to move the suggestions popover relative to the caret (default `"bottom start"`).
## Examples [#examples]
## API Reference [#api-reference]
`Mention` composes the [TokenField](/docs/components/token-field)'s `TokenInput` for the editable area, and the [Popover](/docs/components/popover) and [Menu](/docs/components/menu) primitives for the suggestion list.
### Mention [#mention]
---
# Menu
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/menu
```
```bash
pnpm dlx shadcn@latest add @dotui/menu
```
```bash
yarn dlx shadcn@latest add @dotui/menu
```
```bash
bun x shadcn@latest add @dotui/menu
```
## Usage [#usage]
Use menus to display a list of actions or options that a user can choose from.
```tsx
import { Button } from "@/components/ui/button"
import { Menu, MenuContent, MenuItem } from "@/components/ui/menu"
import { Popover } from "@/components/ui/popover"
```
```tsx
```
## Anatomy [#anatomy]
A `Menu` links a trigger (`Button`) to an overlay (`Popover`) that wraps the `MenuContent`. Each `MenuItem` auto-wraps string children in a `MenuItemLabel`; add a `MenuItemDescription` for secondary text, group items with `MenuSection` + `MenuSectionHeader`, and nest a submenu with `MenuSub`.
```tsx
import { Button } from "@/components/ui/button"
import {
Menu,
MenuContent,
MenuItem,
MenuItemLabel,
MenuItemDescription,
MenuSection,
MenuSectionHeader,
MenuSub,
} from "@/components/ui/menu"
import { Popover } from "@/components/ui/popover"
```
```tsx
```
## Triggers [#triggers]
Menus open on press by default. Set `trigger="longPress"` when press is reserved for a primary action — the menu then opens on long press (or Alt + ▼):
```tsx
```
Set `trigger="contextMenu"` to open the menu at the pointer on right click, long press on touch, or OS keyboard shortcuts. The trigger doesn't have to be a `Button` — wrap any focusable element in React Aria's `Pressable`.
```tsx
import { Pressable } from "react-aria-components"
```
```tsx
```
## Selection [#selection]
Set `selectionMode` to `single` or `multiple` on `MenuContent` to turn items into checkbox or radio items. Control the selection with `selectedKeys`/`onSelectionChange` (or `defaultSelectedKeys`), and disable specific items with `disabledKeys`.
```tsx
```
## Links [#links]
Pass `href` to a `MenuItem` to render it as an ``; add `target` for the link target. Client-side routing depends on your router setup.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### Menu [#menu]
### MenuContent [#menucontent]
### MenuItem [#menuitem]
### MenuItemLabel [#menuitemlabel]
### MenuItemDescription [#menuitemdescription]
### MenuSection [#menusection]
### MenuSectionHeader [#menusectionheader]
### MenuSub [#menusub]
---
# MessageScroller
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/message-scroller
```
```bash
pnpm dlx shadcn@latest add @dotui/message-scroller
```
```bash
yarn dlx shadcn@latest add @dotui/message-scroller
```
```bash
bun x shadcn@latest add @dotui/message-scroller
```
## Usage [#usage]
```tsx
import {
MessageScroller,
MessageScrollerButton,
MessageScrollerContent,
MessageScrollerItem,
MessageScrollerProvider,
MessageScrollerViewport,
} from "@/components/ui/message-scroller"
```
```tsx
{messages.map((message) => (
{/* message */}
))}
```
## Anatomy [#anatomy]
`MessageScrollerProvider` holds the scroll state — autoscroll follows new
content while the reader sits at the bottom edge and lets go the moment they
scroll away. `MessageScrollerViewport` is the scrollable area,
`MessageScrollerContent` lays the messages out, and each
`MessageScrollerItem` renders lazily as it nears the viewport, so long
conversations stay cheap. `MessageScrollerButton` appears once the reader
leaves the edge and scrolls them back to the newest message.
The `useMessageScroller`, `useMessageScrollerScrollable` and
`useMessageScrollerVisibility` hooks expose imperative scrolling and scroll
state to anything inside the provider.
## Examples [#examples]
## API Reference [#api-reference]
### MessageScrollerProvider [#messagescrollerprovider]
### MessageScroller [#messagescroller]
### MessageScrollerViewport [#messagescrollerviewport]
### MessageScrollerContent [#messagescrollercontent]
### MessageScrollerItem [#messagescrolleritem]
### MessageScrollerButton [#messagescrollerbutton]
---
# Message
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/message
```
```bash
pnpm dlx shadcn@latest add @dotui/message
```
```bash
yarn dlx shadcn@latest add @dotui/message
```
```bash
bun x shadcn@latest add @dotui/message
```
## Usage [#usage]
```tsx
import { Message, MessageContent } from "@/components/ui/message"
```
```tsx
{/* bubbles, text, rich content */}
```
## Anatomy [#anatomy]
`Message` lays out one turn: `align` picks the side of the thread and flips
the row, so the `MessageAvatar` sits on the sender's side. `MessageContent`
is the content column — put a [Bubble](/docs/components/bubble) inside for
contained messages, or plain content for full-width assistant replies.
`MessageHeader` and `MessageFooter` carry metadata like the sender name,
timestamp, or delivery status, and consecutive messages from one sender stack
in a `MessageGroup`.
```tsx
import {
Message,
MessageAvatar,
MessageContent,
MessageFooter,
MessageHeader,
} from "@/components/ui/message"
```
```tsx
{/* */}
Lena · 2:14 PM
{/* content */}
Seen
```
## Examples [#examples]
## API Reference [#api-reference]
### MessageGroup [#messagegroup]
### Message [#message]
### MessageAvatar [#messageavatar]
### MessageContent [#messagecontent]
### MessageHeader [#messageheader]
### MessageFooter [#messagefooter]
---
# Modal
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/modal
```
```bash
pnpm dlx shadcn@latest add @dotui/modal
```
```bash
yarn dlx shadcn@latest add @dotui/modal
```
```bash
bun x shadcn@latest add @dotui/modal
```
## Usage [#usage]
Use modals to display content in a layer that overlays the page content.
```tsx
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import { Modal } from "@/components/ui/modal"
```
```tsx
```
## Anatomy [#anatomy]
`Modal` composes the full overlay stack for you, so basic usage is just `{children}`. For full control, import the parts and assemble them yourself.
```tsx
import {
ModalOverlay,
ModalBackdrop,
ModalViewport,
ModalPanel,
} from "@/components/ui/modal"
```
```tsx
{children}
```
`ModalOverlay` renders the overlay and holds the open state, `ModalBackdrop` dims the page, `ModalViewport` centers the modal, and `ModalPanel` is the panel that wraps the dialog content.
## Open state [#open-state]
The trigger is `Dialog`: wrap a `Button` and the `Modal` in it and opening is handled for you. To control it, pass `isOpen`/`defaultOpen` and `onOpenChange` to the modal.
```tsx
Modal content
```
## Examples [#examples]
## API Reference [#api-reference]
### Modal [#modal]
### ModalOverlay [#modaloverlay]
### ModalBackdrop [#modalbackdrop]
### ModalViewport [#modalviewport]
### ModalContent [#modalcontent]
---
# Number Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/number-field
```
```bash
pnpm dlx shadcn@latest add @dotui/number-field
```
```bash
yarn dlx shadcn@latest add @dotui/number-field
```
```bash
bun x shadcn@latest add @dotui/number-field
```
## Usage [#usage]
Use `NumberField` to allow users to enter a numeric value with keyboard or increment/decrement buttons.
```tsx
import { NumberField } from "@/components/ui/number-field"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
Wrap the `Input` in a `NumberFieldGroup` alongside `NumberFieldDecrement` and `NumberFieldIncrement` to expose the stepper buttons. Add `Label` and `FieldError` for labelling and validation.
```tsx
import {
NumberField,
NumberFieldGroup,
NumberFieldDecrement,
NumberFieldIncrement,
} from "@/components/ui/number-field"
import { Input } from "@/components/ui/input"
import { Label, FieldError } from "@/components/ui/field"
```
```tsx
```
## Value [#value]
The value is a number. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it — `onChange` receives the new number.
```tsx
const [value, setValue] = React.useState(69)
```
## Format options [#format-options]
Pass `formatOptions` (an `Intl.NumberFormat` options object) to format the value as a decimal, percent, currency, or unit.
```tsx
```
## Min, max, and step [#min-max-and-step]
Use `minValue` and `maxValue` to constrain the range, and `step` to set the increment applied by the stepper buttons.
```tsx
```
## Validation [#validation]
Mark the field with `isRequired`, drive the invalid state with `isInvalid`, and render the message with `FieldError`.
```tsx
Please fill out this field.
```
## Examples [#examples]
## API Reference [#api-reference]
### NumberField [#numberfield]
### NumberFieldGroup [#numberfieldgroup]
---
# OTP Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/otp-field
```
```bash
pnpm dlx shadcn@latest add @dotui/otp-field
```
```bash
yarn dlx shadcn@latest add @dotui/otp-field
```
```bash
bun x shadcn@latest add @dotui/otp-field
```
## Usage [#usage]
Use `OTPField` with `OTPFieldGroup` and the existing `Input` component to compose passcode slots.
```tsx
import { OTPField, OTPFieldGroup } from "@/components/ui/otp-field"
import { Label } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
```
```tsx
```
## Anatomy [#anatomy]
`OTPField` wraps a `Label`, one or more `OTPFieldGroup`s of single-character `Input` slots, and optional `Description`, `FieldError`, and `OTPFieldSeparator` parts. `length` sets how many slots render. Split the slots across `OTPFieldGroup`s with an `OTPFieldSeparator` between them.
```tsx
import {
OTPField,
OTPFieldGroup,
OTPFieldSeparator,
} from "@/components/ui/otp-field"
import { Description, FieldError, Label } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
```
```tsx
```
## Value [#value]
The value is a string sized by `length`. Pass `defaultValue` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
const [value, setValue] = React.useState('')
{/* ... */}
```
## Validation [#validation]
Mark the field `isRequired`, drive `isInvalid` to surface a `FieldError` alongside a `Description`, and set `name` for form submission. Use `validationType` to restrict input to `"numeric"` (default) or `"alphanumeric"`.
```tsx
{/* ... */}
Enter the code we sent you.
Enter all six characters.
```
## Examples [#examples]
## API Reference [#api-reference]
### OTPField [#otpfield]
### OTPFieldGroup [#otpfieldgroup]
### OTPFieldSeparator [#otpfieldseparator]
---
# Pagination
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/pagination
```
```bash
pnpm dlx shadcn@latest add @dotui/pagination
```
```bash
yarn dlx shadcn@latest add @dotui/pagination
```
```bash
bun x shadcn@latest add @dotui/pagination
```
## Usage [#usage]
Compose pagination from its parts. Provide an `href` on each link to navigate between pages, or wire `onPress` to drive client-side state.
```tsx
import {
Pagination,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationList,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination"
```
```tsx
1
2
```
## Anatomy [#anatomy]
```tsx
```
`Pagination` is the `nav` landmark and `PaginationList` the `ul` that wraps each `PaginationItem`. `PaginationLink` is a page cell, `PaginationPrevious` and `PaginationNext` are the directional links, and `PaginationEllipsis` marks a gap of skipped pages.
## State [#state]
Pagination holds no page state of its own — you own the current page. Wire `onPress` on each link to update it, pass `isActive` to the current page (which sets `aria-current="page"` and the active style), and `isDisabled` to cap the ends.
```tsx
setPage(page - 1)} />
setPage(n)}>
{n}
```
## Framework Setup [#framework-setup]
`PaginationLink`, `PaginationPrevious`, and `PaginationNext` are built on the Link button, so they pick up router integration from your `button.tsx` — there's nothing pagination-specific to wire up. See the [Button](/docs/components/button) docs to connect `LinkButton` to your framework's router, and pagination links with an `href` will route through it automatically.
## Examples [#examples]
## API Reference [#api-reference]
### Pagination [#pagination]
### PaginationList [#paginationlist]
### PaginationItem [#paginationitem]
### PaginationLink [#paginationlink]
### PaginationPrevious [#paginationprevious]
### PaginationNext [#paginationnext]
### PaginationEllipsis [#paginationellipsis]
---
# Popover
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/popover
```
```bash
pnpm dlx shadcn@latest add @dotui/popover
```
```bash
yarn dlx shadcn@latest add @dotui/popover
```
```bash
bun x shadcn@latest add @dotui/popover
```
## Usage [#usage]
Use popovers to display rich content in a floating container that appears above other content.
```tsx
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"
import { Popover } from "@/components/ui/popover"
```
```tsx
```
## Anatomy [#anatomy]
A `Dialog` wraps the trigger `Button` and the `Popover`; the popover holds a `DialogContent` with its title and body.
```tsx
import { Button } from "@/components/ui/button"
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog"
import { Popover } from "@/components/ui/popover"
```
```tsx
```
## Placement [#placement]
Set `placement` to position the popover relative to its trigger. Values are a side with an optional alignment, e.g. `bottom start` or `bottom end`.
```tsx
```
## Arrow [#arrow]
Set `showArrow` to render an arrow pointing at the trigger (default `false`).
```tsx
```
## Open state [#open-state]
Control visibility with `isOpen` and `onOpenChange` on the `Dialog` trigger (or `defaultOpen` for uncontrolled).
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Progress Bar
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/progress-bar
```
```bash
pnpm dlx shadcn@latest add @dotui/progress-bar
```
```bash
yarn dlx shadcn@latest add @dotui/progress-bar
```
```bash
bun x shadcn@latest add @dotui/progress-bar
```
## Usage [#usage]
Use progress bars to show the progression of a system operation or task.
```tsx
import { ProgressBar, ProgressBarControl } from "@/components/ui/progress-bar"
```
```tsx
```
## Anatomy [#anatomy]
`ProgressBar` wraps `ProgressBarControl` (the track) and an optional `ProgressBarOutput` that renders the value as text.
```tsx
import {
ProgressBar,
ProgressBarControl,
ProgressBarOutput,
} from "@/components/ui/progress-bar"
```
```tsx
```
## Value [#value]
`value` is measured against `minValue` and `maxValue`, which default to `0` and `100`. When progress can't be measured, set `isIndeterminate`.
```tsx
```
## Value formatting [#value-formatting]
Pass `formatOptions` (an `Intl.NumberFormat` config) to format the value `ProgressBarOutput` renders, or replace the text entirely with `valueLabel`.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### ProgressBar [#progressbar]
### ProgressBarControl [#progressbarcontrol]
### ProgressBarOutput [#progressbaroutput]
---
# QR Code
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/qr-code
```
```bash
pnpm dlx shadcn@latest add @dotui/qr-code
```
```bash
yarn dlx shadcn@latest add @dotui/qr-code
```
```bash
bun x shadcn@latest add @dotui/qr-code
```
## Usage [#usage]
```tsx
import { QRCode } from "@/components/ui/qr-code"
```
```tsx
```
Pass an `aria-label` describing the destination — to a screen reader, an unlabeled QR code is meaningless.
## Logo [#logo]
Pass children to display a logo at the center of the code. The modules behind it are excavated so it sits in clean whitespace, and the default error correction level is raised to `H` to compensate for the covered area.
```tsx
```
## Error correction [#error-correction]
QR codes embed redundancy so they scan even when partially obscured. The `errorCorrection` prop sets the level: `L` (7%), `M` (15%), `Q` (25%) or `H` (30%) — higher levels produce a denser code.
The code renders with the theme's foreground on the theme's background. Scanners expect dark modules on a light background; in dark themes the code is inverted, which some scanners reject. Always test scanning with your real theme, colors and logo.
## Examples [#examples]
## API Reference [#api-reference]
---
# Questionnaire
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/questionnaire
```
```bash
pnpm dlx shadcn@latest add @dotui/questionnaire
```
```bash
yarn dlx shadcn@latest add @dotui/questionnaire
```
```bash
bun x shadcn@latest add @dotui/questionnaire
```
## Usage [#usage]
```tsx
import {
Questionnaire,
QuestionnaireActions,
QuestionnaireChoice,
QuestionnaireChoices,
QuestionnaireItem,
QuestionnaireNext,
QuestionnairePrevious,
QuestionnaireSubmit,
QuestionnaireTitle,
} from "@/components/ui/questionnaire"
```
```tsx
What best describes your role?
Designer
Engineer
```
## Anatomy [#anatomy]
`Questionnaire` renders a form and shows one `QuestionnaireItem` at a time.
An item is single-answer by default and multi-answer with `multiple`; its
choices render as radios or checkboxes accordingly, with optional letter or
number `shortcuts`. Free-text questions use `QuestionnaireInput`, and
`QuestionnaireError` shows the active question's validation message.
The navigation renders itself: `QuestionnairePrevious` hides on the first
question, `QuestionnaireSkip` only appears on optional questions,
`QuestionnaireNext` advances, and `QuestionnaireSubmit` takes its place on
the last question. `QuestionnaireProgress` reads "1 of 4"-style progress.
## Examples [#examples]
## API Reference [#api-reference]
### Questionnaire [#questionnaire]
### QuestionnaireProgress [#questionnaireprogress]
### QuestionnaireItem [#questionnaireitem]
### QuestionnaireTitle [#questionnairetitle]
### QuestionnaireDescription [#questionnairedescription]
### QuestionnaireChoices [#questionnairechoices]
### QuestionnaireChoice [#questionnairechoice]
### QuestionnaireChoiceDescription [#questionnairechoicedescription]
### QuestionnaireInput [#questionnaireinput]
### QuestionnaireError [#questionnaireerror]
### QuestionnaireActions [#questionnaireactions]
### QuestionnairePrevious [#questionnaireprevious]
### QuestionnaireSkip [#questionnaireskip]
### QuestionnaireNext [#questionnairenext]
### QuestionnaireSubmit [#questionnairesubmit]
---
# Radio Group
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/radio-group
```
```bash
pnpm dlx shadcn@latest add @dotui/radio-group
```
```bash
yarn dlx shadcn@latest add @dotui/radio-group
```
```bash
bun x shadcn@latest add @dotui/radio-group
```
## Usage [#usage]
Use radio group to allow users to select a single option from a short list of related options.
```tsx
import { Radio, RadioControl, RadioGroup } from "@/components/ui/radio-group"
import { FieldGroup, Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
A `RadioGroup` wraps a `Label` and a `FieldGroup` of `Radio` options. Each `Radio` holds a `RadioControl` (which renders the `RadioIndicator`) and its own `Label`.
```tsx
import {
Radio,
RadioControl,
RadioGroup,
RadioIndicator,
} from "@/components/ui/radio-group"
import {
Description,
FieldError,
FieldGroup,
Label,
} from "@/components/ui/field"
```
```tsx
```
Pass a string as the `Radio` child to render its `RadioControl` and `Label` for you.
```tsx
Next.js
```
## Value [#value]
The value is the selected `Radio`'s string `value`. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
const [framework, setFramework] = React.useState('nextjs')
{/* ... */}
```
## Validation [#validation]
Mark the group `isRequired`, and render a `FieldError` to surface the message when `isInvalid`.
```tsx
{/* ... */}
Please select a framework.
```
## Examples [#examples]
## API Reference [#api-reference]
### RadioGroup [#radiogroup]
### Radio [#radio]
### RadioControl [#radiocontrol]
### RadioIndicator [#radioindicator]
---
# Search Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/search-field
```
```bash
pnpm dlx shadcn@latest add @dotui/search-field
```
```bash
yarn dlx shadcn@latest add @dotui/search-field
```
```bash
bun x shadcn@latest add @dotui/search-field
```
## Usage [#usage]
Use `SearchField` to allow users to enter and clear a search query.
```tsx
import { SearchField } from "@/components/ui/search-field"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
A `SearchField` wraps an optional `Label`, an `Input`, and optional `Description` and `FieldError`. Rendered on its own it supplies a default `InputGroup` with a search icon and a clear button, so `` is enough.
```tsx
import { SearchField } from "@/components/ui/search-field"
import { Label, Description, FieldError } from "@/components/ui/field"
import { Input } from "@/components/ui/input"
```
```tsx
```
## Value [#value]
The value is a string. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
const [value, setValue] = React.useState('')
```
## Submit & clear [#submit--clear]
`onSubmit` fires with the current value when the user presses Enter; `onClear` fires when they press Escape or the clear button, which appears once the field is non-empty.
```tsx
search(value)} onClear={() => reset()}>
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Segmented Control
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/segmented-control
```
```bash
pnpm dlx shadcn@latest add @dotui/segmented-control
```
```bash
yarn dlx shadcn@latest add @dotui/segmented-control
```
```bash
bun x shadcn@latest add @dotui/segmented-control
```
## Usage [#usage]
Use a segmented control for a small set of mutually exclusive options — view modes, ranges, filters. It's built on `ToggleButtonGroup` with single selection, and the indicator slides between segments (React Aria's `SelectionIndicator`).
```tsx
import {
SegmentedControl,
SegmentedControlItem,
} from "@/components/ui/segmented-control"
```
```tsx
Day
Week
Month
```
## Anatomy [#anatomy]
A `SegmentedControl` wraps one `SegmentedControlItem` per option. Each item needs a unique `id`, which is the value the control reports as selected.
```tsx
import {
SegmentedControl,
SegmentedControlItem,
} from "@/components/ui/segmented-control"
```
```tsx
…
```
## Selection [#selection]
Selection is single-only and can never be empty (`disallowEmptySelection`). Use `defaultSelectedKeys` for uncontrolled state, or `selectedKeys` with `onSelectionChange` to control it — both are a `Set` of item ids.
```tsx
const [selected, setSelected] = React.useState(new Set(['week']))
Day
Week
Month
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Select
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/select
```
```bash
pnpm dlx shadcn@latest add @dotui/select
```
```bash
yarn dlx shadcn@latest add @dotui/select
```
```bash
bun x shadcn@latest add @dotui/select
```
## Usage [#usage]
Use `Select` to allow users to choose a single option from a collapsible list of options when space is limited.
```tsx
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
} from "@/components/ui/select"
```
```tsx
```
## Anatomy [#anatomy]
```tsx
import {
Select,
SelectTrigger,
SelectContent,
SelectItem,
SelectSection,
SelectSectionHeader,
} from "@/components/ui/select"
```
```tsx
```
`Select` holds the state, `SelectTrigger` opens the popover and shows the current value, `SelectContent` is the option list, and `SelectItem` is an option. `SelectSection` with `SelectSectionHeader` groups items.
## Value [#value]
`Select` selects by key: each `SelectItem` has an `id`, and the value is that id. Use `defaultSelectedKey` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
```
## Selection [#selection]
Selection is single by default. Pass the `M` type param as `'multiple'` (`SelectProps`) and set `selectionMode="multiple"` on `SelectContent` to allow selecting several options.
## Content [#content]
Render items statically as children, or dynamically by passing `items` to `SelectContent` with a render function.
```tsx
{(item) => {item.name}}
```
## Async loading [#async-loading]
Feed a `useAsyncList` result into `SelectContent` via `items`, and wire `isLoading` and `onLoadMore` for infinite scrolling. See the [Async Loading](#examples) example.
## Validation [#validation]
Add a `Label` and a `FieldError` inside `Select`, and set `isRequired` or `isInvalid` to surface validation.
```tsx
import { FieldError, Label } from "@/components/ui/field"
```
```tsx
```
## Composition [#composition]
`SelectTrigger` wraps `Button`, `SelectContent` wraps `Popover` + `ListBox`, and `SelectItem` re-exports `ListBoxItem`. For full control, drop the wrappers and compose the primitives directly.
```tsx
import { ChevronDownIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
ListBox,
ListBoxItem,
ListBoxSection,
ListBoxSectionHeader,
} from "@/components/ui/list-box"
import { Popover } from "@/components/ui/popover"
import { Select, SelectValue } from "@/components/ui/select"
```
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### Select [#select]
### SelectValue [#selectvalue]
### SelectContent [#selectcontent]
---
# Separator
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/separator
```
```bash
pnpm dlx shadcn@latest add @dotui/separator
```
```bash
yarn dlx shadcn@latest add @dotui/separator
```
```bash
bun x shadcn@latest add @dotui/separator
```
## Usage [#usage]
Use separators to visually divide content in lists, menus, or other places.
```tsx
import { Separator } from "@/components/ui/separator"
```
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Sidebar
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/sidebar
```
```bash
pnpm dlx shadcn@latest add @dotui/sidebar
```
```bash
yarn dlx shadcn@latest add @dotui/sidebar
```
```bash
bun x shadcn@latest add @dotui/sidebar
```
## Anatomy [#anatomy]
A sidebar is built from a `SidebarProvider` wrapping the `Sidebar` and a `SidebarInset` (the main content). Inside the sidebar, compose a header, scrollable content split into groups of menus, and a footer.
```tsx
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarGroupLabel,
SidebarHeader,
SidebarInset,
SidebarMenu,
SidebarMenuButton,
SidebarMenuItem,
SidebarProvider,
SidebarTrigger,
} from "@/components/ui/sidebar"
```
```tsx
Platform
Dashboard
{/* page content */}
```
## Usage [#usage]
The `Sidebar` positions itself relative to the `SidebarProvider`, so the whole shell is self-contained. For a full-screen app, give the provider the viewport height and let the content scroll inside the inset:
```tsx
{/* ... */}
{/* ... */}
```
Below the `md` breakpoint the sidebar renders as an off-canvas drawer, toggled by the same `SidebarTrigger`. The sidebar can also be toggled from anywhere with ⌘+B (Ctrl+B).
### Links [#links]
Pass `href` to `SidebarMenuButton` (or `SidebarMenuSubButton`) to render it as a link, and `isActive` to mark the current page (which also sets `aria-current="page"`).
```tsx
Dashboard
```
### useSidebar [#usesidebar]
Read or control the sidebar state from any descendant of `SidebarProvider`:
```tsx
const {
state,
isOpen,
setOpen,
isMobile,
openMobile,
setOpenMobile,
toggleSidebar,
} = useSidebar()
```
### Controlled state [#controlled-state]
Drive the open state yourself with `isOpen` and `onOpenChange` on `SidebarProvider` — useful for persisting it (e.g. in a cookie or `localStorage`).
## Examples [#examples]
## API Reference [#api-reference]
### SidebarProvider [#sidebarprovider]
### Sidebar [#sidebar]
### SidebarInset [#sidebarinset]
### SidebarTrigger [#sidebartrigger]
### SidebarRail [#sidebarrail]
### SidebarHeader [#sidebarheader]
### SidebarFooter [#sidebarfooter]
### SidebarContent [#sidebarcontent]
### SidebarSeparator [#sidebarseparator]
### SidebarGroup [#sidebargroup]
### SidebarGroupLabel [#sidebargrouplabel]
### SidebarGroupAction [#sidebargroupaction]
### SidebarGroupContent [#sidebargroupcontent]
### SidebarMenu [#sidebarmenu]
### SidebarMenuItem [#sidebarmenuitem]
### SidebarMenuButton [#sidebarmenubutton]
### SidebarMenuAction [#sidebarmenuaction]
### SidebarMenuBadge [#sidebarmenubadge]
### SidebarMenuSkeleton [#sidebarmenuskeleton]
### SidebarMenuSub [#sidebarmenusub]
### SidebarMenuSubItem [#sidebarmenusubitem]
### SidebarMenuSubButton [#sidebarmenusubbutton]
---
# Skeleton
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/skeleton
```
```bash
pnpm dlx shadcn@latest add @dotui/skeleton
```
```bash
yarn dlx shadcn@latest add @dotui/skeleton
```
```bash
bun x shadcn@latest add @dotui/skeleton
```
## Usage [#usage]
Use skeleton components as placeholders while content is loading.
```tsx
import { Skeleton } from "@/components/ui/skeleton"
```
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### Skeleton [#skeleton]
---
# Slider
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/slider
```
```bash
pnpm dlx shadcn@latest add @dotui/slider
```
```bash
yarn dlx shadcn@latest add @dotui/slider
```
```bash
bun x shadcn@latest add @dotui/slider
```
## Usage [#usage]
Use slider to allow users to select a value from within a given range.
```tsx
import { Slider, SliderControl } from "@/components/ui/slider"
```
```tsx
```
## Anatomy [#anatomy]
`SliderControl` renders the track, fill, and thumbs for you, so most sliders only need `Slider` + `SliderControl`. Compose the parts by hand for full control over layout.
```tsx
import {
Slider,
SliderControl,
SliderTrack,
SliderFill,
SliderThumb,
SliderOutput,
} from "@/components/ui/slider"
```
```tsx
```
## Value [#value]
A single number renders a standard slider; a `number[]` renders a multi-thumb range. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
```
## Range and step [#range-and-step]
`minValue` and `maxValue` set the bounds (default `0`–`100`), and `step` snaps movement to fixed increments.
```tsx
```
## Format [#format]
`formatOptions` accepts any `Intl.NumberFormat` options to format the `SliderOutput` label, such as currency or percent.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
### Slider [#slider]
### SliderControl [#slidercontrol]
### SliderTrack [#slidertrack]
### SliderFill [#sliderfill]
### SliderThumb [#sliderthumb]
### SliderOutput [#slideroutput]
---
# Switch
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/switch
```
```bash
pnpm dlx shadcn@latest add @dotui/switch
```
```bash
yarn dlx shadcn@latest add @dotui/switch
```
```bash
bun x shadcn@latest add @dotui/switch
```
## Usage [#usage]
Use switch for communicating activation (e.g. on/off states), while checkboxes are best used for communicating selection (e.g. multiple table rows).
```tsx
import { Label } from "@/components/ui/field"
import { Switch, SwitchControl } from "@/components/ui/switch"
```
```tsx
```
## Anatomy [#anatomy]
A `Switch` wraps a `SwitchControl` (which auto-renders its `SwitchIndicator` and `SwitchThumb`) and a `Label`. Pass a string child for the label shorthand, or omit children for a standalone control with an `aria-label`.
```tsx
import { Label } from '@/components/ui/field'
import {
Switch,
SwitchControl,
SwitchIndicator,
SwitchThumb,
} from '@/components/ui/switch'
Focus mode
```
## Value [#value]
The switch is on or off. Use `defaultSelected` for uncontrolled state, or `isSelected` with `onChange` to control it.
```tsx
const [isSelected, setSelected] = React.useState(true)
Focus mode
```
## Examples [#examples]
## API Reference [#api-reference]
### Switch [#switch]
### SwitchControl [#switchcontrol]
### SwitchIndicator [#switchindicator]
### SwitchThumb [#switchthumb]
---
# Table
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/table
```
```bash
pnpm dlx shadcn@latest add @dotui/table
```
```bash
yarn dlx shadcn@latest add @dotui/table
```
```bash
bun x shadcn@latest add @dotui/table
```
## Usage [#usage]
Use tables to display data in rows and columns with support for selection, sorting, and more.
```tsx
import {
Table,
TableBody,
TableCell,
TableColumn,
TableContainer,
TableFooter,
TableHeader,
TableRow,
TableVirtualizer,
} from "@/components/ui/table"
```
```tsx
Name
Type
Date Modified
Games
File folder
6/7/2020
Total
1 item
```
Use `TableContainer` to control the scroll region.
```tsx
```
By default, `TableContainer` renders a plain `div` so the table uses native CSS auto layout. Set `resizable` to opt into React Aria's resizable table layout. In that mode, use `width`, `defaultWidth`, `minWidth`, and `maxWidth` on `TableColumn`.
```tsx
```
Use `TableVirtualizer` for large collections. It uses the table layout exported by this component so row, cell, and selection column alignment stays consistent. Row and header heights default to the active density.
```tsx
```
## Anatomy [#anatomy]
A `Table` composes a `TableHeader` of `TableColumn`s with a `TableBody` of `TableRow`s and `TableCell`s, optionally a `TableFooter`, all inside a `TableContainer` scroll region. Mark one column `isRowHeader` so each row is labeled by that cell.
```tsx
import {
Table,
TableBody,
TableCell,
TableColumn,
TableContainer,
TableFooter,
TableHeader,
TableRow,
} from "@/components/ui/table"
```
```tsx
Name
Type
Games
File folder
1 item
```
## Content [#content]
Pass static `TableRow`s as children, or drive the table from data by giving `TableHeader` and `TableBody` an `items` array with a render function. Give each `TableColumn` an `id` matching a data key, and pass the same `columns` to each `TableRow`.
```tsx
{(column) => (
{column.name}
)}
{(item) => (
{(column) => {item[column.id]}}
)}
```
## Selection [#selection]
Set `selectionMode` to `single` or `multiple` to enable row selection. Control it with `selectedKeys` and `onSelectionChange` (the value is `'all'` or a `Set` of keys), and pass `disallowEmptySelection` to keep at least one row selected.
```tsx
```
## Sorting [#sorting]
Mark sortable columns with `allowsSorting`, then hold a `sortDescriptor` (`{ column, direction }`) and update it via `onSortChange` — you sort the data yourself.
```tsx
```
## Async loading [#async-loading]
Pair `useAsyncList` with `TableBody`'s `onLoadMore` and `isLoading` for infinite loading; `TableLoadMore` renders the loading row.
```tsx
const list = useAsyncList({ async load({ signal }) { /* ... */ } })
{/* ... */}
```
## Examples [#examples]
## API Reference [#api-reference]
### TableContainer [#tablecontainer]
### Table [#table]
### TableHeader [#tableheader]
### TableColumn [#tablecolumn]
### TableBody [#tablebody]
### TableFooter [#tablefooter]
### TableRow [#tablerow]
### TableCell [#tablecell]
### TableLoadMore [#tableloadmore]
### TableDropIndicator [#tabledropindicator]
### TableVirtualizer [#tablevirtualizer]
---
# Tabs
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/tabs
```
```bash
pnpm dlx shadcn@latest add @dotui/tabs
```
```bash
yarn dlx shadcn@latest add @dotui/tabs
```
```bash
bun x shadcn@latest add @dotui/tabs
```
## Usage [#usage]
Use tabs to organize content into multiple sections and allow users to navigate between them.
```tsx
import { Tab, TabList, TabPanel, Tabs } from "@/components/ui/tabs"
```
```tsx
Overview
Usage
Settings
Overview content
Usage content
Settings content
```
## Anatomy [#anatomy]
```tsx
import { Tab, TabList, TabPanel, Tabs } from "@/components/ui/tabs"
```
```tsx
```
`Tabs` provides selection state, `TabList` groups the `Tab` titles, and each `TabPanel` renders the content for the `Tab` whose `id` matches.
## Selection [#selection]
Each `Tab` and `TabPanel` is keyed by `id`. Use `defaultSelectedKey` for uncontrolled state, or `selectedKey` with `onSelectionChange` to control it.
```tsx
const [selectedKey, setSelectedKey] = React.useState('overview')
{/* … */}
```
## Keyboard activation [#keyboard-activation]
By default, focusing a tab with the arrow keys selects it. Set `keyboardActivation="manual"` to require Enter or Space to switch panels.
```tsx
{/* … */}
```
## Links [#links]
Pass `href` to a `Tab` to render an anchor for tab-based navigation. Use it with your client router's link integration for internal routes.
```tsx
Overview
```
## Examples [#examples]
## API Reference [#api-reference]
### Tabs [#tabs]
### TabList [#tablist]
### Tab [#tab]
### TabIndicator [#tabindicator]
### TabPanel [#tabpanel]
---
# Tag Group
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/tag-group
```
```bash
pnpm dlx shadcn@latest add @dotui/tag-group
```
```bash
yarn dlx shadcn@latest add @dotui/tag-group
```
```bash
bun x shadcn@latest add @dotui/tag-group
```
## Usage [#usage]
```tsx
import { TagGroup, TagList, Tag } from "@/components/ui/tag-group"
```
```tsx
React
TypeScript
```
## Anatomy [#anatomy]
A `TagGroup` wraps an optional `Label` and a `TagList` of `Tag` items.
```tsx
import { TagGroup, TagList, Tag } from "@/components/ui/tag-group"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Selection [#selection]
Set `selectionMode` to `single` or `multiple` to make tags selectable, giving each `Tag` an `id`. Control selection with `selectedKeys` + `onSelectionChange`, or default it with `defaultSelectedKeys`.
```tsx
News
Gaming
Travel
```
## Removal [#removal]
Pass `onRemove` to `TagGroup` to make tags removable — each `Tag` renders a remove button, and users can also delete a focused tag with ⌫.
```tsx
remove(keys)}>
News
Gaming
```
## Content [#content]
Render tags statically as children, or pass `items` to `TagList` with a render function to build them from data.
```tsx
{(item) => {item.name}}
```
## Links [#links]
Pass `href` to a `Tag` to render it as an ``; add `target` for the link target. Client-side routing depends on your router setup.
```tsx
Tailwind
```
## Examples [#examples]
## API Reference [#api-reference]
### TagGroup [#taggroup]
### TagList [#taglist]
### Tag [#tag]
---
# Text Area
## Installation [#installation]
`TextArea` ships with the input primitives, so install `text-field`.
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/text-field
```
```bash
pnpm dlx shadcn@latest add @dotui/text-field
```
```bash
yarn dlx shadcn@latest add @dotui/text-field
```
```bash
bun x shadcn@latest add @dotui/text-field
```
## Usage [#usage]
Use `TextArea` to allow users to enter multi-line text content.
```tsx
import { TextField } from "@/components/ui/text-field"
import { TextArea, InputGroup, InputGroupAddon } from "@/components/ui/input"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Auto-resize [#auto-resize]
`TextArea` grows its height to fit its content as the user types. This is automatic — there's no prop to toggle it.
## Examples [#examples]
## API Reference [#api-reference]
---
# TextField
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/text-field
```
```bash
pnpm dlx shadcn@latest add @dotui/text-field
```
```bash
yarn dlx shadcn@latest add @dotui/text-field
```
```bash
bun x shadcn@latest add @dotui/text-field
```
## Usage [#usage]
Use a `TextField` to allow users to input custom text entries with a keyboard.
```tsx
import { TextField } from "@/components/ui/text-field"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
A `TextField` wraps a `Label`, an `Input`, and optional `Description` and `FieldError`. Wrap the `Input` in an `InputGroup` with `InputGroupAddon` to render a prefix or suffix inside the field.
```tsx
import { TextField } from "@/components/ui/text-field"
import { Label, Description, FieldError } from "@/components/ui/field"
import { Input, InputGroup, InputGroupAddon } from "@/components/ui/input"
```
```tsx
```
## Value [#value]
The value is a string. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it.
```tsx
const [value, setValue] = React.useState('')
```
## Validation [#validation]
Mark a field with `isRequired`, and supply a custom `validate` function that returns an error string. By default validation is native (browser); set `validationBehavior="aria"` to defer to your own logic. Errors render in `FieldError`.
```tsx
(value.includes("@") ? null : "Enter a valid email")}
>
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Time Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/time-field
```
```bash
pnpm dlx shadcn@latest add @dotui/time-field
```
```bash
yarn dlx shadcn@latest add @dotui/time-field
```
```bash
bun x shadcn@latest add @dotui/time-field
```
## Usage [#usage]
Use `TimeField` to allow users to enter and edit time values using a keyboard.
```tsx
import { TimeField } from "@/components/ui/time-field"
import { DateInput } from "@/components/ui/input"
import { Label } from "@/components/ui/field"
```
```tsx
```
## Anatomy [#anatomy]
`TimeField` wraps a `Label`, the `DateInput` that holds the editable time segments, and an optional `Description` or `FieldError`.
```tsx
import { TimeField } from "@/components/ui/time-field"
import { DateInput } from "@/components/ui/input"
import { Label, Description, FieldError } from "@/components/ui/field"
```
```tsx
```
## Value [#value]
Values are `Time` objects from `@internationalized/date`. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it. Parse a string with `parseTime`.
```tsx
import { Time } from "@internationalized/date"
```
```tsx
```
## Granularity [#granularity]
`granularity` sets the smallest editable segment — `hour`, `minute` (the default), or `second`.
```tsx
```
## Hour cycle [#hour-cycle]
`hourCycle` forces 12- or 24-hour display regardless of the locale.
```tsx
```
## Validation [#validation]
Set `isRequired` or `isInvalid` and render messages with `FieldError`; `minValue` and `maxValue` constrain the allowed time.
```tsx
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Time Picker
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/time-picker
```
```bash
pnpm dlx shadcn@latest add @dotui/time-picker
```
```bash
yarn dlx shadcn@latest add @dotui/time-picker
```
```bash
bun x shadcn@latest add @dotui/time-picker
```
## Usage [#usage]
Use time pickers to allow users to select a time using a field and a scrollable column popover.
```tsx
import { ClockIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { DialogContent } from "@/components/ui/dialog"
import { Label } from "@/components/ui/field"
import { DateInput, InputGroup, InputGroupAddon } from "@/components/ui/input"
import { Popover } from "@/components/ui/popover"
import { TimePicker, TimePickerColumns } from "@/components/ui/time-picker"
```
```tsx
```
## Anatomy [#anatomy]
There is no React Aria `TimePicker`, so it's composed from field and overlay primitives: `TimePicker` wraps a labeled `InputGroup` (the editable `DateInput` plus a `Button` trigger in an `InputGroupAddon`) and a `Popover` whose `DialogContent` renders the scrollable `TimePickerColumns`. `Description` and `FieldError` are optional field slots.
```tsx
```
## Value [#value]
The value is an `@internationalized/date` `Time` object. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it. Bound the selectable range with `minValue` and `maxValue`.
```tsx
import { Time } from '@internationalized/date'
const [value, setValue] = React.useState(new Time(9, 30))
{/* ... */}
```
## Granularity [#granularity]
`granularity` (`"hour"`, `"minute"`, or `"second"`) controls both the editable segments and which scrollable columns render. `hourCycle` switches between 12- and 24-hour display.
```tsx
{/* ... */}
```
## Open state [#open-state]
The popover is uncontrolled by default. Open it initially with `defaultOpen`, or control it with `isOpen` and `onOpenChange`.
```tsx
{/* ... */}
```
## Examples [#examples]
## API Reference [#api-reference]
### TimePicker [#timepicker]
---
# Toast
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/toast
```
```bash
pnpm dlx shadcn@latest add @dotui/toast
```
```bash
yarn dlx shadcn@latest add @dotui/toast
```
```bash
bun x shadcn@latest add @dotui/toast
```
## Usage [#usage]
```tsx
import { ToastProvider, toastManager } from "@/components/ui/toast"
```
```tsx
```
```tsx
toastManager.add({
title: "Your message has been sent.",
})
toastManager.add({
title: "Changes saved",
description: "Your update is live.",
type: "success",
})
```
## Imperative API [#imperative-api]
Toasts aren't rendered as JSX. Mount `` once at your app root, then push notifications imperatively with `toastManager`. `add` returns an id you can pass to `close`.
```tsx
import { ToastProvider, toastManager } from "@/components/ui/toast"
```
```tsx
```
```tsx
const id = toastManager.add({ title: "Your message has been sent." })
toastManager.close(id)
```
## Variants [#variants]
Pass `type` to `add` to select a semantic variant, each with its own icon and color. Values are `neutral`, `success`, `error`, `danger`, `warning`, `info`, and `loading`. `neutral` renders no icon.
```tsx
toastManager.add({
title: "Changes saved",
description: "Your update is live.",
type: "success",
})
```
## Actions [#actions]
Pass `actionProps` to render an action button inside the toast, typically to undo the operation and close the current toast by id.
```tsx
const id = toastManager.add({
title: "Message archived",
type: "info",
actionProps: {
children: "Undo",
onClick: () => toastManager.close(id),
},
})
```
## Promise [#promise]
Use `toastManager.promise` to drive loading, success, and error states from a promise. Each key takes the same options as `add`.
```tsx
toastManager.promise(publish(), {
loading: { title: "Publishing changes", type: "loading" },
success: { title: "Published", type: "success" },
error: { title: "Publish failed", type: "error" },
})
```
## Placement [#placement]
The `position` prop on `ToastProvider` sets the viewport corner and derives the swipe-to-dismiss direction. Values are `top-left`, `top-center`, `top-right`, `bottom-left`, `bottom-center`, and `bottom-right`; it defaults to `bottom-right`.
```tsx
```
## Provider options [#provider-options]
`ToastProvider` caps visible toasts with `limit` (default `3`) and sets the auto-dismiss duration in milliseconds with `timeout` (default `5000`).
```tsx
```
## Examples [#examples]
No examples yet.
## API Reference [#api-reference]
---
# Toggle Button Group
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/toggle-button-group
```
```bash
pnpm dlx shadcn@latest add @dotui/toggle-button-group
```
```bash
yarn dlx shadcn@latest add @dotui/toggle-button-group
```
```bash
bun x shadcn@latest add @dotui/toggle-button-group
```
## Usage [#usage]
Use toggle button groups to let users toggle between multiple options.
```tsx
import { ToggleButton } from "@/components/ui/toggle-button"
import { ToggleButtonGroup } from "@/components/ui/toggle-button-group"
```
```tsx
Left
Center
Right
```
## Selection [#selection]
Each `ToggleButton` needs an `id`; selection keys map to those ids. Selection is `single` by default — set `selectionMode="multiple"` to allow several. Use `defaultSelectedKeys` for uncontrolled state, or `selectedKeys` with `onSelectionChange` to control it, and pass `disallowEmptySelection` to keep at least one selected.
```tsx
const [selected, setSelected] = React.useState(new Set(['bold']))
Bold
Italic
Underline
```
## Examples [#examples]
## API Reference [#api-reference]
---
# Toggle Button
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/toggle-button
```
```bash
pnpm dlx shadcn@latest add @dotui/toggle-button
```
```bash
yarn dlx shadcn@latest add @dotui/toggle-button
```
```bash
bun x shadcn@latest add @dotui/toggle-button
```
## Usage [#usage]
A toggle button switches a selection on or off, like pinning or starring an item.
```tsx
import { ToggleButton } from "@/components/ui/toggle-button"
```
```tsx
Pin
```
## Variants [#variants]
Use the `variant` prop to set the visual style of the toggle button.
## Sizes [#sizes]
Use the `size` prop to set the size of the toggle button.
## With icon [#with-icon]
Add the `data-icon="inline-start"` or `data-icon="inline-end"` attribute to the icon for the correct spacing.
## Icon buttons [#icon-buttons]
Use the `isIconOnly` prop for icon-only toggle buttons.
Provide an `aria-label` to give the button an accessible name.
## Selection [#selection]
Use `defaultSelected` to set the initial state, or `isSelected` with `onChange` to control it.
## API Reference [#api-reference]
---
# Token Field
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/token-field
```
```bash
pnpm dlx shadcn@latest add @dotui/token-field
```
```bash
yarn dlx shadcn@latest add @dotui/token-field
```
```bash
bun x shadcn@latest add @dotui/token-field
```
## About [#about]
`TokenField` is built on the [TokenField](https://react-aria.adobe.com/TokenField) primitive from `react-aria-components`. The primitive handles content-editable editing, IME composition, undo/redo, token-aware clipboard and drag behaviour, and screen-reader announcements.
## Usage [#usage]
Compose a `TokenField` with a `TokenInput` for the editable area, and a `Label` before it when you want a visible label (otherwise give the input an `aria-label`). Without `allowsNewlines` the field stays single-line.
```tsx
import { Label } from "@/components/ui/field"
import { TokenField, TokenInput } from "@/components/ui/token-field"
```
```tsx
```
## Anatomy [#anatomy]
```tsx
```
`TokenField` owns the value and provides the label and description slots, `TokenInput` renders the text and inline tokens, and `Token` renders a single inline token. Tokens render as `Token`s by default; pass a render function as `TokenInput`'s children to customize them.
```tsx
{(token) => {token.text}}
```
## Value [#value]
The value is a `TokenFieldValue` — a list of plain-text and token segments, imported from `react-aria-components`. Use `defaultValue` for uncontrolled state, or `value` with `onChange` to control it; `toString()` joins the segments back into plain text.
```tsx
import { TokenFieldValue } from "react-aria-components"
const [value, setValue] = React.useState(
() =>
new TokenFieldValue([
{ type: "text", text: "Hello " },
{ type: "token", text: "@sarahjones" },
]),
)
{/* ... */}
```
## Tokenization [#tokenization]
Subclass `TokenFieldValue` and override `tokenize` to convert typed text into tokens automatically — for hashtags, tag inputs, or structured search filters. `tokenize` receives the text of an edited region and returns the segments it should become.
```tsx
class TagFieldValue extends TokenFieldValue {
protected tokenize(text: string): TokenFieldSegment[] {
// split on commas/spaces and return text + token segments
}
}
```
## Autocomplete [#autocomplete]
For trigger-based suggestions (`@`-mentions, `/`-commands) use the [Mention](/docs/components/mention) component, which wires a caret-anchored suggestions menu onto the token field.
## Examples [#examples]
## API Reference [#api-reference]
### TokenField [#tokenfield]
### TokenInput [#tokeninput]
### Token [#token]
---
# Tooltip
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/tooltip
```
```bash
pnpm dlx shadcn@latest add @dotui/tooltip
```
```bash
yarn dlx shadcn@latest add @dotui/tooltip
```
```bash
bun x shadcn@latest add @dotui/tooltip
```
## Usage [#usage]
Use tooltips to provide contextual information about an element when it receives focus or the user hovers over it.
```tsx
import { Button } from "@/components/ui/button"
import { Tooltip, TooltipContent } from "@/components/ui/tooltip"
```
```tsx
Tooltip content
```
## Anatomy [#anatomy]
`Tooltip` wraps a focusable trigger (any element that takes focus, like a `Button` or `Link`) and a `TooltipContent`. The trigger opens the tooltip on hover or focus.
```tsx
import { Tooltip, TooltipContent } from "@/components/ui/tooltip"
```
```tsx
```
## Delay [#delay]
`Tooltip` opens after a `delay` (default `700`ms) on hover and closes after `closeDelay` (default `0`) when the pointer leaves.
```tsx
Opens instantly
```
## Open state [#open-state]
Use `defaultOpen` for uncontrolled open state, or `isOpen` with `onOpenChange` to control it.
```tsx
Controlled
```
## Examples [#examples]
## API Reference [#api-reference]
### Tooltip [#tooltip]
### TooltipContent [#tooltipcontent]
---
# Tree
## Installation [#installation]
npm
pnpm
yarn
bun
```bash
npx shadcn@latest add @dotui/tree
```
```bash
pnpm dlx shadcn@latest add @dotui/tree
```
```bash
yarn dlx shadcn@latest add @dotui/tree
```
```bash
bun x shadcn@latest add @dotui/tree
```
## Usage [#usage]
Use a tree to display nested, hierarchical data such as a file system or
category navigation. Each row is a `TreeItem` whose `TreeItemContent` holds the
label; nested `TreeItem`s become its children.
```tsx
import { Tree, TreeItem, TreeItemContent } from "@/components/ui/tree"
```
```tsx
Documents
Weekly report
```
When rendering data dynamically, pass `items` to the `Tree` and a `Collection`
to each `TreeItem` for its children.
```tsx
import { Collection } from "react-aria-components"
```
```tsx
{function renderItem(item) {
return (
{item.name}
{item.children && (
{renderItem}
)}
)
}}
```
## Anatomy [#anatomy]
A `Tree` wraps `TreeItem`s. Each `TreeItem` holds a `TreeItemContent` for its row — the expand chevron, optional checkbox and drag handle, and the label — and nests child `TreeItem`s directly beneath it.
```tsx
```
## Selection [#selection]
Set `selectionMode` to `single` or `multiple` to make rows selectable. Control the selection with `selectedKeys` and `onSelectionChange`, typed as `Selection` from `react-aria-components`. Use `disabledKeys` to make specific rows non-interactive.
```tsx
import { useState } from 'react'
import type { Selection } from 'react-aria-components'
const [selectedKeys, setSelectedKeys] = useState(new Set(['report']))
{items}
```
## Expansion [#expansion]
Set `defaultExpandedKeys` to expand parents by default (uncontrolled), or control which parents are open with `expandedKeys` and `onExpandedChange`.
```tsx
{items}
```
## Links [#links]
Pass `href` to a `TreeItem` to render it as an ``; add `target` for the link target. Client-side routing depends on your router setup.
```tsx
Weekly report
```
## Examples [#examples]
## API Reference [#api-reference]
### Tree [#tree]
### TreeItem [#treeitem]
### TreeItemContent [#treeitemcontent]