# 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 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
`; 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) => {person.name}} ``` 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) => {item.id}} )} ``` ## 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 Edit Duplicate Delete ``` ## 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 Label Description Section Item Submenu Nested item ``` ## 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
Right click me
{/* ... */}
``` ## 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 Top Bottom Right ``` ## 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 X ``` ## 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 Modal content ``` ## 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 Popover Title

Popover content

``` ## 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 Name Type {/* ... */}
``` 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 Name {/* ... */}
``` ## 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