snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
All checks were successful
Release / Create Version PR or Publish Stable Release (push) Has been skipped
Release / Publish Prerelease to NPM (push) Has been skipped
Monitor Registries / Monitor registry health (push) Has been skipped

This commit is contained in:
upstream-mirror
2026-09-15 22:44:43 +05:00
commit 1416db152c
5727 changed files with 630238 additions and 0 deletions

View File

@@ -0,0 +1,165 @@
---
title: Accordion
description: A vertically stacked set of interactive headings that each reveal a section of content.
base: base
component: true
links:
doc: https://base-ui.com/react/components/accordion
api: https://base-ui.com/react/components/accordion#api-reference
---
<ComponentPreview
styleName="base-nova"
name="accordion-demo"
align="start"
previewClassName="*:data-[slot=accordion]:max-w-sm h-[300px]"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add accordion
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="accordion"
title="components/ui/accordion.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Accordion,
AccordionContent,
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion"
```
```tsx showLineNumbers
<Accordion defaultValue={["item-1"]}>
<AccordionItem value="item-1">
<AccordionTrigger>Is it accessible?</AccordionTrigger>
<AccordionContent>
Yes. It adheres to the WAI-ARIA design pattern.
</AccordionContent>
</AccordionItem>
</Accordion>
```
## Composition
Use the following composition to build an `Accordion`:
```text
Accordion
├── AccordionItem
│ ├── AccordionTrigger
│ └── AccordionContent
└── AccordionItem
├── AccordionTrigger
└── AccordionContent
```
## Basic
A basic accordion that shows one item at a time. The first item is open by default.
<ComponentPreview
styleName="base-nova"
name="accordion-basic"
align="start"
previewClassName="*:data-[slot=accordion]:max-w-sm h-[300px]"
/>
## Multiple
Use the `multiple` prop to allow multiple items to be open at the same time.
<ComponentPreview
styleName="base-nova"
name="accordion-multiple"
align="start"
previewClassName="*:data-[slot=accordion]:max-w-sm h-[450px]"
/>
## Disabled
Use the `disabled` prop on `AccordionItem` to disable individual items.
<ComponentPreview
styleName="base-nova"
name="accordion-disabled"
align="start"
previewClassName="*:data-[slot=accordion]:max-w-sm h-[300px]"
/>
## Borders
Add `border` to the `Accordion` and `border-b last:border-b-0` to the `AccordionItem` to add borders to the items.
<ComponentPreview
styleName="base-nova"
name="accordion-borders"
align="start"
previewClassName="*:data-[slot=accordion]:max-w-sm h-[300px]"
/>
## Card
Wrap the `Accordion` in a `Card` component.
<ComponentPreview
styleName="base-nova"
name="accordion-card"
align="start"
previewClassName="*:data-[slot=accordion]:max-w-sm h-[435px]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="accordion-rtl"
align="start"
direction="rtl"
/>
## API Reference
See the [Base UI](https://base-ui.com/react/components/accordion#api-reference) documentation for more information.

View File

@@ -0,0 +1,185 @@
---
title: Alert Dialog
description: A modal dialog that interrupts the user with important content and expects a response.
featured: true
base: base
component: true
links:
doc: https://base-ui.com/react/components/alert-dialog
api: https://base-ui.com/react/components/alert-dialog#api-reference
---
<ComponentPreview
styleName="base-nova"
name="alert-dialog-demo"
previewClassName="h-56"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add alert-dialog
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="alert-dialog"
title="components/ui/alert-dialog.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog"
```
```tsx showLineNumbers
<AlertDialog>
<AlertDialogTrigger render={<Button variant="outline" />}>
Show Dialog
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone. This will permanently delete your account
from our servers.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction>Continue</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
```
## Composition
Use the following composition to build an `AlertDialog`:
```text
AlertDialog
├── AlertDialogTrigger
└── AlertDialogContent
├── AlertDialogHeader
│ ├── AlertDialogMedia
│ ├── AlertDialogTitle
│ └── AlertDialogDescription
└── AlertDialogFooter
├── AlertDialogCancel
└── AlertDialogAction
```
## Basic
A basic alert dialog with a title, description, and cancel and continue buttons.
<ComponentPreview
styleName="base-nova"
name="alert-dialog-basic"
previewClassName="h-56"
/>
## Small
Use the `size="sm"` prop to make the alert dialog smaller.
<ComponentPreview
styleName="base-nova"
name="alert-dialog-small"
previewClassName="h-56"
/>
## Media
Use the `AlertDialogMedia` component to add a media element such as an icon or image to the alert dialog.
<ComponentPreview
styleName="base-nova"
name="alert-dialog-media"
previewClassName="h-56"
/>
## Small with Media
Use the `size="sm"` prop to make the alert dialog smaller and the `AlertDialogMedia` component to add a media element such as an icon or image to the alert dialog.
<ComponentPreview
styleName="base-nova"
name="alert-dialog-small-media"
previewClassName="h-56"
/>
## Destructive
Use the `AlertDialogAction` component to add a destructive action button to the alert dialog.
<ComponentPreview
styleName="base-nova"
name="alert-dialog-destructive"
previewClassName="h-56"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="alert-dialog-rtl"
direction="rtl"
previewClassName="h-56"
/>
## API Reference
### size
Use the `size` prop on the `AlertDialogContent` component to control the size of the alert dialog. It accepts the following values:
| Prop | Type | Default |
| ------ | ------------------- | ----------- |
| `size` | `"default" \| "sm"` | `"default"` |
For more information about the other components and their props, see the [Base UI documentation](https://base-ui.com/react/components/alert-dialog#api-reference).

View File

@@ -0,0 +1,169 @@
---
title: Alert
description: Displays a callout for user attention.
base: base
component: true
---
<ComponentPreview
styleName="base-nova"
name="alert-demo"
previewClassName="h-auto sm:h-72 p-6"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add alert
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
styleName="base-nova"
name="alert"
title="components/ui/alert.tsx"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert"
```
```tsx showLineNumbers
<Alert>
<InfoIcon />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components and dependencies to your app using the cli.
</AlertDescription>
<AlertAction>
<Button variant="outline">Enable</Button>
</AlertAction>
</Alert>
```
## Composition
Use the following composition to build an `Alert`:
```text
Alert
├── Icon
├── AlertTitle
├── AlertDescription
└── AlertAction
```
## Basic
A basic alert with an icon, title and description.
<ComponentPreview
styleName="base-nova"
name="alert-basic"
previewClassName="h-auto sm:h-72 p-6"
/>
## Destructive
Use `variant="destructive"` to create a destructive alert.
<ComponentPreview
styleName="base-nova"
name="alert-destructive"
previewClassName="h-auto sm:h-72 p-6"
/>
## Action
Use `AlertAction` to add a button or other action element to the alert.
<ComponentPreview
styleName="base-nova"
name="alert-action"
previewClassName="h-auto sm:h-72 p-6"
/>
## Custom Colors
You can customize the alert colors by adding custom classes such as `bg-amber-50 dark:bg-amber-950` to the `Alert` component.
<ComponentPreview
styleName="base-nova"
name="alert-colors"
previewClassName="h-auto sm:h-72 p-6"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="alert-rtl"
direction="rtl"
previewClassName="h-auto sm:h-72 p-6"
/>
## API Reference
### Alert
The `Alert` component displays a callout for user attention.
| Prop | Type | Default |
| --------- | ---------------------------- | ----------- |
| `variant` | `"default" \| "destructive"` | `"default"` |
### AlertTitle
The `AlertTitle` component displays the title of the alert.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### AlertDescription
The `AlertDescription` component displays the description or content of the alert.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### AlertAction
The `AlertAction` component displays an action element (like a button) positioned absolutely in the top-right corner of the alert.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |

View File

@@ -0,0 +1,102 @@
---
title: Aspect Ratio
description: Displays content within a desired ratio.
base: base
component: true
---
<ComponentPreview name="aspect-ratio-demo" styleName="base-nova" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add aspect-ratio
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="aspect-ratio"
title="components/ui/aspect-ratio.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { AspectRatio } from "@/components/ui/aspect-ratio"
```
```tsx showLineNumbers
<AspectRatio ratio={16 / 9}>
<Image src="..." alt="Image" className="rounded-md object-cover" />
</AspectRatio>
```
## Square
A square aspect ratio component using the `ratio={1 / 1}` prop. This is useful for displaying images in a square format.
<ComponentPreview name="aspect-ratio-square" styleName="base-nova" />
## Portrait
A portrait aspect ratio component using the `ratio={9 / 16}` prop. This is useful for displaying images in a portrait format.
<ComponentPreview
styleName="base-nova"
name="aspect-ratio-portrait"
previewClassName="h-96"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="aspect-ratio-rtl"
direction="rtl"
previewClassName="h-96"
/>
## API Reference
### AspectRatio
The `AspectRatio` component displays content within a desired ratio.
| Prop | Type | Default | Required |
| ----------- | -------- | ------- | -------- |
| `ratio` | `number` | - | Yes |
| `className` | `string` | - | No |
For more information, see the [Base UI documentation](https://base-ui.com/react/components/aspect-ratio#api-reference).

View File

@@ -0,0 +1,302 @@
---
title: Attachment
description: Displays a file or image attachment with media, metadata, upload state, and actions.
base: base
component: true
---
<ComponentPreview
styleName="base-rhea"
name="attachment-demo"
previewClassName="h-auto theme-blue bg-surface dark:bg-background"
/>
The `Attachment` component displays a file or image attachment, its media, name, and metadata, with optional actions and upload state. Use it for files and images in chat composers, message threads, and upload lists.
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add attachment
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the required shadcn/ui dependencies:</Step>
```bash
npx shadcn@latest add button
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="attachment"
title="components/ui/attachment.tsx"
styleName="base-rhea"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import {
Attachment,
AttachmentAction,
AttachmentActions,
AttachmentContent,
AttachmentDescription,
AttachmentMedia,
AttachmentTitle,
} from "@/components/ui/attachment"
```
```tsx
<Attachment>
<AttachmentMedia>
<FileTextIcon />
</AttachmentMedia>
<AttachmentContent>
<AttachmentTitle>sales-dashboard.pdf</AttachmentTitle>
<AttachmentDescription>PDF · 2.4 MB</AttachmentDescription>
</AttachmentContent>
<AttachmentActions>
<AttachmentAction aria-label="Remove sales-dashboard.pdf">
<XIcon />
</AttachmentAction>
</AttachmentActions>
</Attachment>
```
## Composition
Use the following composition to build an attachment:
```text
Attachment
├── AttachmentMedia
├── AttachmentContent
│ ├── AttachmentTitle
│ └── AttachmentDescription
├── AttachmentActions
│ └── AttachmentAction
└── AttachmentTrigger
```
Use `AttachmentGroup` to lay out multiple attachments in a scrollable row:
```text
AttachmentGroup
├── Attachment
└── Attachment
```
## Features
- Icon and image media through `AttachmentMedia`
- Upload states: `idle`, `uploading`, `processing`, `error`, and `done` with built-in styling and a shimmer while in progress
- Three sizes and horizontal or vertical orientation
- A full-card `AttachmentTrigger` that opens a link or dialog while the actions stay independently clickable
- Scrollable, snapping `AttachmentGroup` with an edge fade
- Customizable styling through the `className` prop on every part
## Image
Set `variant="image"` on `AttachmentMedia` and render an `<img>` inside it. Use `orientation="vertical"` to stack the media above the content.
<ComponentPreview
styleName="base-rhea"
name="attachment-image"
previewClassName="h-auto theme-blue bg-surface dark:bg-background"
/>
## States
Set `state` to reflect the upload lifecycle. `uploading` and `processing` shimmer the title, and `error` switches to a destructive treatment.
<ComponentPreview
styleName="base-rhea"
name="attachment-states"
previewClassName="h-auto theme-blue bg-surface dark:bg-background"
/>
## Sizes
Use `size` to switch between `default`, `sm`, and `xs`.
<ComponentPreview
styleName="base-rhea"
name="attachment-sizes"
previewClassName="h-auto theme-blue bg-surface dark:bg-background"
/>
## Group
Wrap attachments in `AttachmentGroup` to lay them out in a horizontally scrollable, snapping row with an edge fade.
<ComponentPreview
styleName="base-rhea"
name="attachment-group"
previewClassName="h-auto theme-blue bg-surface dark:bg-background"
/>
## Trigger
Add an `AttachmentTrigger` to make the whole card open a link or dialog. It fills the card behind the actions, so the actions stay clickable.
<ComponentPreview
styleName="base-rhea"
name="attachment-trigger"
previewClassName="h-auto theme-blue bg-surface dark:bg-background"
/>
```tsx showLineNumbers
<Dialog>
<Attachment>
{/* media, content, actions */}
<DialogTrigger
render={<AttachmentTrigger aria-label="Preview research-summary.pdf" />}
/>
</Attachment>
<DialogContent>{/* ... */}</DialogContent>
</Dialog>
```
## Accessibility
`AttachmentAction` renders a `Button`, and `AttachmentTrigger` renders a real `<button>` (or your element via `render`). Follow the guidance below so both are operable and announced.
### Label icon-only actions
`AttachmentAction` is usually icon-only, so give each one an `aria-label` describing the action and its target.
```tsx showLineNumbers
<AttachmentAction aria-label="Remove sales-dashboard.pdf">
<XIcon />
</AttachmentAction>
```
### Label the trigger
`AttachmentTrigger` covers the card with no text of its own, so give it an `aria-label` for what activating it does.
```tsx showLineNumbers
<AttachmentTrigger
render={
<a
href={url}
target="_blank"
rel="noreferrer"
aria-label="Open workspace.png"
/>
}
/>
```
The trigger sits behind the actions in the stacking order, so an `AttachmentAction` and the `AttachmentTrigger` never trap each other — both remain separately focusable and clickable.
### Keyboard scrolling
An `AttachmentGroup` scrolls horizontally. When its attachments are interactive: a trigger or actions, keyboard users reach off-screen items by tabbing to them. For a row of presentational attachments, make the group itself focusable and scrollable by adding `tabIndex={0}`, `role="group"`, and an `aria-label`.
### Meaning beyond color
The `error` state uses a destructive color. Keep the failure reason in `AttachmentDescription` so the state is not conveyed by color alone.
## API Reference
### Attachment
The root attachment container.
| Prop | Type | Default | Description |
| ------------- | ------------------------------------------------------------ | -------------- | ------------------------------------------------- |
| `state` | `"idle" \| "uploading" \| "processing" \| "error" \| "done"` | `"done"` | The upload state. Drives styling and the shimmer. |
| `size` | `"default" \| "sm" \| "xs"` | `"default"` | The attachment size. |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Lay the media beside or above the content. |
| `className` | `string` | - | Additional classes to apply to the root element. |
### AttachmentMedia
The media slot for an icon or image preview.
| Prop | Type | Default | Description |
| ----------- | ------------------- | -------- | ---------------------------------------------- |
| `variant` | `"icon" \| "image"` | `"icon"` | Whether the media holds an icon or an `<img>`. |
| `className` | `string` | - | Additional classes to apply to the media slot. |
### AttachmentContent
Wraps the title and description.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ------------------------------------------------ |
| `className` | `string` | - | Additional classes to apply to the content slot. |
### AttachmentTitle
The attachment name. Shimmers while the attachment is `uploading` or `processing`.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ----------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the title. |
### AttachmentDescription
Secondary metadata such as the file type, size, or upload status.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ----------------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the description. |
### AttachmentActions
A container for one or more actions, aligned to the end of the attachment.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ------------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the actions. |
### AttachmentAction
An action button. Renders a [`Button`](/docs/components/button) and accepts all of its props.
| Prop | Type | Default | Description |
| ---------- | ------------------------------------- | ----------- | ---------------------------------------- |
| `size` | `Button["size"]` | `"icon-xs"` | The button size. |
| `...props` | `React.ComponentProps<typeof Button>` | - | Props spread to the underlying `Button`. |
### AttachmentTrigger
A full-card overlay that activates the attachment. Renders a `<button>` by default.
| Prop | Type | Default | Description |
| ---------- | -------------------------------- | ------- | ---------------------------------------------- |
| `render` | `ReactElement \| function` | - | Render as a different element, such as a link. |
| `...props` | `React.ComponentProps<"button">` | - | Props spread to the trigger element. |
### AttachmentGroup
Lays out attachments in a horizontally scrollable, snapping row.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ----------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the group. |

View File

@@ -0,0 +1,220 @@
---
title: Avatar
description: An image element with a fallback for representing the user.
base: base
component: true
links:
doc: https://base-ui.com/react/components/avatar
api: https://base-ui.com/react/components/avatar#api-reference
---
<ComponentPreview
styleName="base-nova"
name="avatar-demo"
previewClassName="h-72"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add avatar
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="avatar"
title="components/ui/avatar.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
```
```tsx showLineNumbers
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
```
## Composition
Use the following composition to build an `Avatar`:
```text
Avatar
├── AvatarImage
├── AvatarFallback
└── AvatarBadge
```
Use the following composition to build an `AvatarGroup`:
```text
AvatarGroup
├── Avatar
│ ├── AvatarImage
│ ├── AvatarFallback
│ └── AvatarBadge
├── Avatar
│ ├── AvatarImage
│ ├── AvatarFallback
│ └── AvatarBadge
└── AvatarGroupCount
```
## Basic
A basic avatar component with an image and a fallback.
<ComponentPreview styleName="base-nova" name="avatar-basic" />
## Badge
Use the `AvatarBadge` component to add a badge to the avatar. The badge is positioned at the bottom right of the avatar.
<ComponentPreview styleName="base-nova" name="avatar-badge" />
Use the `className` prop to add custom styles to the badge such as custom colors, sizes, etc.
```tsx showLineNumbers
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
<AvatarFallback>CN</AvatarFallback>
<AvatarBadge className="bg-green-600 dark:bg-green-800" />
</Avatar>
```
## Badge with Icon
You can also use an icon inside `<AvatarBadge>`.
<ComponentPreview styleName="base-nova" name="avatar-badge-icon" />
## Avatar Group
Use the `AvatarGroup` component to add a group of avatars.
<ComponentPreview styleName="base-nova" name="avatar-group" />
## Avatar Group Count
Use `<AvatarGroupCount>` to add a count to the group.
<ComponentPreview styleName="base-nova" name="avatar-group-count" />
## Avatar Group with Icon
You can also use an icon inside `<AvatarGroupCount>`.
<ComponentPreview styleName="base-nova" name="avatar-group-count-icon" />
## Sizes
Use the `size` prop to change the size of the avatar.
<ComponentPreview styleName="base-nova" name="avatar-size" />
## Dropdown
You can use the `Avatar` component as a trigger for a dropdown menu.
<ComponentPreview styleName="base-nova" name="avatar-dropdown" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="avatar-rtl"
direction="rtl"
previewClassName="h-72"
/>
## API Reference
### Avatar
The `Avatar` component is the root component that wraps the avatar image and fallback.
| Prop | Type | Default |
| ----------- | --------------------------- | ----------- |
| `size` | `"default" \| "sm" \| "lg"` | `"default"` |
| `className` | `string` | - |
### AvatarImage
The `AvatarImage` component displays the avatar image. It accepts all Base UI Avatar Image props.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `src` | `string` | - |
| `alt` | `string` | - |
| `className` | `string` | - |
### AvatarFallback
The `AvatarFallback` component displays a fallback when the image fails to load. It accepts all Base UI Avatar Fallback props.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### AvatarBadge
The `AvatarBadge` component displays a badge indicator on the avatar, typically positioned at the bottom right.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### AvatarGroup
The `AvatarGroup` component displays a group of avatars with overlapping styling.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### AvatarGroupCount
The `AvatarGroupCount` component displays a count indicator in an avatar group, typically showing the number of additional avatars.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
For more information about Base UI Avatar props, see the [Base UI documentation](https://base-ui.com/react/components/avatar#api-reference).

View File

@@ -0,0 +1,101 @@
---
title: Badge
description: Displays a badge or a component that looks like a badge.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="badge-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add badge
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="badge"
title="components/ui/badge.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Badge } from "@/components/ui/badge"
```
```tsx
<Badge variant="default | outline | secondary | destructive">Badge</Badge>
```
## Variants
Use the `variant` prop to change the variant of the badge.
<ComponentPreview styleName="base-nova" name="badge-variants" />
## With Icon
You can render an icon inside the badge. Use `data-icon="inline-start"` to render the icon on the left and `data-icon="inline-end"` to render the icon on the right.
<ComponentPreview styleName="base-nova" name="badge-icon" />
## With Spinner
You can render a spinner inside the badge. Remember to add the `data-icon="inline-start"` or `data-icon="inline-end"` prop to the spinner.
<ComponentPreview styleName="base-nova" name="badge-spinner" />
## Link
Use the `render` prop to render a link as a badge.
<ComponentPreview styleName="base-nova" name="badge-link" />
## Custom Colors
You can customize the colors of a badge by adding custom classes such as `bg-green-50 dark:bg-green-800` to the `Badge` component.
<ComponentPreview styleName="base-nova" name="badge-colors" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="badge-rtl" direction="rtl" />
## API Reference
### Badge
The `Badge` component displays a badge or a component that looks like a badge.
| Prop | Type | Default |
| ----------- | ----------------------------------------------------------------------------- | ----------- |
| `variant` | `"default" \| "secondary" \| "destructive" \| "outline" \| "ghost" \| "link"` | `"default"` |
| `className` | `string` | - |

View File

@@ -0,0 +1,202 @@
---
title: Breadcrumb
description: Displays the path to the current resource using a hierarchy of links.
base: base
component: true
---
<ComponentPreview
styleName="base-nova"
name="breadcrumb-demo"
previewClassName="p-2"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add breadcrumb
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="breadcrumb"
title="components/ui/breadcrumb.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb"
```
```tsx showLineNumbers
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink render={<a href="/" />}>Home</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink render={<a href="/components" />}>
Components
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Breadcrumb</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
```
## Composition
Use the following composition to build a `Breadcrumb`:
```text
Breadcrumb
└── BreadcrumbList
├── BreadcrumbItem
│ └── BreadcrumbLink
├── BreadcrumbSeparator
├── BreadcrumbItem
│ └── BreadcrumbLink
├── BreadcrumbSeparator
└── BreadcrumbItem
└── BreadcrumbPage
```
## Basic
A basic breadcrumb with a home link and a components link.
<ComponentPreview styleName="base-nova" name="breadcrumb-basic" />
## Custom separator
Use a custom component as `children` for `<BreadcrumbSeparator />` to create a custom separator.
<ComponentPreview styleName="base-nova" name="breadcrumb-separator" />
## Dropdown
You can compose `<BreadcrumbItem />` with a `<DropdownMenu />` to create a dropdown in the breadcrumb.
<ComponentPreview styleName="base-nova" name="breadcrumb-dropdown" />
## Collapsed
We provide a `<BreadcrumbEllipsis />` component to show a collapsed state when the breadcrumb is too long.
<ComponentPreview
styleName="base-nova"
name="breadcrumb-ellipsis"
previewClassName="p-2"
/>
## Link component
To use a custom link component from your routing library, you can use the `render` prop on `<BreadcrumbLink />`.
<ComponentPreview styleName="base-nova" name="breadcrumb-link" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="breadcrumb-rtl"
direction="rtl"
previewClassName="p-2"
/>
## API Reference
### Breadcrumb
The `Breadcrumb` component is the root navigation element that wraps all breadcrumb components.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### BreadcrumbList
The `BreadcrumbList` component displays the ordered list of breadcrumb items.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### BreadcrumbItem
The `BreadcrumbItem` component wraps individual breadcrumb items.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### BreadcrumbLink
The `BreadcrumbLink` component displays a clickable link in the breadcrumb.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### BreadcrumbPage
The `BreadcrumbPage` component displays the current page in the breadcrumb (non-clickable).
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### BreadcrumbSeparator
The `BreadcrumbSeparator` component displays a separator between breadcrumb items. You can pass custom children to override the default separator icon.
| Prop | Type | Default |
| ----------- | ----------------- | ------- |
| `children` | `React.ReactNode` | - |
| `className` | `string` | - |
### BreadcrumbEllipsis
The `BreadcrumbEllipsis` component displays an ellipsis indicator for collapsed breadcrumb items.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |

View File

@@ -0,0 +1,298 @@
---
title: Bubble
description: Displays conversational content in a message bubble. Supports variants, alignment, grouping, reactions, and collapsible content.
base: base
component: true
---
<ComponentPreview
styleName="base-rhea"
name="bubble-demo"
previewClassName="h-auto theme-blue"
/>
The `Bubble` component displays framed conversational content. Use it for chat text, short structured output, quoted replies, suggestions, and reactions.
For full-featured chat interfaces, use the [`Message`](/docs/components/message) component. `Bubble` is intentionally scoped to the bubble surface. Place avatars, names, timestamps, metadata, and message-level actions in [`Message`](/docs/components/message).
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add bubble
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="bubble"
title="components/ui/bubble.tsx"
styleName="base-rhea"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Bubble, BubbleContent, BubbleReactions } from "@/components/ui/bubble"
```
```tsx showLineNumbers
<Bubble>
<BubbleContent>
I checked the registry output and removed the stale route.
</BubbleContent>
<BubbleReactions>
<span>👍</span>
</BubbleReactions>
</Bubble>
```
## Composition
Use the following composition to build a bubble:
```text
Bubble
├── BubbleContent
└── BubbleReactions
```
Use `BubbleGroup` to group consecutive bubbles from the same sender:
```text
BubbleGroup
├── Bubble
│ └── BubbleContent
└── Bubble
└── BubbleContent
```
## Features
- Seven visual variants, from a strong primary bubble to unframed ghost content
- Start and end alignment for sender and receiver bubbles
- Reactions that anchor to the bubble edge with configurable side and alignment
- Bubbles size to their content, up to 80% of the container width
- Polymorphic content via `render` for link and button bubbles
- Customizable styling through the `className` prop on every part
## Variants
Use `variant` to change the visual treatment of the bubble.
<ComponentPreview
styleName="base-rhea"
name="bubble-variants"
previewClassName="h-auto theme-blue"
/>
| Variant | Description |
| ------------- | ------------------------------------------------------ |
| `default` | A strong primary bubble, usually for the current user. |
| `secondary` | The standard neutral bubble for conversation content. |
| `muted` | A lower-emphasis bubble for quiet supporting content. |
| `tinted` | A subtle primary-tinted bubble. |
| `outline` | A bordered bubble for secondary or rich content. |
| `ghost` | Unframed content for assistant text or rich content. |
| `destructive` | A destructive bubble for error or failed actions. |
A bubble sizes to its content, up to 80% of the container width. The `ghost` variant removes the max-width so assistant text and rich content can span the full row.
## Alignment
Use `align` on `Bubble` to align the bubble to the start or end of the conversation.
<ComponentPreview
styleName="base-rhea"
name="bubble-alignment"
previewClassName="h-auto theme-blue"
/>
| align | Description |
| ------- | -------------------------------------------------- |
| `start` | Align the bubble to the start of the conversation. |
| `end` | Align the bubble to the end of the conversation. |
**Note:** When building chat interfaces, you probably want to use alignment on the `Message` component itself, not the `Bubble` component. You can use the `role` prop on the `Message` component to automatically align the bubble to the start or end of the conversation.
## Bubble Group
Use `BubbleGroup` to group consecutive bubbles from the same sender. Note the `align` prop should be set on the `Bubble` component itself, not the `BubbleGroup` component.
```text
BubbleGroup
├── Bubble
│ └── BubbleContent
└── Bubble
└── BubbleContent
```
<ComponentPreview
styleName="base-rhea"
name="bubble-group-demo"
previewClassName="h-auto theme-blue"
/>
## Links and Buttons
You can turn a bubble into a link or button by using the `render` prop on `BubbleContent`.
<ComponentPreview
styleName="base-rhea"
name="bubble-link-button"
previewClassName="h-auto theme-blue"
/>
```tsx showLineNumbers
import { Bubble, BubbleContent } from "@/components/ui/bubble"
export function BubbleLinkDemo() {
return (
<Bubble variant="muted">
<BubbleContent render={<button />}>Click here</BubbleContent>
</Bubble>
)
}
```
## Reactions
Use `BubbleReactions` for bubble reactions. You can use it to display reactions or quick action buttons. Use `side` and `align` to position the row — `side="top"` anchors it to the upper edge. Reactions overlap the bubble edge, so leave vertical space between rows — the examples below use a larger `gap` for this reason.
<ComponentPreview
styleName="base-rhea"
name="bubble-reactions"
previewClassName="h-auto theme-blue"
/>
## Show More / Collapsible
Long bubble content can be composed with [`Collapsible`](/docs/components/collapsible) to allow for a show more or show less interaction. Use the `CollapsibleTrigger` component to trigger the collapsible content.
<ComponentPreview
styleName="base-rhea"
name="bubble-collapsible"
previewClassName="h-auto theme-blue"
/>
## Tooltip
Wrap a bubble in a [`Tooltip`](/docs/components/tooltip) to reveal metadata on hover, such as when a message was read.
<ComponentPreview
styleName="base-rhea"
name="bubble-tooltip"
previewClassName="h-auto theme-blue"
/>
## Popover
Pair a bubble with a [`Popover`](/docs/components/popover) to surface more information on demand, such as the full error message for a failed action.
<ComponentPreview
styleName="base-rhea"
name="bubble-popover"
previewClassName="h-auto theme-blue"
/>
## Accessibility
`Bubble` renders the presentational message surface. Keep conversation-level semantics on the surrounding container and follow the guidelines below.
### Labeling Reactions
Reactions render as a row of emoji. A screen reader reads each glyph with no context, and counters like `+8` are announced as "plus eight". Group the row as a single image with a descriptive `aria-label` so it announces once. `role="img"` also hides the individual emoji from assistive tech, so no `aria-hidden` is needed.
```tsx showLineNumbers
<BubbleReactions role="img" aria-label="Reactions: thumbs up, fire, and 8 more">
<span>👍</span>
<span>🔥</span>
<span>+8</span>
</BubbleReactions>
```
When reactions are interactive, render buttons instead and give icon-only buttons an `aria-label`.
```tsx showLineNumbers
<BubbleReactions>
<Button aria-label="Thumbs up" variant="secondary" size="icon-xs">
<ThumbsUpIcon />
</Button>
</BubbleReactions>
```
### Interactive Bubbles
When a bubble is clickable, render it as a real `<button>` or `<a>` with the `render` prop so it is focusable and exposes the correct role. `BubbleContent` ships a visible focus ring for interactive elements, and the accessible name comes from the bubble text. No extra label is needed.
```tsx showLineNumbers
<Bubble variant="muted" align="end">
<BubbleContent render={<button type="button" onClick={onReply} />}>
I forgot my password
</BubbleContent>
</Bubble>
```
### Meaning Beyond Color
Bubble variants signal role and tone with color. Pair them with text, alignment, or icons so meaning is not conveyed by color alone. For a `destructive` bubble, keep the error context in the message text rather than relying on the color treatment.
## API Reference
### Bubble
The root bubble wrapper.
| Prop | Type | Default | Description |
| ----------- | ------------------------------------------------------------------------------------------ | ----------- | ------------------------------------------------ |
| `variant` | `"default" \| "secondary" \| "muted" \| "tinted" \| "outline" \| "ghost" \| "destructive"` | `"default"` | The bubble visual treatment. |
| `align` | `"start" \| "end"` | `"start"` | The inline alignment of the bubble. |
| `className` | `string` | - | Additional classes to apply to the root element. |
### BubbleContent
The bubble content wrapper.
| Prop | Type | Default | Description |
| ----------- | -------------------------- | ------- | --------------------------------------------------------- |
| `render` | `ReactElement \| function` | - | Render the content as a different element such as a link. |
| `className` | `string` | - | Additional classes to apply to the content element. |
### BubbleReactions
Displays overlapped reactions for a bubble.
| Prop | Type | Default | Description |
| ----------- | ------------------- | ---------- | ------------------------------------------------ |
| `side` | `"top" \| "bottom"` | `"bottom"` | The side of the bubble to anchor the reactions. |
| `align` | `"start" \| "end"` | `"end"` | The inline alignment of the reactions. |
| `className` | `string` | - | Additional classes to apply to the reaction row. |
### BubbleGroup
Groups consecutive bubbles from the same sender.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ---------------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the group root. |

View File

@@ -0,0 +1,241 @@
---
title: Button Group
description: A container that groups related buttons together with consistent styling.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="button-group-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add button-group
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="button-group"
title="components/ui/button-group.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import {
ButtonGroup,
ButtonGroupSeparator,
ButtonGroupText,
} from "@/components/ui/button-group"
```
```tsx
<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
```
## Composition
Use the following composition to build a `ButtonGroup`:
```text
ButtonGroup
├── Button or Input
├── ButtonGroupSeparator
└── ButtonGroupText
```
## Accessibility
- The `ButtonGroup` component has the `role` attribute set to `group`.
- Use <Kbd>Tab</Kbd> to navigate between the buttons in the group.
- Use `aria-label` or `aria-labelledby` to label the button group.
```tsx showLineNumbers
<ButtonGroup aria-label="Button group">
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
```
## ButtonGroup vs ToggleGroup
- Use the `ButtonGroup` component when you want to group buttons that perform an action.
- Use the `ToggleGroup` component when you want to group buttons that toggle a state.
## Orientation
Set the `orientation` prop to change the button group layout.
<ComponentPreview styleName="base-nova" name="button-group-orientation" />
## Size
Control the size of buttons using the `size` prop on individual buttons.
<ComponentPreview styleName="base-nova" name="button-group-size" />
## Nested
Nest `<ButtonGroup>` components to create button groups with spacing.
<ComponentPreview styleName="base-nova" name="button-group-nested" />
## Separator
The `ButtonGroupSeparator` component visually divides buttons within a group.
Buttons with variant `outline` do not need a separator since they have a border. For other variants, a separator is recommended to improve the visual hierarchy.
<ComponentPreview styleName="base-nova" name="button-group-separator" />
## Split
Create a split button group by adding two buttons separated by a `ButtonGroupSeparator`.
<ComponentPreview styleName="base-nova" name="button-group-split" />
## Input
Wrap an `Input` component with buttons.
<ComponentPreview styleName="base-nova" name="button-group-input" />
## Input Group
Wrap an `InputGroup` component to create complex input layouts.
<ComponentPreview styleName="base-nova" name="button-group-input-group" />
## Dropdown Menu
Create a split button group with a `DropdownMenu` component.
<ComponentPreview styleName="base-nova" name="button-group-dropdown" />
## Select
Pair with a `Select` component.
<ComponentPreview styleName="base-nova" name="button-group-select" />
## Popover
Use with a `Popover` component.
<ComponentPreview styleName="base-nova" name="button-group-popover" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="button-group-rtl"
direction="rtl"
/>
## API Reference
### ButtonGroup
The `ButtonGroup` component is a container that groups related buttons together with consistent styling.
| Prop | Type | Default |
| ------------- | ---------------------------- | -------------- |
| `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` |
```tsx
<ButtonGroup>
<Button>Button 1</Button>
<Button>Button 2</Button>
</ButtonGroup>
```
Nest multiple button groups to create complex layouts with spacing. See the [nested](#nested) example for more details.
```tsx
<ButtonGroup>
<ButtonGroup />
<ButtonGroup />
</ButtonGroup>
```
### ButtonGroupSeparator
The `ButtonGroupSeparator` component visually divides buttons within a group.
| Prop | Type | Default |
| ------------- | ---------------------------- | ------------ |
| `orientation` | `"horizontal" \| "vertical"` | `"vertical"` |
```tsx
<ButtonGroup>
<Button>Button 1</Button>
<ButtonGroupSeparator />
<Button>Button 2</Button>
</ButtonGroup>
```
### ButtonGroupText
Use this component to display text within a button group.
| Prop | Type | Default |
| -------- | -------------------- | ------- |
| `render` | `React.ReactElement` | |
```tsx
<ButtonGroup>
<ButtonGroupText>Text</ButtonGroupText>
<Button>Button</Button>
</ButtonGroup>
```
Use the `render` prop to render a custom component as the text, for example a label.
```tsx showLineNumbers
import { ButtonGroupText } from "@/components/ui/button-group"
import { Label } from "@/components/ui/label"
export function ButtonGroupTextDemo() {
return (
<ButtonGroup>
<ButtonGroupText render={<Label htmlFor="name" />}>Text</ButtonGroupText>
<Input placeholder="Type something here..." id="name" />
</ButtonGroup>
)
}
```

View File

@@ -0,0 +1,161 @@
---
title: Button
description: Displays a button or a component that looks like a button.
featured: true
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="button-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add button
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="button"
title="components/ui/button.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Button } from "@/components/ui/button"
```
```tsx
<Button variant="outline">Button</Button>
```
## Cursor
Tailwind v4 [switched](https://tailwindcss.com/docs/upgrade-guide#buttons-use-the-default-cursor) from `cursor: pointer` to `cursor: default` for the button component.
If you want to keep the `cursor: pointer` behavior, add the following code to your CSS file:
You can also enable this during project setup with `npx shadcn@latest init --pointer`.
```css showLineNumbers title="globals.css"
@layer base {
button:not(:disabled),
[role="button"]:not(:disabled) {
cursor: pointer;
}
}
```
## Size
Use the `size` prop to change the size of the button.
<ComponentPreview styleName="base-nova" name="button-size" />
## Default
<ComponentPreview styleName="base-nova" name="button-default" />
## Outline
<ComponentPreview styleName="base-nova" name="button-outline" />
## Secondary
<ComponentPreview styleName="base-nova" name="button-secondary" />
## Ghost
<ComponentPreview styleName="base-nova" name="button-ghost" />
## Destructive
<ComponentPreview styleName="base-nova" name="button-destructive" />
## Link
<ComponentPreview styleName="base-nova" name="button-link" />
## Icon
<ComponentPreview styleName="base-nova" name="button-icon" />
## With Icon
Remember to add the `data-icon="inline-start"` or `data-icon="inline-end"` attribute to the icon for the correct spacing.
<ComponentPreview styleName="base-nova" name="button-with-icon" />
## Rounded
Use the `rounded-full` class to make the button rounded.
<ComponentPreview styleName="base-nova" name="button-rounded" />
## Spinner
Render a `<Spinner />` component inside the button to show a loading state. Remember to add the `data-icon="inline-start"` or `data-icon="inline-end"` attribute to the spinner for the correct spacing.
<ComponentPreview styleName="base-nova" name="button-spinner" />
## Button Group
To create a button group, use the `ButtonGroup` component. See the [Button Group](/docs/components/base/button-group) documentation for more details.
<ComponentPreview styleName="base-nova" name="button-group-demo" />
## As Link
You can use the `buttonVariants` helper to make a link look like a button.
**Do not use `<Button render={<a />} nativeButton={false} />` for links.** The Base UI `Button` component always applies `role="button"`, which overrides the semantic link role on `<a>` elements. Use `buttonVariants` with a plain `<a>` tag instead.
<ComponentPreview styleName="base-nova" name="button-render" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="button-rtl" direction="rtl" />
## API Reference
### Button
The `Button` component is a wrapper around the `button` element that adds a variety of styles and functionality.
| Prop | Type | Default |
| --------- | ------------------------------------------------------------------------------------ | ----------- |
| `variant` | `"default" \| "outline" \| "ghost" \| "destructive" \| "secondary" \| "link"` | `"default"` |
| `size` | `"default" \| "xs" \| "sm" \| "lg" \| "icon" \| "icon-xs" \| "icon-sm" \| "icon-lg"` | `"default"` |

View File

@@ -0,0 +1,402 @@
---
title: Calendar
description: A calendar component that allows users to select a date or a range of dates.
base: base
component: true
links:
doc: https://react-day-picker.js.org
---
<ComponentPreview
styleName="base-nova"
name="calendar-demo"
previewClassName="h-96"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add calendar
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install react-day-picker date-fns
```
<Step>Add the `Button` component to your project.</Step>
The `Calendar` component uses the `Button` component. Make sure you have it installed in your project.
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="calendar"
title="components/ui/calendar.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Calendar } from "@/components/ui/calendar"
```
```tsx showLineNumbers
const [date, setDate] = React.useState<Date | undefined>(new Date())
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-lg border"
/>
)
```
See the [React DayPicker](https://react-day-picker.js.org) documentation for more information.
## About
The `Calendar` component is built on top of [React DayPicker](https://react-day-picker.js.org).
## Date Picker
You can use the `<Calendar>` component to build a date picker. See the [Date Picker](/docs/components/base/date-picker) page for more information.
## Persian / Hijri / Jalali Calendar
To use the Persian calendar, edit `components/ui/calendar.tsx` and replace `react-day-picker` with `react-day-picker/persian`.
```diff
- import { DayPicker } from "react-day-picker"
+ import { DayPicker } from "react-day-picker/persian"
```
<ComponentPreview
styleName="base-nova"
name="calendar-hijri"
title="Persian / Hijri / Jalali Calendar"
description="A Persian calendar."
previewClassName="h-[400px]"
/>
## Selected Date (With TimeZone)
The Calendar component accepts a `timeZone` prop to ensure dates are displayed and selected in the user's local timezone.
```tsx showLineNumbers
export function CalendarWithTimezone() {
const [date, setDate] = React.useState<Date | undefined>(undefined)
const [timeZone, setTimeZone] = React.useState<string | undefined>(undefined)
React.useEffect(() => {
setTimeZone(Intl.DateTimeFormat().resolvedOptions().timeZone)
}, [])
return (
<Calendar
mode="single"
selected={date}
onSelect={setDate}
timeZone={timeZone}
/>
)
}
```
**Note:** If you notice a selected date offset (for example, selecting the 20th highlights the 19th), make sure the `timeZone` prop is set to the user's local timezone.
**Why client-side?** The timezone is detected using `Intl.DateTimeFormat().resolvedOptions().timeZone` inside a `useEffect` to ensure compatibility with server-side rendering. Detecting the timezone during render would cause hydration mismatches, as the server and client may be in different timezones.
## Basic
A basic calendar component. We used `className="rounded-lg border"` to style the calendar.
<ComponentPreview
styleName="base-nova"
name="calendar-basic"
previewClassName="h-96"
/>
## Range Calendar
Use the `mode="range"` prop to enable range selection.
<ComponentPreview
styleName="base-nova"
name="calendar-range"
previewClassName="h-[36rem] md:h-96"
/>
## Month and Year Selector
Use `captionLayout="dropdown"` to show month and year dropdowns.
<ComponentPreview
styleName="base-nova"
name="calendar-caption"
previewClassName="h-96"
/>
## Presets
<ComponentPreview
styleName="base-nova"
name="calendar-presets"
previewClassName="h-[650px]"
/>
## Date and Time Picker
<ComponentPreview
styleName="base-nova"
name="calendar-time"
previewClassName="h-[600px]"
/>
## Booked dates
<ComponentPreview
styleName="base-nova"
name="calendar-booked-dates"
previewClassName="h-96"
/>
## Custom Cell Size
<ComponentPreview
styleName="base-nova"
name="calendar-custom-days"
title="Custom Cell Size"
description="A calendar with custom cell size that's responsive."
className="**:[.preview]:h-[560px]"
/>
You can customize the size of calendar cells using the `--cell-size` CSS variable. You can also make it responsive by using breakpoint-specific values:
```tsx showLineNumbers
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-lg border [--cell-size:--spacing(11)] md:[--cell-size:--spacing(12)]"
/>
```
Or use fixed values:
```tsx showLineNumbers
<Calendar
mode="single"
selected={date}
onSelect={setDate}
className="rounded-lg border [--cell-size:2.75rem] md:[--cell-size:3rem]"
/>
```
## Week Numbers
Use `showWeekNumber` to show week numbers.
<ComponentPreview
styleName="base-nova"
name="calendar-week-numbers"
previewClassName="h-96"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
See also the [Hijri Guide](#persian--hijri--jalali-calendar) for enabling the Persian / Hijri / Jalali calendar.
<ComponentPreview
styleName="base-nova"
name="calendar-rtl"
direction="rtl"
previewClassName="h-96"
/>
When using RTL, import the locale from `react-day-picker/locale` and pass both the `locale` and `dir` props to the Calendar component:
```tsx showLineNumbers
import { arSA } from "react-day-picker/locale"
;<Calendar
mode="single"
selected={date}
onSelect={setDate}
locale={arSA}
dir="rtl"
/>
```
## API Reference
See the [React DayPicker](https://react-day-picker.js.org) documentation for more information on the `Calendar` component.
## Changelog
### RTL Support
If you're upgrading from a previous version of the `Calendar` component, you'll need to apply the following updates to add locale support:
<Steps>
<Step>Import the `Locale` type.</Step>
Add `Locale` to your imports from `react-day-picker`:
```diff
import {
DayPicker,
getDefaultClassNames,
type DayButton,
+ type Locale,
} from "react-day-picker"
```
<Step>Add `locale` prop to the Calendar component.</Step>
Add the `locale` prop to the component's props:
```diff
function Calendar({
className,
classNames,
showOutsideDays = true,
captionLayout = "label",
buttonVariant = "ghost",
+ locale,
formatters,
components,
...props
}: React.ComponentProps<typeof DayPicker> & {
buttonVariant?: React.ComponentProps<typeof Button>["variant"]
}) {
```
<Step>Pass `locale` to DayPicker.</Step>
Pass the `locale` prop to the `DayPicker` component:
```diff
<DayPicker
showOutsideDays={showOutsideDays}
className={cn(...)}
captionLayout={captionLayout}
+ locale={locale}
formatters={{
formatMonthDropdown: (date) =>
- date.toLocaleString("default", { month: "short" }),
+ date.toLocaleString(locale?.code, { month: "short" }),
...formatters,
}}
```
<Step>Update CalendarDayButton to accept locale.</Step>
Update the `CalendarDayButton` component signature and pass `locale`:
```diff
function CalendarDayButton({
className,
day,
modifiers,
+ locale,
...props
- }: React.ComponentProps<typeof DayButton>) {
+ }: React.ComponentProps<typeof DayButton> & { locale?: Partial<Locale> }) {
```
<Step>Update date formatting in CalendarDayButton.</Step>
Use `locale?.code` in the date formatting:
```diff
<Button
variant="ghost"
size="icon"
- data-day={day.date.toLocaleDateString()}
+ data-day={day.date.toLocaleDateString(locale?.code)}
...
/>
```
<Step>Pass locale to DayButton component.</Step>
Update the `DayButton` component usage to pass the `locale` prop:
```diff
components={{
...
- DayButton: CalendarDayButton,
+ DayButton: ({ ...props }) => (
+ <CalendarDayButton locale={locale} {...props} />
+ ),
...
}}
```
<Step>Update RTL-aware CSS classes.</Step>
Replace directional classes with logical properties for better RTL support:
```diff
// In the day classNames:
- [&:last-child[data-selected=true]_button]:rounded-r-(--cell-radius)
+ [&:last-child[data-selected=true]_button]:rounded-e-(--cell-radius)
- [&:nth-child(2)[data-selected=true]_button]:rounded-l-(--cell-radius)
+ [&:nth-child(2)[data-selected=true]_button]:rounded-s-(--cell-radius)
- [&:first-child[data-selected=true]_button]:rounded-l-(--cell-radius)
+ [&:first-child[data-selected=true]_button]:rounded-s-(--cell-radius)
// In range_start classNames:
- rounded-l-(--cell-radius) ... after:right-0
+ rounded-s-(--cell-radius) ... after:end-0
// In range_end classNames:
- rounded-r-(--cell-radius) ... after:left-0
+ rounded-e-(--cell-radius) ... after:start-0
// In CalendarDayButton className:
- data-[range-end=true]:rounded-r-(--cell-radius)
+ data-[range-end=true]:rounded-e-(--cell-radius)
- data-[range-start=true]:rounded-l-(--cell-radius)
+ data-[range-start=true]:rounded-s-(--cell-radius)
```
</Steps>
After applying these changes, you can use the `locale` prop to provide locale-specific formatting:
```tsx
import { enUS } from "react-day-picker/locale"
;<Calendar mode="single" selected={date} onSelect={setDate} locale={enUS} />
```

View File

@@ -0,0 +1,267 @@
---
title: Card
description: Displays a card with header, content, and footer.
base: base
component: true
---
<ComponentPreview
name="card-demo"
styleName="base-nova"
previewClassName="h-[30rem]"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add card
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="card"
title="components/ui/card.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
```
```tsx showLineNumbers
<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card Description</CardDescription>
<CardAction>Card Action</CardAction>
</CardHeader>
<CardContent>
<p>Card Content</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>
```
## Composition
Use the following composition to build a `Card`:
```text
Card
├── CardHeader
│ ├── CardTitle
│ ├── CardDescription
│ └── CardAction
├── CardContent
└── CardFooter
```
## Size
Use the `size="sm"` prop to set the size of the card to small. The small size variant uses smaller spacing.
<ComponentPreview
styleName="base-nova"
name="card-small"
previewClassName="h-96"
/>
## Spacing
In addition to the `size` prop, you can use the `--card-spacing` CSS variable to control the spacing between sections and the inset of card parts.
<ComponentPreview
styleName="base-nova"
name="card-spacing"
previewClassName="h-[34rem]"
/>
Use negative margins with `-mx-(--card-spacing)` to make content go edge to edge while keeping it aligned with the card inset. When the edge-to-edge content sits above a footer, use `-mb-(--card-spacing)` on `CardContent` to remove the section gap.
<ComponentPreview
styleName="base-nova"
name="card-edge-to-edge"
previewClassName="h-[24rem]"
/>
## Image
Add an image before the card header to create a card with an image.
<ComponentPreview
styleName="base-nova"
name="card-image"
previewClassName="h-[32rem]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="card-rtl"
direction="rtl"
previewClassName="h-[30rem]"
/>
## API Reference
### Card
The `Card` component is the root container for card content.
| Prop | Type | Default |
| ----------- | ------------------- | ----------- |
| `size` | `"default" \| "sm"` | `"default"` |
| `className` | `string` | - |
### CardHeader
The `CardHeader` component is used for a title, description, and optional action.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### CardTitle
The `CardTitle` component is used for the card title.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### CardDescription
The `CardDescription` component is used for helper text under the title.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### CardAction
The `CardAction` component places content in the top-right of the header (for example, a button or a badge).
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### CardContent
The `CardContent` component is used for the main card body.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
### CardFooter
The `CardFooter` component is used for actions and secondary content at the bottom of the card.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | - |
## Changelog
### Spacing Variable
If you're upgrading from a previous version of the `Card` component, you'll need to apply the following updates to use the `--card-spacing` variable:
<Steps>
<Step>Update the Card root spacing classes.</Step>
Replace the hard-coded gap and vertical padding with `--card-spacing`, and set the default and small size values on the root:
```diff
className={cn(
- "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
+ "group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl bg-card py-(--card-spacing) text-sm text-card-foreground ring-1 ring-foreground/10 [--card-spacing:--spacing(4)] has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(3)] data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
className
)}
```
<Step>Update CardHeader spacing classes.</Step>
Replace the horizontal padding and border spacing with the shared variable:
```diff
className={cn(
- "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
+ "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
className
)}
```
<Step>Update CardContent and CardFooter spacing classes.</Step>
Use `--card-spacing` for the content inset and footer padding:
```diff
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
- className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
+ className={cn("px-(--card-spacing)", className)}
{...props}
/>
)
}
```
```diff
className={cn(
- "flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
+ "flex items-center rounded-b-xl border-t bg-muted/50 p-(--card-spacing)",
className
)}
```
</Steps>
After applying these changes, you can customize card spacing by setting `--card-spacing` on the `Card` with an arbitrary property class:
```tsx
function Example() {
return <Card className="[--card-spacing:--spacing(6)]">...</Card>
}
```

View File

@@ -0,0 +1,333 @@
---
title: Carousel
description: A carousel with motion and swipe built using Embla.
base: base
component: true
links:
doc: https://www.embla-carousel.com/get-started/react
api: https://www.embla-carousel.com/api
---
<ComponentPreview
styleName="base-nova"
name="carousel-demo"
previewClassName="h-80 sm:h-[32rem]"
/>
## About
The carousel component is built using the [Embla Carousel](https://www.embla-carousel.com/) library.
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add carousel
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install embla-carousel-react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="carousel"
title="components/ui/carousel.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Carousel,
CarouselContent,
CarouselItem,
CarouselNext,
CarouselPrevious,
} from "@/components/ui/carousel"
```
```tsx showLineNumbers
<Carousel>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
<CarouselPrevious />
<CarouselNext />
</Carousel>
```
## Composition
Use the following composition to build a `Carousel`:
```text
Carousel
├── CarouselContent
│ ├── CarouselItem
│ └── CarouselItem
├── CarouselPrevious
└── CarouselNext
```
## Sizes
To set the size of the items, you can use the `basis` utility class on the `<CarouselItem />`.
<ComponentPreview styleName="base-nova" name="carousel-size" />
```tsx showLineNumbers {4-6}
// 33% of the carousel width.
<Carousel>
<CarouselContent>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
<CarouselItem className="basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx showLineNumbers {4-6}
// 50% on small screens and 33% on larger screens.
<Carousel>
<CarouselContent>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
<CarouselItem className="md:basis-1/2 lg:basis-1/3">...</CarouselItem>
</CarouselContent>
</Carousel>
```
## Spacing
To set the spacing between the items, we use a `pl-[VALUE]` utility on the `<CarouselItem />` and a negative `-ml-[VALUE]` on the `<CarouselContent />`.
<ComponentPreview styleName="base-nova" name="carousel-spacing" />
```tsx showLineNumbers /-ml-4/ /pl-4/
<Carousel>
<CarouselContent className="-ml-4">
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
<CarouselItem className="pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
```tsx showLineNumbers /-ml-2/ /pl-2/ /md:-ml-4/ /md:pl-4/
<Carousel>
<CarouselContent className="-ml-2 md:-ml-4">
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
<CarouselItem className="pl-2 md:pl-4">...</CarouselItem>
</CarouselContent>
</Carousel>
```
## Orientation
Use the `orientation` prop to set the orientation of the carousel.
<ComponentPreview
styleName="base-nova"
name="carousel-orientation"
previewClassName="h-[32rem]"
/>
```tsx showLineNumbers /vertical | horizontal/
<Carousel orientation="vertical | horizontal">
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## Options
You can pass options to the carousel using the `opts` prop. See the [Embla Carousel docs](https://www.embla-carousel.com/api/options/) for more information.
```tsx showLineNumbers {2-5}
<Carousel
opts={{
align: "start",
loop: true,
}}
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
```
## API
Use a state and the `setApi` prop to get an instance of the carousel API.
<ComponentPreview
styleName="base-nova"
name="carousel-api"
previewClassName="sm:h-[32rem]"
/>
```tsx showLineNumbers {1,4,22}
import { type CarouselApi } from "@/components/ui/carousel"
export function Example() {
const [api, setApi] = React.useState<CarouselApi>()
const [current, setCurrent] = React.useState(0)
const [count, setCount] = React.useState(0)
React.useEffect(() => {
if (!api) {
return
}
setCount(api.scrollSnapList().length)
setCurrent(api.selectedScrollSnap() + 1)
api.on("select", () => {
setCurrent(api.selectedScrollSnap() + 1)
})
}, [api])
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
)
}
```
## Events
You can listen to events using the api instance from `setApi`.
```tsx showLineNumbers {1,4-14,16}
import { type CarouselApi } from "@/components/ui/carousel"
export function Example() {
const [api, setApi] = React.useState<CarouselApi>()
React.useEffect(() => {
if (!api) {
return
}
api.on("select", () => {
// Do something on select.
})
}, [api])
return (
<Carousel setApi={setApi}>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
</Carousel>
)
}
```
See the [Embla Carousel docs](https://www.embla-carousel.com/api/events/) for more information on using events.
## Plugins
You can use the `plugins` prop to add plugins to the carousel.
```ts showLineNumbers {1,6-10}
import Autoplay from "embla-carousel-autoplay"
export function Example() {
return (
<Carousel
plugins={[
Autoplay({
delay: 2000,
}),
]}
>
// ...
</Carousel>
)
}
```
<ComponentPreview
styleName="base-nova"
name="carousel-plugin"
previewClassName="sm:h-[32rem]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="carousel-rtl"
direction="rtl"
previewClassName="h-80 sm:h-[32rem]"
/>
When localizing the carousel for RTL languages, you need to set the `direction` option in the `opts` prop to match the text direction. This ensures the carousel scrolls in the correct direction.
```tsx showLineNumbers {2-5}
<Carousel
dir={dir}
opts={{
direction: dir,
}}
>
<CarouselContent>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
<CarouselItem>...</CarouselItem>
</CarouselContent>
<CarouselPrevious className="rtl:rotate-180" />
<CarouselNext className="rtl:rotate-180" />
</Carousel>
```
The `direction` option accepts `"ltr"` or `"rtl"` and should match the `dir` prop value. You may also want to rotate the navigation buttons using the `rtl:rotate-180` class to ensure they point in the correct direction.
## API Reference
See the [Embla Carousel docs](https://www.embla-carousel.com/api/) for more information on props and plugins.

View File

@@ -0,0 +1,602 @@
---
title: Chart
description: Beautiful charts. Built using Recharts. Copy and paste into your apps.
base: base
component: true
---
<Callout className="mt-4">
**Updated:** The `chart` component now uses Recharts v3. If you're upgrading existing chart code, see [Updating to Recharts v3](#updating-to-recharts-v3).
</Callout>
<ComponentPreview
styleName="base-nova"
name="chart-demo"
className="theme-blue [&_.preview]:h-auto [&_.preview]:p-0 [&_.preview]:lg:min-h-[404px] [&_.preview>div]:w-full [&_.preview>div]:border-none [&_.preview>div]:shadow-none"
hideCode
/>
Introducing **Charts**. A collection of chart components that you can copy and paste into your apps.
Charts are designed to look great out of the box. They work well with the other components and are fully customizable to fit your project.
[Browse the Charts Library](/charts).
## Component
We use [Recharts](https://recharts.org/) under the hood.
We designed the `chart` component with composition in mind. **You build your charts using Recharts components and only bring in custom components, such as `ChartTooltip`, when and where you need it**.
```tsx showLineNumbers /ChartContainer/ /ChartTooltipContent/
import { Bar, BarChart } from "recharts"
import { ChartContainer, ChartTooltipContent } from "@/components/ui/chart"
export function MyChart() {
return (
<ChartContainer>
<BarChart data={data}>
<Bar dataKey="value" />
<ChartTooltip content={<ChartTooltipContent />} />
</BarChart>
</ChartContainer>
)
}
```
We do not wrap Recharts. This means you're not locked into an abstraction. When a new Recharts version is released, you can follow the official upgrade path to upgrade your charts.
**The components are yours**.
## Updating to Recharts v3
If you're updating older chart code to Recharts v3:
- Use `var(--chart-1)` instead of `hsl(var(--chart-1))` when you reference chart tokens from your CSS variables.
- Use `ChartTooltip.defaultIndex` for initial tooltip state only. Keep persistent active shapes in your own chart state.
- Remove `layout` from `<Bar>` when the parent `<BarChart>` already defines it.
- Keep a height, `min-h-*`, or `aspect-*` on `ChartContainer` so `ResponsiveContainer` can measure on first render.
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add chart
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install recharts
```
<Step>Copy and paste the following code into `components/ui/chart.tsx`.</Step>
<ComponentSource
name="chart"
title="components/ui/chart.tsx"
styleName="base-nova"
/>
<Step>Add the following colors to your CSS file</Step>
```css title="app/globals.css" showLineNumbers
@layer base {
:root {
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
}
.dark {
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
}
}
```
</Steps>
</TabsContent>
</CodeTabs>
## Your First Chart
Let's build your first chart. We'll build a bar chart, add a grid, axis, tooltip and legend.
<Steps>
<Step>Start by defining your data</Step>
The following data represents the number of desktop and mobile users for each month.
<Callout className="mt-4">
**Note:** Your data can be in any shape. You are not limited to the shape of the data below. Use the `dataKey` prop to map your data to the chart.
</Callout>
```tsx title="components/example-chart.tsx" showLineNumbers
const chartData = [
{ month: "January", desktop: 186, mobile: 80 },
{ month: "February", desktop: 305, mobile: 200 },
{ month: "March", desktop: 237, mobile: 120 },
{ month: "April", desktop: 73, mobile: 190 },
{ month: "May", desktop: 209, mobile: 130 },
{ month: "June", desktop: 214, mobile: 140 },
]
```
<Step>Define your chart config</Step>
The chart config holds configuration for the chart. This is where you place human-readable strings, such as labels, icons and color tokens for theming.
```tsx title="components/example-chart.tsx" showLineNumbers
import { type ChartConfig } from "@/components/ui/chart"
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
mobile: {
label: "Mobile",
color: "#60a5fa",
},
} satisfies ChartConfig
```
<Step>Build your chart</Step>
You can now build your chart using Recharts components.
<Callout className="mt-4 bg-amber-50 border-amber-200 dark:bg-amber-950/50 dark:border-amber-950">
**Important:** Remember to set a `min-h-[VALUE]` on the `ChartContainer` component. This is required for the chart to be responsive.
</Callout>
<ComponentPreview
styleName="base-nova"
name="chart-example"
previewClassName="h-80"
/>
</Steps>
### Add a Grid
Let's add a grid to the chart.
<Steps className="mb-0 pt-2">
<Step>Import the `CartesianGrid` component.</Step>
```tsx /CartesianGrid/
import { Bar, BarChart, CartesianGrid } from "recharts"
```
<Step>Add the `CartesianGrid` component to your chart.</Step>
```tsx showLineNumbers {3}
<ChartContainer config={chartConfig} className="min-h-[200px] w-full">
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
```
<ComponentPreview
styleName="base-nova"
name="chart-example-grid"
previewClassName="h-80"
/>
</Steps>
### Add an Axis
To add an x-axis to the chart, we'll use the `XAxis` component.
<Steps className="mb-0 pt-2">
<Step>Import the `XAxis` component.</Step>
```tsx /XAxis/
import { Bar, BarChart, CartesianGrid, XAxis } from "recharts"
```
<Step>Add the `XAxis` component to your chart.</Step>
```tsx showLineNumbers {4-10}
<ChartContainer config={chartConfig} className="h-[200px] w-full">
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
```
<ComponentPreview
styleName="base-nova"
name="chart-example-axis"
previewClassName="h-80"
/>
</Steps>
### Add Tooltip
So far we've only used components from Recharts. They look great out of the box thanks to some customization in the `chart` component.
To add a tooltip, we'll use the custom `ChartTooltip` and `ChartTooltipContent` components from `chart`.
<Steps className="mb-0 pt-2">
<Step>Import the `ChartTooltip` and `ChartTooltipContent` components.</Step>
```tsx
import { ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
```
<Step>Add the components to your chart.</Step>
```tsx showLineNumbers {11}
<ChartContainer config={chartConfig} className="h-[200px] w-full">
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
```
<ComponentPreview
styleName="base-nova"
name="chart-example-tooltip"
previewClassName="h-80"
/>
Hover to see the tooltips. Easy, right? Two components, and we've got a beautiful tooltip.
</Steps>
### Add Legend
We'll do the same for the legend. We'll use the `ChartLegend` and `ChartLegendContent` components from `chart`.
<Steps className="mb-0 pt-2">
<Step>Import the `ChartLegend` and `ChartLegendContent` components.</Step>
```tsx
import { ChartLegend, ChartLegendContent } from "@/components/ui/chart"
```
<Step>Add the components to your chart.</Step>
```tsx showLineNumbers {12}
<ChartContainer config={chartConfig} className="h-[200px] w-full">
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="month"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value.slice(0, 3)}
/>
<ChartTooltip content={<ChartTooltipContent />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="desktop" fill="var(--color-desktop)" radius={4} />
<Bar dataKey="mobile" fill="var(--color-mobile)" radius={4} />
</BarChart>
</ChartContainer>
```
<ComponentPreview
styleName="base-nova"
name="chart-example-legend"
previewClassName="h-80"
/>
</Steps>
Done. You've built your first chart! What's next?
- [Themes and Colors](/docs/components/chart#theming)
- [Tooltip](/docs/components/chart#tooltip)
- [Legend](/docs/components/chart#legend)
## Chart Config
The chart config is where you define the labels, icons and colors for a chart.
It is intentionally decoupled from chart data.
This allows you to share config and color tokens between charts. It can also work independently for cases where your data or color tokens live remotely or in a different format.
```tsx showLineNumbers /ChartConfig/
import { Monitor } from "lucide-react"
import { type ChartConfig } from "@/components/ui/chart"
const chartConfig = {
desktop: {
label: "Desktop",
icon: Monitor,
// A color like 'hsl(220, 98%, 61%)' or 'var(--color-name)'
color: "#2563eb",
// OR a theme object with 'light' and 'dark' keys
theme: {
light: "#2563eb",
dark: "#dc2626",
},
},
} satisfies ChartConfig
```
## Theming
Charts have built-in support for theming. You can use css variables (recommended) or color values in any color format, such as hex, hsl or oklch.
### CSS Variables
<Steps className="mb-0 pt-2">
<Step>Define your colors in your css file</Step>
```css title="app/globals.css" showLineNumbers
@layer base {
:root {
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
}
.dark {
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
}
}
```
<Step>Add the color to your `chartConfig`</Step>
```tsx title="components/example-chart.tsx" showLineNumbers
const chartConfig = {
desktop: {
label: "Desktop",
color: "var(--chart-1)",
},
mobile: {
label: "Mobile",
color: "var(--chart-2)",
},
} satisfies ChartConfig
```
</Steps>
### hex, hsl or oklch
You can also define your colors directly in the chart config. Use the color format you prefer.
```tsx title="components/example-chart.tsx" showLineNumbers
const chartConfig = {
desktop: {
label: "Desktop",
color: "#2563eb",
},
mobile: {
label: "Mobile",
color: "hsl(220, 98%, 61%)",
},
tablet: {
label: "Tablet",
color: "oklch(0.5 0.2 240)",
},
laptop: {
label: "Laptop",
color: "var(--chart-2)",
},
} satisfies ChartConfig
```
### Using Colors
To use the theme colors in your chart, reference the colors using the format `var(--color-KEY)`.
#### Components
```tsx
<Bar dataKey="desktop" fill="var(--color-desktop)" />
```
#### Chart Data
```tsx title="components/example-chart.tsx" showLineNumbers
const chartData = [
{ browser: "chrome", visitors: 275, fill: "var(--color-chrome)" },
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
]
```
#### Tailwind
```tsx title="components/example-chart.tsx"
<LabelList className="fill-(--color-desktop)" />
```
## Tooltip
A chart tooltip contains a label, name, indicator and value. You can use a combination of these to customize your tooltip.
<ComponentPreview styleName="base-nova" name="chart-tooltip" hideCode />
You can turn on/off any of these using the `hideLabel`, `hideIndicator` props and customize the indicator style using the `indicator` prop.
Use `labelKey` and `nameKey` to use a custom key for the tooltip label and name.
Chart comes with the `<ChartTooltip>` and `<ChartTooltipContent>` components. You can use these two components to add custom tooltips to your chart.
```tsx title="components/example-chart.tsx"
import { ChartTooltip, ChartTooltipContent } from "@/components/ui/chart"
```
```tsx title="components/example-chart.tsx"
<ChartTooltip content={<ChartTooltipContent />} />
```
### Props
Use the following props to customize the tooltip.
| Prop | Type | Description |
| :-------------- | :----------------------- | :------------------------------------------- |
| `labelKey` | string | The config or data key to use for the label. |
| `nameKey` | string | The config or data key to use for the name. |
| `indicator` | `dot` `line` or `dashed` | The indicator style for the tooltip. |
| `hideLabel` | boolean | Whether to hide the label. |
| `hideIndicator` | boolean | Whether to hide the indicator. |
### Colors
Colors are automatically referenced from the chart config.
### Custom
To use a custom key for tooltip label and names, use the `labelKey` and `nameKey` props.
```tsx showLineNumbers /browser/
const chartData = [
{ browser: "chrome", visitors: 187, fill: "var(--color-chrome)" },
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
]
const chartConfig = {
visitors: {
label: "Total Visitors",
},
chrome: {
label: "Chrome",
color: "var(--chart-1)",
},
safari: {
label: "Safari",
color: "var(--chart-2)",
},
} satisfies ChartConfig
```
```tsx title="components/example-chart.tsx"
<ChartTooltip
content={<ChartTooltipContent labelKey="visitors" nameKey="browser" />}
/>
```
This will use `Total Visitors` for label and `Chrome` and `Safari` for the tooltip names.
## Legend
You can use the custom `<ChartLegend>` and `<ChartLegendContent>` components to add a legend to your chart.
```tsx title="components/example-chart.tsx"
import { ChartLegend, ChartLegendContent } from "@/components/ui/chart"
```
```tsx title="components/example-chart.tsx"
<ChartLegend content={<ChartLegendContent />} />
```
### Colors
Colors are automatically referenced from the chart config.
### Custom
To use a custom key for legend names, use the `nameKey` prop.
```tsx showLineNumbers /browser/
const chartData = [
{ browser: "chrome", visitors: 187, fill: "var(--color-chrome)" },
{ browser: "safari", visitors: 200, fill: "var(--color-safari)" },
]
const chartConfig = {
chrome: {
label: "Chrome",
color: "var(--chart-1)",
},
safari: {
label: "Safari",
color: "var(--chart-2)",
},
} satisfies ChartConfig
```
```tsx title="components/example-chart.tsx"
<ChartLegend content={<ChartLegendContent nameKey="browser" />} />
```
This will use `Chrome` and `Safari` for the legend names.
## Accessibility
You can turn on the `accessibilityLayer` prop to add an accessible layer to your chart.
This prop adds keyboard access and screen reader support to your charts.
```tsx title="components/example-chart.tsx"
<LineChart accessibilityLayer />
```
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="chart-rtl"
direction="rtl"
previewClassName="h-92"
/>

View File

@@ -0,0 +1,136 @@
---
title: Checkbox
description: A control that allows the user to toggle between checked and not checked.
base: base
component: true
links:
doc: https://base-ui.com/react/components/checkbox
api: https://base-ui.com/react/components/checkbox#api-reference
---
<ComponentPreview
styleName="base-nova"
name="checkbox-demo"
previewClassName="h-80"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add checkbox
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="checkbox"
title="components/ui/checkbox.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Checkbox } from "@/components/ui/checkbox"
```
```tsx
<Checkbox />
```
## Checked State
Use `defaultChecked` for uncontrolled checkboxes, or `checked` and
`onCheckedChange` to control the state.
```tsx showLineNumbers
import * as React from "react"
export function Example() {
const [checked, setChecked] = React.useState(false)
return <Checkbox checked={checked} onCheckedChange={setChecked} />
}
```
## Invalid State
Set `aria-invalid` on the checkbox and `data-invalid` on the field wrapper to
show the invalid styles.
<ComponentPreview styleName="base-nova" name="checkbox-invalid" />
## Basic
Pair the checkbox with `Field` and `FieldLabel` for proper layout and labeling.
<ComponentPreview styleName="base-nova" name="checkbox-basic" />
## Description
Use `FieldContent` and `FieldDescription` for helper text.
<ComponentPreview styleName="base-nova" name="checkbox-description" />
## Disabled
Use the `disabled` prop to prevent interaction and add the `data-disabled` attribute to the `<Field>` component for disabled styles.
<ComponentPreview styleName="base-nova" name="checkbox-disabled" />
## Group
Use multiple fields to create a checkbox list.
<ComponentPreview styleName="base-nova" name="checkbox-group" />
## Table
<ComponentPreview
styleName="base-nova"
name="checkbox-table"
previewClassName="p-4 md:p-8"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="checkbox-rtl"
direction="rtl"
previewClassName="h-80"
/>
## API Reference
See the [Base UI](https://base-ui.com/react/components/checkbox#api-reference) documentation for more information.

View File

@@ -0,0 +1,142 @@
---
title: Collapsible
description: An interactive component which expands/collapses a panel.
base: base
component: true
featured: true
links:
doc: https://base-ui.com/react/components/collapsible
api: https://base-ui.com/react/components/collapsible#api-reference
---
<ComponentPreview styleName="base-nova" name="collapsible-demo" align="start" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add collapsible
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="collapsible"
title="components/ui/collapsible.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from "@/components/ui/collapsible"
```
```tsx showLineNumbers
<Collapsible>
<CollapsibleTrigger>Can I use this in my project?</CollapsibleTrigger>
<CollapsibleContent>
Yes. Free to use for personal and commercial projects. No attribution
required.
</CollapsibleContent>
</Collapsible>
```
## Composition
Use the following composition to build a `Collapsible`:
```text
Collapsible
├── CollapsibleTrigger
└── CollapsibleContent
```
## Controlled State
Use the `open` and `onOpenChange` props to control the state.
```tsx showLineNumbers
import * as React from "react"
export function Example() {
const [open, setOpen] = React.useState(false)
return (
<Collapsible open={open} onOpenChange={setOpen}>
<CollapsibleTrigger>Toggle</CollapsibleTrigger>
<CollapsibleContent>Content</CollapsibleContent>
</Collapsible>
)
}
```
## Basic
<ComponentPreview
styleName="base-nova"
name="collapsible-basic"
align="start"
/>
## Settings Panel
Use a trigger button to reveal additional settings.
<ComponentPreview styleName="base-nova" name="collapsible-settings" />
## File Tree
Use nested collapsibles to build a file tree.
<ComponentPreview
styleName="base-nova"
name="collapsible-file-tree"
previewClassName="h-[36rem]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="collapsible-rtl"
direction="rtl"
align="start"
/>
## API Reference
See the [Base UI](https://base-ui.com/react/components/collapsible#api-reference) documentation for more information.

View File

@@ -0,0 +1,326 @@
---
title: Combobox
description: Autocomplete input with a list of suggestions.
base: base
component: true
links:
doc: https://base-ui.com/react/components/combobox
api: https://base-ui.com/react/components/combobox#api-reference
---
<ComponentPreview
styleName="base-nova"
name="combobox-demo"
description="A combobox with a list of frameworks."
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add combobox
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="combobox"
title="components/ui/combobox.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox"
```
```tsx showLineNumbers
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"]
export function ExampleCombobox() {
return (
<Combobox items={frameworks}>
<ComboboxInput placeholder="Select a framework" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
)
}
```
## Composition
### Simple
A single-line input and a flat list (see [Basic](#basic)).
```text
Combobox
├── ComboboxInput
└── ComboboxContent
├── ComboboxEmpty
└── ComboboxList
├── ComboboxItem
└── ComboboxItem
```
### With chips
Multi-select with `multiple`, chips, and a chips input (see [Multiple](#multiple)).
```text
Combobox
├── ComboboxChips
│ ├── ComboboxValue
│ │ └── ComboboxChip
│ └── ComboboxChipsInput
└── ComboboxContent
├── ComboboxEmpty
└── ComboboxList
├── ComboboxItem
└── ComboboxItem
```
### With groups and collection
Nested items per group using `ComboboxCollection` inside each `ComboboxGroup`, with a separator between groups (see [Groups](#groups)).
```text
Combobox
├── ComboboxInput
└── ComboboxContent
├── ComboboxEmpty
└── ComboboxList
├── ComboboxGroup
│ ├── ComboboxLabel
│ └── ComboboxCollection
│ ├── ComboboxItem
│ └── ComboboxItem
├── ComboboxSeparator
└── ComboboxGroup
├── ComboboxLabel
└── ComboboxCollection
├── ComboboxItem
└── ComboboxItem
```
## Custom Items
Use `itemToStringValue` when your items are objects.
```tsx showLineNumbers
import * as React from "react"
import {
Combobox,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
} from "@/components/ui/combobox"
type Framework = {
label: string
value: string
}
const frameworks: Framework[] = [
{ label: "Next.js", value: "next" },
{ label: "SvelteKit", value: "sveltekit" },
{ label: "Nuxt", value: "nuxt" },
]
export function ExampleComboboxCustomItems() {
return (
<Combobox
items={frameworks}
itemToStringValue={(framework) => framework.label}
>
<ComboboxInput placeholder="Select a framework" />
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(framework) => (
<ComboboxItem key={framework.value} value={framework}>
{framework.label}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
)
}
```
## Multiple Selection
Use `multiple` with chips for multi-select behavior.
```tsx showLineNumbers
import * as React from "react"
import {
Combobox,
ComboboxChip,
ComboboxChips,
ComboboxChipsInput,
ComboboxContent,
ComboboxEmpty,
ComboboxInput,
ComboboxItem,
ComboboxList,
ComboboxValue,
} from "@/components/ui/combobox"
const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"]
export function ExampleComboboxMultiple() {
const [value, setValue] = React.useState<string[]>([])
return (
<Combobox
items={frameworks}
multiple
value={value}
onValueChange={setValue}
>
<ComboboxChips>
<ComboboxValue>
{value.map((item) => (
<ComboboxChip key={item}>{item}</ComboboxChip>
))}
</ComboboxValue>
<ComboboxChipsInput placeholder="Add framework" />
</ComboboxChips>
<ComboboxContent>
<ComboboxEmpty>No items found.</ComboboxEmpty>
<ComboboxList>
{(item) => (
<ComboboxItem key={item} value={item}>
{item}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
)
}
```
## Basic
A simple combobox with a list of frameworks.
<ComponentPreview styleName="base-nova" name="combobox-basic" />
## Multiple
A combobox with multiple selection using `multiple` and `ComboboxChips`.
<ComponentPreview styleName="base-nova" name="combobox-multiple" />
## Clear Button
Use the `showClear` prop to show a clear button.
<ComponentPreview styleName="base-nova" name="combobox-clear" />
## Groups
Use `ComboboxGroup` and `ComboboxSeparator` to group items.
<ComponentPreview styleName="base-nova" name="combobox-groups" />
## Custom Items
You can render a custom component inside `ComboboxItem`.
<ComponentPreview styleName="base-nova" name="combobox-custom" />
## Invalid
Use the `aria-invalid` prop to make the combobox invalid.
<ComponentPreview styleName="base-nova" name="combobox-invalid" />
## Disabled
Use the `disabled` prop to disable the combobox.
<ComponentPreview styleName="base-nova" name="combobox-disabled" />
## Auto Highlight
Use the `autoHighlight` prop to automatically highlight the first item on filter.
<ComponentPreview styleName="base-nova" name="combobox-auto-highlight" />
## Popup
You can trigger the combobox from a button or any other component by using the `render` prop. Move the `ComboboxInput` inside the `ComboboxContent`.
<ComponentPreview styleName="base-nova" name="combobox-popup" />
## Input Group
You can add an addon to the combobox by using the `InputGroupAddon` component inside the `ComboboxInput`.
<ComponentPreview styleName="base-nova" name="combobox-input-group" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="combobox-rtl"
direction="rtl"
align="start"
/>
## API Reference
See the [Base UI](https://base-ui.com/react/components/combobox#api-reference) documentation for more information.

View File

@@ -0,0 +1,153 @@
---
title: Command
description: Command menu for search and quick actions.
base: base
component: true
links:
doc: https://github.com/dip/cmdk
---
<ComponentPreview
styleName="base-nova"
name="command-demo"
align="start"
previewClassName="h-[24.5rem]"
/>
## About
The `<Command />` component uses the [`cmdk`](https://github.com/dip/cmdk) component by [Dip](https://www.dip.org/).
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add command
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install cmdk
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="command"
title="components/ui/command.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command"
```
```tsx showLineNumbers
<Command className="max-w-sm rounded-lg border">
<CommandInput placeholder="Type a command or search..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading="Suggestions">
<CommandItem>Calendar</CommandItem>
<CommandItem>Search Emoji</CommandItem>
<CommandItem>Calculator</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading="Settings">
<CommandItem>Profile</CommandItem>
<CommandItem>Billing</CommandItem>
<CommandItem>Settings</CommandItem>
</CommandGroup>
</CommandList>
</Command>
```
## Composition
Use the following composition to build a `Command`:
```text
Command
├── CommandInput
└── CommandList
├── CommandEmpty
├── CommandGroup
│ ├── CommandItem
│ └── CommandItem
├── CommandSeparator
└── CommandGroup
├── CommandItem
└── CommandItem
```
## Basic
A simple command menu in a dialog.
<ComponentPreview styleName="base-nova" name="command-basic" />
## Shortcuts
<ComponentPreview styleName="base-nova" name="command-shortcuts" />
## Groups
A command menu with groups, icons and separators.
<ComponentPreview styleName="base-nova" name="command-groups" />
## Scrollable
Scrollable command menu with multiple items.
<ComponentPreview styleName="base-nova" name="command-scrollable" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="command-rtl"
direction="rtl"
align="start"
previewClassName="h-[24.5rem]"
/>
## API Reference
See the [cmdk](https://github.com/dip/cmdk) documentation for more information.

View File

@@ -0,0 +1,193 @@
---
title: Context Menu
description: Displays a menu of actions triggered by a right click.
base: base
component: true
links:
doc: https://base-ui.com/react/components/context-menu
api: https://base-ui.com/react/components/context-menu#api-reference
---
<ComponentPreview
styleName="base-nova"
name="context-menu-demo"
description="A context menu with sub menu items."
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add context-menu
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="context-menu"
title="components/ui/context-menu.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
ContextMenu,
ContextMenuContent,
ContextMenuItem,
ContextMenuTrigger,
} from "@/components/ui/context-menu"
```
```tsx showLineNumbers
<ContextMenu>
<ContextMenuTrigger>Right click here</ContextMenuTrigger>
<ContextMenuContent>
<ContextMenuItem>Profile</ContextMenuItem>
<ContextMenuItem>Billing</ContextMenuItem>
<ContextMenuItem>Team</ContextMenuItem>
<ContextMenuItem>Subscription</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
```
## Composition
Use the following composition to build a `ContextMenu`:
```text
ContextMenu
├── ContextMenuTrigger
└── ContextMenuContent
├── ContextMenuGroup
│ ├── ContextMenuLabel
│ ├── ContextMenuItem
│ └── ContextMenuItem
├── ContextMenuSeparator
├── ContextMenuGroup
│ ├── ContextMenuLabel
│ ├── ContextMenuCheckboxItem
│ └── ContextMenuCheckboxItem
├── ContextMenuSeparator
├── ContextMenuGroup
│ ├── ContextMenuLabel
│ └── ContextMenuRadioGroup
│ ├── ContextMenuRadioItem
│ └── ContextMenuRadioItem
└── ContextMenuSub
├── ContextMenuSubTrigger
└── ContextMenuSubContent
└── ContextMenuGroup
├── ContextMenuItem
└── ContextMenuItem
```
## Basic
A simple context menu with a few actions.
<ComponentPreview styleName="base-nova" name="context-menu-basic" />
## Submenu
Use `ContextMenuSub` to nest secondary actions.
<ComponentPreview styleName="base-nova" name="context-menu-submenu" />
## Shortcuts
Add `ContextMenuShortcut` to show keyboard hints.
<ComponentPreview styleName="base-nova" name="context-menu-shortcuts" />
## Groups
Group related actions and separate them with dividers.
<ComponentPreview styleName="base-nova" name="context-menu-groups" />
## Icons
Combine icons with labels for quick scanning.
<ComponentPreview styleName="base-nova" name="context-menu-icons" />
## Checkboxes
Use `ContextMenuCheckboxItem` for toggles.
<ComponentPreview styleName="base-nova" name="context-menu-checkboxes" />
## Radio
Use `ContextMenuRadioItem` for exclusive choices.
<ComponentPreview styleName="base-nova" name="context-menu-radio" />
## Destructive
Use `variant="destructive"` to style the menu item as destructive.
<ComponentPreview styleName="base-nova" name="context-menu-destructive" />
## Sides
Control submenu placement with side and align props.
<ComponentPreview styleName="base-nova" name="context-menu-sides" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="context-menu-rtl"
direction="rtl"
/>
Use `side="inline-end"` to place the menu on the logical right side of the trigger.
```tsx showLineNumbers
<ContextMenu>
<ContextMenuTrigger>Right click here</ContextMenuTrigger>
<ContextMenuContent side="inline-end">
<ContextMenuItem>Profile</ContextMenuItem>
<ContextMenuItem>Billing</ContextMenuItem>
<ContextMenuItem>Team</ContextMenuItem>
<ContextMenuItem>Subscription</ContextMenuItem>
</ContextMenuContent>
</ContextMenu>
```
## API Reference
See the [Base UI](https://base-ui.com/react/components/context-menu#api-reference) documentation for more information.

View File

@@ -0,0 +1,901 @@
---
title: Data Table
description: Powerful table and datagrids built using TanStack Table.
base: base
component: true
links:
doc: https://tanstack.com/table/latest/docs/overview
---
<ComponentPreview
styleName="base-nova"
name="data-table-demo"
align="start"
previewClassName="items-start h-auto px-4 md:px-8"
hideCode
/>
## Introduction
Every data table or datagrid I've created has been unique. They all behave differently, have specific sorting and filtering requirements, and work with different data sources.
It doesn't make sense to combine all of these variations into a single component. If we do that, we'll lose the flexibility that [headless UI](https://tanstack.com/table/latest/docs/overview#what-is-headless-ui) provides.
So instead of a data-table component, I thought it would be more helpful to provide a guide on how to build your own.
We'll start with the basic `<Table />` component and build a complex data table from scratch.
<Callout className="mt-4">
**Tip:** If you find yourself using the same table in multiple places in your app, you can always extract it into a reusable component.
</Callout>
## Table of Contents
This guide will show you how to use [TanStack Table](https://tanstack.com/table) and the `<Table />` component to build your own custom data table. We'll cover the following topics:
- [Set up Table Features](#set-up-table-features)
- [Basic Table](#basic-table)
- [Row Actions](#row-actions)
- [Pagination](#pagination)
- [Sorting](#sorting)
- [Filtering](#filtering)
- [Visibility](#visibility)
- [Row Selection](#row-selection)
- [Reusable Components](#reusable-components)
## Installation
1. Add the `<Table />` component to your project:
```bash
npx shadcn@latest add table
```
2. Add the `@tanstack/react-table` dependency. This guide uses **TanStack Table v9**:
```bash
npm install @tanstack/react-table
```
## Prerequisites
We are going to build a table to show recent payments. Here's what our data looks like:
```tsx showLineNumbers
type Payment = {
id: string
amount: number
status: "pending" | "processing" | "success" | "failed"
email: string
}
export const payments: Payment[] = [
{
id: "728ed52f",
amount: 100,
status: "pending",
email: "m@example.com",
},
{
id: "489e1d42",
amount: 125,
status: "processing",
email: "example@gmail.com",
},
// ...
]
```
## Project Structure
Start by creating the following file structure:
```txt
app
└── payments
├── columns.tsx
├── data-table-features.ts
├── data-table.tsx
└── page.tsx
```
I'm using a Next.js example here but this works for any other React framework.
- `columns.tsx` (client component) will contain our column definitions.
- `data-table-features.ts` will contain the shared `features` object that tells TanStack Table which behavior to enable.
- `data-table.tsx` (client component) will contain our `<DataTable />` component.
- `page.tsx` (server component) is where we'll fetch data and render our table.
## Set up Table Features
TanStack Table v9 is feature-based: you opt into the behavior you want — sorting, filtering, pagination, and so on — by declaring it with `tableFeatures()`. Anything you don't list is tree-shaken out of your bundle. That includes the built-in filter and sort functions: register the ones your columns rely on under `filterFns` and `sortFns` (our email filter uses `includesString`, and string columns sort with `text` / `alphanumeric`).
```tsx showLineNumbers title="app/payments/data-table-features.ts"
import {
columnFilteringFeature,
columnVisibilityFeature,
createFilteredRowModel,
createPaginatedRowModel,
createSortedRowModel,
filterFn_includesString,
rowPaginationFeature,
rowSelectionFeature,
rowSortingFeature,
sortFn_alphanumeric,
sortFn_text,
tableFeatures,
} from "@tanstack/react-table"
// New in v9: declare the features this table uses — anything you don't
// register is tree-shaken out of the bundle.
export const features = tableFeatures({
columnFilteringFeature,
columnVisibilityFeature,
rowPaginationFeature,
rowSelectionFeature,
rowSortingFeature,
filteredRowModel: createFilteredRowModel(),
paginatedRowModel: createPaginatedRowModel(),
sortedRowModel: createSortedRowModel(),
filterFns: { includesString: filterFn_includesString },
sortFns: { alphanumeric: sortFn_alphanumeric, text: sortFn_text },
})
// Pass this as the first generic argument to `ColumnDef`, `Column`, `Table`,
// and `Row` so each type knows which feature APIs are available.
export type DataTableFeatures = typeof features
```
<Callout className="mt-4">
**Note:** The core row model is always included, so you never register it yourself. Row models for optional features are created with `create*RowModel()` and registered on the features object — there are no more `get*RowModel` table options.
</Callout>
## Basic Table
Let's start by building a basic table.
<Steps className="mb-0 pt-2">
### Column Definitions
First, we'll define our columns.
```tsx showLineNumbers title="app/payments/columns.tsx" {3,5,16-17,19-29}
"use client"
import { createColumnHelper } from "@tanstack/react-table"
import { type DataTableFeatures } from "./data-table-features"
// This type is used to define the shape of our data.
// You can use a Zod schema here if you want.
export type Payment = {
id: string
amount: number
status: "pending" | "processing" | "success" | "failed"
email: string
}
// Use `accessor` for data columns and `display` for columns without one.
const columnHelper = createColumnHelper<DataTableFeatures, Payment>()
export const columns = columnHelper.columns([
columnHelper.accessor("status", {
header: "Status",
}),
columnHelper.accessor("email", {
header: "Email",
}),
columnHelper.accessor("amount", {
header: "Amount",
}),
])
```
<Callout className="mt-4">
**Note:** Columns are where you define the core of what your table
will look like. They define the data that will be displayed, how it will be
formatted, sorted and filtered.
</Callout>
### `<DataTable />` component
Next, we'll create a `<DataTable />` component to render our table.
```tsx showLineNumbers title="app/payments/data-table.tsx"
"use client"
import { useTable, type ColumnDef, type RowData } from "@tanstack/react-table"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { features, type DataTableFeatures } from "./data-table-features"
interface DataTableProps<TData extends RowData> {
columns: ColumnDef<DataTableFeatures, TData>[]
data: TData[]
}
export function DataTable<TData extends RowData>({
columns,
data,
}: DataTableProps<TData>) {
const table = useTable({
features,
data,
columns,
})
return (
<div className="overflow-hidden rounded-md border">
<Table>
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => {
return (
<TableHead key={header.id}>
{header.isPlaceholder ? null : (
<table.FlexRender header={header} />
)}
</TableHead>
)
})}
</TableRow>
))}
</TableHeader>
<TableBody>
{table.getRowModel().rows?.length ? (
table.getRowModel().rows.map((row) => (
<TableRow
key={row.id}
data-state={row.getIsSelected() && "selected"}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
<table.FlexRender cell={cell} />
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={columns.length} className="h-24 text-center">
No results.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
)
}
```
<Callout>
**Tip**: If you find yourself using `<DataTable />` in multiple places, this is the component you could make reusable by extracting it to `components/ui/data-table.tsx`.
`<DataTable columns={columns} data={data} />`
</Callout>
<Callout className="mt-4">
**`<table.FlexRender />` vs `flexRender`:** This guide uses v9's `<table.FlexRender header={header} />` and `<table.FlexRender cell={cell} />` component, available right on the table instance — no extra import needed. The classic `flexRender(component, context)` helper from v8 still works too, if you prefer the function form (or need to render outside the component that owns `table`, where you can also import the standalone `<FlexRender />`).
</Callout>
### Render the table
Finally, we'll render our table in our page component.
```tsx showLineNumbers title="app/payments/page.tsx" {22}
import { columns, Payment } from "./columns"
import { DataTable } from "./data-table"
async function getData(): Promise<Payment[]> {
// Fetch data from your API here.
return [
{
id: "728ed52f",
amount: 100,
status: "pending",
email: "m@example.com",
},
// ...
]
}
export default async function DemoPage() {
const data = await getData()
return (
<div className="container mx-auto py-10">
<DataTable columns={columns} data={data} />
</div>
)
}
```
</Steps>
## Cell Formatting
Let's format the amount cell to display the dollar amount. We'll also align the cell to the right.
<Steps className="mb-0 pt-2">
### Update columns definition
Update the `header` and `cell` definitions for amount as follows:
```tsx showLineNumbers title="app/payments/columns.tsx" {3-13}
export const columns = columnHelper.columns([
columnHelper.accessor("amount", {
header: () => <div className="text-right">Amount</div>,
cell: ({ row }) => {
const amount = parseFloat(row.getValue("amount"))
const formatted = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(amount)
return <div className="text-right font-medium">{formatted}</div>
},
}),
])
```
You can use the same approach to format other cells and headers.
</Steps>
## Row Actions
Let's add row actions to our table. We'll use a `<DropdownMenu />` component for this.
<Steps className="mb-0 pt-2">
### Update columns definition
Update our columns definition to add a new `actions` column. The `actions` cell returns a `<DropdownMenu />` component.
```tsx showLineNumbers title="app/payments/columns.tsx" {4,6-14,18-45}
"use client"
import { createColumnHelper } from "@tanstack/react-table"
import { MoreHorizontal } from "lucide-react"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export const columns = columnHelper.columns([
// ...
columnHelper.display({
id: "actions",
cell: ({ row }) => {
const payment = row.original
return (
<DropdownMenu>
<DropdownMenuTrigger
render={<Button variant="ghost" className="h-8 w-8 p-0" />}
>
<span className="sr-only">Open menu</span>
<MoreHorizontal className="h-4 w-4" />
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Actions</DropdownMenuLabel>
<DropdownMenuItem
onClick={() => navigator.clipboard.writeText(payment.id)}
>
Copy payment ID
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
},
}),
// ...
])
```
You can access the row data using `row.original` in the `cell` function. Use this to handle actions for your row eg. use the `id` to make a DELETE call to your API.
</Steps>
## Pagination
Next, we'll add pagination to our table.
<Steps className="mb-0 pt-2">
### Pagination is already enabled
Because our features object includes `rowPaginationFeature` and `createPaginatedRowModel()`, the table automatically paginates rows into pages of 10 — there's nothing to add to `useTable`. See the [pagination docs](https://tanstack.com/table/latest/docs/framework/react/guide/pagination) for more information on customizing page size and implementing manual pagination.
### Add pagination controls
We can add pagination controls to our table using the `<Button />` component and the `table.previousPage()`, `table.nextPage()` API methods.
```tsx showLineNumbers title="app/payments/data-table.tsx" {1,20-37}
import { Button } from "@/components/ui/button"
export function DataTable<TData extends RowData>({
columns,
data,
}: DataTableProps<TData>) {
const table = useTable({
features,
data,
columns,
})
return (
<div>
<div className="overflow-hidden rounded-md border">
<Table>
{ // .... }
</Table>
</div>
<div className="flex items-center justify-end space-x-2 py-4">
<Button
variant="outline"
size="sm"
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
Previous
</Button>
<Button
variant="outline"
size="sm"
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
Next
</Button>
</div>
</div>
)
}
```
See [Reusable Components](#reusable-components) section for a more advanced pagination component.
</Steps>
## Sorting
Let's make the email column sortable.
The `rowSortingFeature` and sorted row model are already registered in our features object, so all that's left is wiring up the sorting state.
<Steps className="mb-0 pt-2">
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {3,8,15,21-24}
"use client"
import * as React from "react"
import {
useTable,
type ColumnDef,
type RowData,
type SortingState,
} from "@tanstack/react-table"
export function DataTable<TData extends RowData>({
columns,
data,
}: DataTableProps<TData>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const table = useTable({
features,
data,
columns,
onSortingChange: setSorting,
state: {
sorting,
},
})
return (
<div>
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}
```
### Make header cell sortable
We can now update the `email` header cell to add sorting controls.
```tsx showLineNumbers title="app/payments/columns.tsx" {4,8-18}
"use client"
import { createColumnHelper } from "@tanstack/react-table"
import { ArrowUpDown } from "lucide-react"
export const columns = columnHelper.columns([
columnHelper.accessor("email", {
header: ({ column }) => {
return (
<Button
variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Email
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
)
},
}),
])
```
This will automatically sort the table (asc and desc) when the user toggles on the header cell.
</Steps>
## Filtering
Let's add a search input to filter emails in our table.
The `columnFilteringFeature` and filtered row model are already part of our features object, so we only need to wire up the filter state and render an input.
<Steps className="mb-0 pt-2">
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {7,13,20-22,29,32,38-46}
"use client"
import * as React from "react"
import {
useTable,
type ColumnDef,
type ColumnFiltersState,
type RowData,
type SortingState,
} from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
export function DataTable<TData extends RowData>({
columns,
data,
}: DataTableProps<TData>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const table = useTable({
features,
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
state: {
sorting,
columnFilters,
},
})
return (
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
</div>
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}
```
Filtering is now enabled for the `email` column. You can add filters to other columns as well. See the [filtering docs](https://tanstack.com/table/latest/docs/framework/react/guide/column-filtering) for more information on customizing filters.
</Steps>
## Visibility
Adding column visibility is fairly simple using `@tanstack/react-table` visibility API.
<Steps className="mb-0 pt-2">
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {8,14-19,29-30,38,42,57-84}
"use client"
import * as React from "react"
import {
useTable,
type ColumnDef,
type ColumnFiltersState,
type ColumnVisibilityState,
type RowData,
type SortingState,
} from "@tanstack/react-table"
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuCheckboxItem,
DropdownMenuContent,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export function DataTable<TData extends RowData>({
columns,
data,
}: DataTableProps<TData>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [columnVisibility, setColumnVisibility] =
React.useState<ColumnVisibilityState>({})
const table = useTable({
features,
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
onColumnVisibilityChange: setColumnVisibility,
state: {
sorting,
columnFilters,
columnVisibility,
},
})
return (
<div>
<div className="flex items-center py-4">
<Input
placeholder="Filter emails..."
value={table.getColumn("email")?.getFilterValue() as string}
onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value)
}
className="max-w-sm"
/>
<DropdownMenu>
<DropdownMenuTrigger render={<Button variant="outline" className="ml-auto" />}>
Columns
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{table
.getAllColumns()
.filter(
(column) => column.getCanHide()
)
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</DropdownMenuCheckboxItem>
)
})}
</DropdownMenuContent>
</DropdownMenu>
</div>
<div className="overflow-hidden rounded-md border">
<Table>{ ... }</Table>
</div>
</div>
)
}
```
This adds a dropdown menu that you can use to toggle column visibility.
</Steps>
## Row Selection
Next, we're going to add row selection to our table.
<Steps className="mb-0 pt-2">
### Update column definitions
```tsx showLineNumbers title="app/payments/columns.tsx" {6,9-30}
"use client"
import { createColumnHelper } from "@tanstack/react-table"
import { Badge } from "@/components/ui/badge"
import { Checkbox } from "@/components/ui/checkbox"
export const columns = columnHelper.columns([
columnHelper.display({
id: "select",
header: ({ table }) => (
<Checkbox
checked={table.getIsAllPageRowsSelected()}
indeterminate={
table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected()
}
onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
aria-label="Select all"
/>
),
cell: ({ row }) => (
<Checkbox
checked={row.getIsSelected()}
onCheckedChange={(value) => row.toggleSelected(!!value)}
aria-label="Select row"
/>
),
enableSorting: false,
enableHiding: false,
}),
])
```
### Update `<DataTable>`
```tsx showLineNumbers title="app/payments/data-table.tsx" {11,20,25}
export function DataTable<TData extends RowData>({
columns,
data,
}: DataTableProps<TData>) {
const [sorting, setSorting] = React.useState<SortingState>([])
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[]
)
const [columnVisibility, setColumnVisibility] =
React.useState<ColumnVisibilityState>({})
const [rowSelection, setRowSelection] = React.useState({})
const table = useTable({
features,
data,
columns,
onSortingChange: setSorting,
onColumnFiltersChange: setColumnFilters,
onColumnVisibilityChange: setColumnVisibility,
onRowSelectionChange: setRowSelection,
state: {
sorting,
columnFilters,
columnVisibility,
rowSelection,
},
})
return (
<div>
<div className="overflow-hidden rounded-md border">
<Table />
</div>
</div>
)
}
```
This adds a checkbox to each row and a checkbox in the header to select all rows.
### Show selected rows
You can show the number of selected rows using the `table.getFilteredSelectedRowModel()` API.
```tsx
<div className="flex-1 text-sm text-muted-foreground">
{table.getFilteredSelectedRowModel().rows.length} of{" "}
{table.getFilteredRowModel().rows.length} row(s) selected.
</div>
```
</Steps>
## Reusable Components
Here are some components you can use to build your data tables. This is from the [Tasks](/examples/tasks) demo, which shares its features object (and the matching `TasksTableFeatures` type) across every component via a `data-table-features.ts` module — the same pattern we set up in [Set up Table Features](#set-up-table-features).
### Column header
Make any column header sortable and hideable.
<ComponentSource
src="/app/(app)/examples/tasks/components/data-table-column-header.tsx"
title="components/data-table-column-header.tsx"
/>
```tsx showLineNumbers {4}
export const columns = columnHelper.columns([
columnHelper.accessor("email", {
header: ({ column }) => (
<DataTableColumnHeader column={column} title="Email" />
),
}),
])
```
### Pagination
Add pagination controls to your table including page size and selection count.
<ComponentSource
src="/app/(app)/examples/tasks/components/data-table-pagination.tsx"
styleName="radix-nova"
/>
```tsx
<DataTablePagination table={table} />
```
### Column toggle
A component to toggle column visibility.
<ComponentSource
src="/app/(app)/examples/tasks/components/data-table-view-options.tsx"
styleName="radix-nova"
/>
```tsx
<DataTableViewOptions table={table} />
```
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="data-table-rtl"
direction="rtl"
previewClassName="items-start h-auto px-4 md:px-8"
hideCode
/>

View File

@@ -0,0 +1,116 @@
---
title: Date Picker
description: A date picker component with range and presets.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="date-picker-demo" />
## Installation
The Date Picker is built using a composition of the `<Popover />` and the `<Calendar />` components.
See installation instructions for the [Popover](/docs/components/base/popover#installation) and the [Calendar](/docs/components/base/calendar#installation) components.
## Usage
```tsx showLineNumbers title="components/example-date-picker.tsx"
"use client"
import * as React from "react"
import { cn } from "cn"
import { format } from "date-fns"
import { Calendar as CalendarIcon } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Calendar } from "@/components/ui/calendar"
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover"
export function DatePickerDemo() {
const [date, setDate] = React.useState<Date>()
return (
<Popover>
<PopoverTrigger
render={
<Button
variant="outline"
data-empty={!date}
className="justify-start text-left font-normal data-[empty=true]:text-muted-foreground"
/>
}
>
<CalendarIcon />
{date ? format(date, "PPP") : <span>Pick a date</span>}
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar mode="single" selected={date} onSelect={setDate} />
</PopoverContent>
</Popover>
)
}
```
See the [React DayPicker](https://react-day-picker.js.org) documentation for more information.
## Composition
A date picker is built from `Popover` and `Calendar` (there is no `DatePicker` root component):
```text
Popover
├── PopoverTrigger
└── PopoverContent
└── Calendar
```
## Basic
A basic date picker component.
<ComponentPreview styleName="base-nova" name="date-picker-basic" />
## Range Picker
A date picker component for selecting a range of dates.
<ComponentPreview styleName="base-nova" name="date-picker-range" />
## Date of Birth
A date picker component for selecting a date of birth. This component includes a dropdown caption layout for date and month selection.
<ComponentPreview styleName="base-nova" name="date-picker-dob" />
## Input
A date picker component with an input field for selecting a date.
<ComponentPreview styleName="base-nova" name="date-picker-input" />
## Time Picker
A date picker component with a time input field for selecting a time.
<ComponentPreview styleName="base-nova" name="date-picker-time" />
## Natural Language Picker
This component uses the `chrono-node` library to parse natural language dates.
<ComponentPreview styleName="base-nova" name="date-picker-natural-language" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="date-picker-rtl"
direction="rtl"
/>

View File

@@ -0,0 +1,134 @@
---
title: Dialog
description: A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
featured: true
base: base
component: true
links:
doc: https://base-ui.com/react/components/dialog
api: https://base-ui.com/react/components/dialog#api-reference
---
<ComponentPreview
styleName="base-nova"
name="dialog-demo"
description="A dialog for editing profile details."
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add dialog
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="dialog"
title="components/ui/dialog.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
```
```tsx showLineNumbers
<Dialog>
<DialogTrigger>Open</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Are you absolutely sure?</DialogTitle>
<DialogDescription>
This action cannot be undone. This will permanently delete your account
and remove your data from our servers.
</DialogDescription>
</DialogHeader>
</DialogContent>
</Dialog>
```
## Composition
Use the following composition to build a `Dialog`:
```text
Dialog
├── DialogTrigger
└── DialogContent
├── DialogHeader
│ ├── DialogTitle
│ └── DialogDescription
└── DialogFooter
```
## Custom Close Button
Replace the default close control with your own button.
<ComponentPreview styleName="base-nova" name="dialog-close-button" />
## No Close Button
Use `showCloseButton={false}` to hide the close button.
<ComponentPreview styleName="base-nova" name="dialog-no-close-button" />
## Sticky Footer
Keep actions visible while the content scrolls.
<ComponentPreview styleName="base-nova" name="dialog-sticky-footer" />
## Scrollable Content
Long content can scroll while the header stays in view.
<ComponentPreview styleName="base-nova" name="dialog-scrollable-content" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="dialog-rtl" direction="rtl" />
## API Reference
See the [Base UI](https://base-ui.com/react/components/dialog#api-reference) documentation for more information.

View File

@@ -0,0 +1,93 @@
---
title: Direction
description: A provider component that sets the text direction for your application.
base: base
component: true
links:
doc: https://base-ui.com/react/utils/direction-provider
api: https://base-ui.com/react/utils/direction-provider#api-reference
---
The `DirectionProvider` component is used to set the text direction (`ltr` or `rtl`) for your application. This is essential for supporting right-to-left languages like Arabic, Hebrew, and Persian.
Here's a preview of the component in RTL mode. Use the language selector to switch the language. To see more examples, look for the RTL section on components pages.
<ComponentPreview
styleName="base-nova"
name="card-rtl"
direction="rtl"
previewClassName="h-auto"
hideCode
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add direction
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="direction"
title="components/ui/direction.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { DirectionProvider } from "@/components/ui/direction"
```
```tsx showLineNumbers
<html dir="rtl">
<body>
<DirectionProvider direction="rtl">
{/* Your app content */}
</DirectionProvider>
</body>
</html>
```
## useDirection
The `useDirection` hook is used to get the current direction of the application.
```tsx showLineNumbers
import { useDirection } from "@/components/ui/direction"
function MyComponent() {
const direction = useDirection()
return <div>Current direction: {direction}</div>
}
```

View File

@@ -0,0 +1,325 @@
---
title: Drawer
description: A drawer component for React.
base: base
component: true
links:
doc: https://base-ui.com/react/components/drawer
api: https://base-ui.com/react/components/drawer#api-reference
---
<ComponentPreview styleName="base-rhea" name="drawer-demo" />
<Callout>
The drawer component now uses [Base
UI](https://base-ui.com/react/components/drawer) instead of Vaul. If you
installed the previous version, see the [migration
guide](#migrating-from-vaul).
</Callout>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add drawer
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="drawer"
title="components/ui/drawer.tsx"
styleName="base-rhea"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
Add the following to your global styles. On iOS Safari, the drawer overlay is absolutely positioned and requires a positioned `body` to cover the viewport after the page is scrolled. See the [Base UI docs](https://base-ui.com/react/overview/quick-start#ios-26-safari) for details.
```css
body {
position: relative;
}
```
## Usage
```tsx showLineNumbers
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer"
```
```tsx showLineNumbers
<Drawer>
<DrawerTrigger render={<Button variant="outline" />}>Open</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Are you absolutely sure?</DrawerTitle>
<DrawerDescription>This action cannot be undone.</DrawerDescription>
</DrawerHeader>
<div className="p-4">{/* Content here */}</div>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose render={<Button variant="outline" />}>Cancel</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
```
## Composition
Use the following composition to build a `Drawer`:
```text
Drawer
├── DrawerTrigger
└── DrawerContent
├── DrawerHeader
│ ├── DrawerTitle
│ └── DrawerDescription
└── DrawerFooter
```
`DrawerContent` composes the portal, overlay, viewport, and popup from Base UI. For lower-level control, `DrawerPortal`, `DrawerOverlay`, and `DrawerSwipeHandle` are also exported.
## Custom Sizes
A vertical drawer sizes itself to its content and is capped at `calc(100dvh - 6rem)` by default. A side drawer spans `75%` of the viewport width, or `24rem` on larger screens.
To customize the height of a vertical drawer, use the `h-*` and `max-h-*` utilities on `DrawerContent`.
```tsx
<DrawerContent className="h-[50vh]">
```
To customize the width of a side drawer, use the `w-*` and `max-w-*` utilities on `DrawerContent`.
```tsx
<DrawerContent className="w-96">
```
When the same component renders in multiple directions, scope an override to one axis using the `data-[swipe-axis=*]` variants.
```tsx
<DrawerContent className="data-[swipe-axis=y]:max-h-[50vh] data-[swipe-axis=x]:w-96">
```
To make a region of the drawer scrollable, make the scroll container a flex item. Avoid `h-full`, which does not resolve inside a content-sized drawer.
```tsx
<DrawerContent>
<DrawerHeader>...</DrawerHeader>
<div className="flex-1 overflow-y-auto p-4">{/* Scrollable content */}</div>
<DrawerFooter>...</DrawerFooter>
</DrawerContent>
```
## Styling
The drawer exposes CSS variables for style-level customization. Set the sizing variables on `DrawerContent`. Set the overlay variable on `[data-slot=drawer-overlay]` in your CSS.
| Variable | Default | Description |
| ------------------------------ | ---------------------- | ----------------------------------------------------------------------- |
| `--drawer-inset` | `0px` | Floats the drawer from the viewport edges. |
| `--drawer-bleed-background` | `var(--color-popover)` | Fills the gap behind the drawer on swipe overshoot. |
| `--drawer-overlay-min-opacity` | `0` | Minimum overlay opacity. Defaults to `0.5` when snap points are active. |
The drawer also sets data attributes you can target with variants such as `data-[swipe-direction=down]:` on `DrawerContent`, or `group-data-[swipe-axis=y]/drawer-popup:` on its descendants.
| Attribute | Values | Set when |
| ------------------------- | ----------------------------- | ------------------------------------- |
| `data-swipe-direction` | `up`, `right`, `down`, `left` | Always. |
| `data-swipe-axis` | `x`, `y` | Always. |
| `data-snap-points` | Present | The drawer has snap points. |
| `data-expanded` | Present | The drawer is at the full snap point. |
| `data-swiping` | Present | A swipe is in progress. |
| `data-nested-drawer-open` | Present | A nested drawer is open on top. |
## Position
Use the `swipeDirection` prop to set the side of the drawer.
Available options are `up`, `right`, `down`, and `left`.
<ComponentPreview styleName="base-rhea" name="drawer-sides" />
## Swipe Handle
Use `showSwipeHandle` on `Drawer` to render a swipe handle.
<ComponentPreview styleName="base-rhea" name="drawer-swipe-handle" />
## Nested
Open drawers from inside another drawer. Parent drawers stay mounted and stack behind the frontmost drawer.
<ComponentPreview styleName="base-rhea" name="drawer-nested" />
## Non Modal
Set `modal={false}` to allow interaction with the rest of the page while the drawer is open. Combine with `disablePointerDismissal` to prevent the drawer from closing on outside presses. Use `modal="trap-focus"` to keep focus inside the drawer while leaving scroll and pointer interaction unrestricted.
<ComponentPreview styleName="base-rhea" name="drawer-non-modal" />
## Snap Points
Use `snapPoints` to snap a drawer to preset heights. Numbers between `0` and `1` represent fractions of the viewport. Numbers greater than `1` are treated as pixel values. String values support `px` and `rem` units. Snap points apply to vertical drawers.
Track the active snap point with the controlled `snapPoint` and `onSnapPointChange` props. At the full snap point, the drawer gets a `data-expanded` attribute you can style with the `data-expanded:` variant.
<ComponentPreview styleName="base-rhea" name="drawer-snap-points" />
## Responsive
You can combine the `Dialog` and `Drawer` components to create a responsive dialog. This renders a `Dialog` component on desktop and a `Drawer` on mobile.
<ComponentPreview styleName="base-rhea" name="drawer-dialog" />
## Migrating from Vaul
The base drawer now uses [Base UI](https://base-ui.com/react/components/drawer)
instead of Vaul. If you installed the previous base drawer, update your usage
to the Base UI API.
<Steps>
<Step>Update the dependency.</Step>
```diff
- npm install vaul
+ npm install @base-ui/react
```
<Step>Replace `direction` with `swipeDirection`.</Step>
Use `down` instead of `bottom`, and `up` instead of `top`. `left` and `right`
stay the same.
```diff
- <Drawer direction="bottom">
+ <Drawer swipeDirection="down">
```
<Step>Replace `asChild` with `render`.</Step>
For `DrawerTrigger`, pass the trigger element to the `render` prop.
```diff
- <DrawerTrigger asChild>
- <Button variant="outline">Open</Button>
- </DrawerTrigger>
+ <DrawerTrigger render={<Button variant="outline" />}>
+ Open
+ </DrawerTrigger>
```
For `DrawerClose`, pass the close element to the `render` prop.
```diff
- <DrawerClose asChild>
- <Button variant="outline">Cancel</Button>
- </DrawerClose>
+ <DrawerClose render={<Button variant="outline" />}>
+ Cancel
+ </DrawerClose>
```
<Step>Update snap point props.</Step>
If you use snap points, rename the controlled snap point props and the sequential
snap point prop.
```diff
<Drawer
snapPoints={[0.25, 0.5, 1]}
- activeSnapPoint={snapPoint}
- setActiveSnapPoint={setSnapPoint}
- snapToSequentialPoint
+ snapPoint={snapPoint}
+ onSnapPointChange={setSnapPoint}
+ snapToSequentialPoints
>
```
<Step>Update animation and focus props.</Step>
```diff
- <Drawer onAnimationEnd={(open) => setDone(open)}>
+ <Drawer onOpenChangeComplete={(open) => setDone(open)}>
```
```diff
- <DrawerContent onOpenAutoFocus={(event) => event.preventDefault()}>
+ <DrawerContent initialFocus={false}>
```
<Step>Review Vaul-only props.</Step>
Vaul props like `handleOnly`, `repositionInputs`, and
`shouldScaleBackground` do not have one-to-one replacements in the base drawer
API. Use Base UI props such as `disablePointerDismissal`, `modal`, `snapPoints`,
or controlled `open` state for the behavior you need.
```diff
- <Drawer handleOnly repositionInputs={false} shouldScaleBackground>
+ <Drawer>
```
```diff
- <Drawer dismissible={false}>
+ <Drawer disablePointerDismissal>
```
<Step>Update custom data attribute selectors.</Step>
Replace Vaul's `data-vaul-drawer-direction` selectors with Base UI's
`data-swipe-direction` selectors.
```diff
- <DrawerContent className="data-[vaul-drawer-direction=bottom]:max-h-[50vh]">
+ <DrawerContent className="data-[swipe-direction=down]:max-h-[50vh]">
```
Base UI also exposes attributes like `data-swiping`, `data-starting-style`, and
`data-ending-style` for swipe and transition states. Descendants inside
`DrawerContent` can use `group-data-[swipe-axis=x]/drawer-popup` and
`group-data-[swipe-axis=y]/drawer-popup` for axis-specific styling.
</Steps>
## API Reference
See the [Base UI documentation](https://base-ui.com/react/components/drawer) for the full API reference.

View File

@@ -0,0 +1,205 @@
---
title: Dropdown Menu
description: Displays a menu to the user — such as a set of actions or functions — triggered by a button.
featured: true
base: base
component: true
links:
doc: https://base-ui.com/react/components/menu
api: https://base-ui.com/react/components/menu#api-reference
---
<ComponentPreview
styleName="base-nova"
name="dropdown-menu-demo"
description="A dropdown menu with icons, shortcuts and sub menu items."
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add dropdown-menu
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="dropdown-menu"
title="components/ui/dropdown-menu.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
```
```tsx showLineNumbers
<DropdownMenu>
<DropdownMenuTrigger render={<Button variant="outline" />}>
Open
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuGroup>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Billing</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem>Team</DropdownMenuItem>
<DropdownMenuItem>Subscription</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
```
## Composition
Use the following composition to build a `DropdownMenu`:
```text
DropdownMenu
├── DropdownMenuTrigger
└── DropdownMenuContent
├── DropdownMenuGroup
│ ├── DropdownMenuLabel
│ ├── DropdownMenuItem
│ └── DropdownMenuItem
├── DropdownMenuSeparator
├── DropdownMenuGroup
│ ├── DropdownMenuLabel
│ ├── DropdownMenuCheckboxItem
│ └── DropdownMenuCheckboxItem
├── DropdownMenuSeparator
├── DropdownMenuGroup
│ ├── DropdownMenuLabel
│ └── DropdownMenuRadioGroup
│ ├── DropdownMenuRadioItem
│ └── DropdownMenuRadioItem
└── DropdownMenuSub
├── DropdownMenuSubTrigger
└── DropdownMenuSubContent
└── DropdownMenuGroup
├── DropdownMenuLabel
├── DropdownMenuItem
└── DropdownMenuItem
```
## Basic
A basic dropdown menu with labels and separators.
<ComponentPreview styleName="base-nova" name="dropdown-menu-basic" />
## Submenu
Use `DropdownMenuSub` to nest secondary actions.
<ComponentPreview styleName="base-nova" name="dropdown-menu-submenu" />
## Shortcuts
Add `DropdownMenuShortcut` to show keyboard hints.
<ComponentPreview styleName="base-nova" name="dropdown-menu-shortcuts" />
## Icons
Combine icons with labels for quick scanning.
<ComponentPreview styleName="base-nova" name="dropdown-menu-icons" />
## Checkboxes
Use `DropdownMenuCheckboxItem` for toggles.
<ComponentPreview styleName="base-nova" name="dropdown-menu-checkboxes" />
## Checkboxes Icons
Add icons to checkbox items.
<ComponentPreview styleName="base-nova" name="dropdown-menu-checkboxes-icons" />
## Radio Group
Use `DropdownMenuRadioGroup` for exclusive choices.
<ComponentPreview styleName="base-nova" name="dropdown-menu-radio-group" />
## Radio Icons
Show radio options with icons.
<ComponentPreview styleName="base-nova" name="dropdown-menu-radio-icons" />
## Destructive
Use `variant="destructive"` for irreversible actions.
<ComponentPreview styleName="base-nova" name="dropdown-menu-destructive" />
## Avatar
An account switcher dropdown triggered by an avatar.
<ComponentPreview styleName="base-nova" name="dropdown-menu-avatar" />
## Complex
A richer example combining groups, icons, and submenus.
<ComponentPreview styleName="base-nova" name="dropdown-menu-complex" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="dropdown-menu-rtl"
direction="rtl"
/>
## API Reference
See the [Base UI documentation](https://base-ui.com/react/components/menu) for the full API reference.

View File

@@ -0,0 +1,240 @@
---
title: Empty
description: Use the Empty component to display an empty state.
base: base
component: true
---
<ComponentPreview
styleName="base-nova"
name="empty-demo"
previewClassName="h-96 p-0"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add empty
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="empty"
title="components/ui/empty.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@/components/ui/empty"
```
```tsx
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<Icon />
</EmptyMedia>
<EmptyTitle>No data</EmptyTitle>
<EmptyDescription>No data found</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button>Add data</Button>
</EmptyContent>
</Empty>
```
## Composition
Use the following composition to build an `Empty` state:
```text
Empty
├── EmptyHeader
│ ├── EmptyMedia
│ ├── EmptyTitle
│ └── EmptyDescription
└── EmptyContent
```
## Outline
Use the `border` utility class to create an outline empty state.
<ComponentPreview
styleName="base-nova"
name="empty-outline"
previewClassName="h-96 p-6 md:p-10"
/>
## Background
Use the `bg-*` and `bg-gradient-*` utilities to add a background to the empty state.
<ComponentPreview
styleName="base-nova"
name="empty-background"
previewClassName="h-96 p-0"
/>
## Avatar
Use the `EmptyMedia` component to display an avatar in the empty state.
<ComponentPreview
styleName="base-nova"
name="empty-avatar"
previewClassName="h-96 p-0"
/>
## Avatar Group
Use the `EmptyMedia` component to display an avatar group in the empty state.
<ComponentPreview
styleName="base-nova"
name="empty-avatar-group"
previewClassName="h-96 p-0"
/>
## InputGroup
You can add an `InputGroup` component to the `EmptyContent` component.
<ComponentPreview
styleName="base-nova"
name="empty-input-group"
previewClassName="h-96 p-0"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="empty-rtl" direction="rtl" />
## API Reference
### Empty
The main component of the empty state. Wraps the `EmptyHeader` and `EmptyContent` components.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<Empty>
<EmptyHeader />
<EmptyContent />
</Empty>
```
### EmptyHeader
The `EmptyHeader` component wraps the empty media, title, and description.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<EmptyHeader>
<EmptyMedia />
<EmptyTitle />
<EmptyDescription />
</EmptyHeader>
```
### EmptyMedia
Use the `EmptyMedia` component to display the media of the empty state such as an icon or an image. You can also use it to display other components such as an avatar.
| Prop | Type | Default |
| ----------- | --------------------- | --------- |
| `variant` | `"default" \| "icon"` | `default` |
| `className` | `string` | |
```tsx
<EmptyMedia variant="icon">
<Icon />
</EmptyMedia>
```
```tsx
<EmptyMedia>
<Avatar>
<AvatarImage src="..." />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</EmptyMedia>
```
### EmptyTitle
Use the `EmptyTitle` component to display the title of the empty state.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<EmptyTitle>No data</EmptyTitle>
```
### EmptyDescription
Use the `EmptyDescription` component to display the description of the empty state.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<EmptyDescription>You do not have any notifications.</EmptyDescription>
```
### EmptyContent
Use the `EmptyContent` component to display the content of the empty state such as a button, input or a link.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<EmptyContent>
<Button>Add Project</Button>
</EmptyContent>
```

View File

@@ -0,0 +1,404 @@
---
title: Field
description: Combine labels, controls, and help text to compose accessible form fields and grouped inputs.
base: base
component: true
---
<ComponentPreview
styleName="base-nova"
name="field-demo"
previewClassName="h-[800px] p-6 md:h-[850px]"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add field
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="field"
title="components/ui/field.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Field,
FieldContent,
FieldDescription,
FieldError,
FieldGroup,
FieldLabel,
FieldLegend,
FieldSeparator,
FieldSet,
FieldTitle,
} from "@/components/ui/field"
```
```tsx showLineNumbers
<FieldSet>
<FieldLegend>Profile</FieldLegend>
<FieldDescription>This appears on invoices and emails.</FieldDescription>
<FieldGroup>
<Field>
<FieldLabel htmlFor="name">Full name</FieldLabel>
<Input id="name" autoComplete="off" placeholder="Evil Rabbit" />
<FieldDescription>This appears on invoices and emails.</FieldDescription>
</Field>
<Field>
<FieldLabel htmlFor="username">Username</FieldLabel>
<Input id="username" autoComplete="off" aria-invalid />
<FieldError>Choose another username.</FieldError>
</Field>
<Field orientation="horizontal">
<Switch id="newsletter" />
<FieldLabel htmlFor="newsletter">Subscribe to the newsletter</FieldLabel>
</Field>
</FieldGroup>
</FieldSet>
```
## Composition
### Field
A single control with label, helper text, and validation.
```text
Field
├── FieldLabel
├── Input / Textarea / Switch / Select
├── FieldDescription
└── FieldError
```
### FieldGroup
Related fields in one group. Use `FieldSeparator` between sections when needed.
```text
FieldGroup
├── Field
│ ├── FieldLabel
│ ├── Input / Textarea / Switch / Select
│ ├── FieldDescription
│ └── FieldError
├── FieldSeparator
└── Field
├── FieldLabel
└── Input / Textarea / Switch / Select
```
### FieldSet
Semantic grouping with a legend and description, usually containing a `FieldGroup`.
```text
FieldSet
├── FieldLegend
├── FieldDescription
└── FieldGroup
├── Field
│ ├── FieldLabel
│ ├── Input / Textarea / Switch / Select
│ ├── FieldDescription
│ └── FieldError
└── Field
├── FieldLabel
└── Input / Textarea / Switch / Select
```
## Anatomy
The `Field` family is designed for composing accessible forms. A typical field is structured as follows:
```tsx showLineNumbers
<Field>
<FieldLabel htmlFor="input-id">Label</FieldLabel>
{/* Input, Select, Switch, etc. */}
<FieldDescription>Optional helper text.</FieldDescription>
<FieldError>Validation message.</FieldError>
</Field>
```
- `Field` is the core wrapper for a single field.
- `FieldContent` is a flex column that groups label and description. Not required if you have no description.
- Wrap related fields with `FieldGroup`, and use `FieldSet` with `FieldLegend` for semantic grouping.
## Form
See the [Form](/docs/forms) documentation for building forms with the `Field` component and [React Hook Form](/docs/forms/react-hook-form), [Tanstack Form](/docs/forms/tanstack-form), or [Formisch](/docs/forms/formisch).
## Input
<ComponentPreview styleName="base-nova" name="field-input" />
## Textarea
<ComponentPreview styleName="base-nova" name="field-textarea" />
## Select
<ComponentPreview styleName="base-nova" name="field-select" />
## Slider
<ComponentPreview styleName="base-nova" name="field-slider" />
## Fieldset
<ComponentPreview styleName="base-nova" name="field-fieldset" />
## Checkbox
<ComponentPreview
styleName="base-nova"
name="field-checkbox"
previewClassName="h-[32rem]"
/>
## Radio
<ComponentPreview styleName="base-nova" name="field-radio" />
## Switch
<ComponentPreview styleName="base-nova" name="field-switch" />
## Choice Card
Wrap `Field` components inside `FieldLabel` to create selectable field groups. This works with `RadioItem`, `Checkbox` and `Switch` components.
<ComponentPreview styleName="base-nova" name="field-choice-card" />
## Field Group
Stack `Field` components with `FieldGroup`. Add `FieldSeparator` to divide them.
<ComponentPreview
styleName="base-nova"
name="field-group"
previewClassName="h-96"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="field-rtl"
direction="rtl"
previewClassName="h-auto p-6"
/>
## Responsive Layout
- **Vertical fields:** Default orientation stacks label, control, and helper text—ideal for mobile-first layouts.
- **Horizontal fields:** Set `orientation="horizontal"` on `Field` to align the label and control side-by-side. Pair with `FieldContent` to keep descriptions aligned.
- **Responsive fields:** Set `orientation="responsive"` for automatic column layouts inside container-aware parents. Apply `@container/field-group` classes on `FieldGroup` to switch orientations at specific breakpoints.
<ComponentPreview
styleName="base-nova"
name="field-responsive"
previewClassName="h-[650px] p-6 md:h-[500px] md:p-10"
/>
## Validation and Errors
- Add `data-invalid` to `Field` to switch the entire block into an error state.
- Add `aria-invalid` on the input itself for assistive technologies.
- Render `FieldError` immediately after the control or inside `FieldContent` to keep error messages aligned with the field.
```tsx showLineNumbers /data-invalid/ /aria-invalid/
<Field data-invalid>
<FieldLabel htmlFor="email">Email</FieldLabel>
<Input id="email" type="email" aria-invalid />
<FieldError>Enter a valid email address.</FieldError>
</Field>
```
## Accessibility
- `FieldSet` and `FieldLegend` keep related controls grouped for keyboard and assistive tech users.
- `Field` outputs `role="group"` so nested controls inherit labeling from `FieldLabel` and `FieldLegend` when combined.
- Apply `FieldSeparator` sparingly to ensure screen readers encounter clear section boundaries.
## API Reference
### FieldSet
Container that renders a semantic `fieldset` with spacing presets.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldSet>
<FieldLegend>Delivery</FieldLegend>
<FieldGroup>{/* Fields */}</FieldGroup>
</FieldSet>
```
### FieldLegend
Legend element for a `FieldSet`. Switch to the `label` variant to align with label sizing.
| Prop | Type | Default |
| ----------- | --------------------- | ---------- |
| `variant` | `"legend" \| "label"` | `"legend"` |
| `className` | `string` | |
```tsx
<FieldLegend variant="label">Notification Preferences</FieldLegend>
```
The `FieldLegend` has two variants: `legend` and `label`. The `label` variant applies label sizing and alignment. Handy if you have nested `FieldSet`.
### FieldGroup
Layout wrapper that stacks `Field` components and enables container queries for responsive orientations.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldGroup className="@container/field-group flex flex-col gap-6">
<Field>{/* ... */}</Field>
<Field>{/* ... */}</Field>
</FieldGroup>
```
### Field
The core wrapper for a single field. Provides orientation control, invalid state styling, and spacing.
| Prop | Type | Default |
| -------------- | -------------------------------------------- | ------------ |
| `orientation` | `"vertical" \| "horizontal" \| "responsive"` | `"vertical"` |
| `className` | `string` | |
| `data-invalid` | `boolean` | |
```tsx
<Field orientation="horizontal">
<FieldLabel htmlFor="remember">Remember me</FieldLabel>
<Switch id="remember" />
</Field>
```
### FieldContent
Flex column that groups control and descriptions when the label sits beside the control. Not required if you have no description.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<Field>
<Checkbox id="notifications" />
<FieldContent>
<FieldLabel htmlFor="notifications">Notifications</FieldLabel>
<FieldDescription>Email, SMS, and push options.</FieldDescription>
</FieldContent>
</Field>
```
### FieldLabel
Label styled for both direct inputs and nested `Field` children.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldLabel htmlFor="email">Email</FieldLabel>
```
### FieldTitle
Renders a title with label styling inside `FieldContent`.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldContent>
<FieldTitle>Enable Touch ID</FieldTitle>
<FieldDescription>Unlock your device faster.</FieldDescription>
</FieldContent>
```
### FieldDescription
Helper text slot that automatically balances long lines in horizontal layouts.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldDescription>We never share your email with anyone.</FieldDescription>
```
### FieldSeparator
Visual divider to separate sections inside a `FieldGroup`. Accepts optional inline content.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<FieldSeparator>Or continue with</FieldSeparator>
```
### FieldError
Accessible error container that accepts children or an `errors` array (e.g., from `react-hook-form`).
| Prop | Type | Default |
| ----------- | ------------------------------------------ | ------- |
| `errors` | `Array<{ message?: string } \| undefined>` | |
| `className` | `string` | |
```tsx
<FieldError errors={errors.username} />
```
When the `errors` array contains multiple messages, the component renders a list automatically.
`FieldError` also accepts issues produced by any validator that implements [Standard Schema](https://standardschema.dev/), including Zod, Valibot, and ArkType. Pass the `issues` array from the schema result directly to render a unified error list across libraries.

View File

@@ -0,0 +1,144 @@
---
title: Hover Card
description: For sighted users to preview content available behind a link.
base: base
component: true
links:
doc: https://base-ui.com/react/components/hover-card
api: https://base-ui.com/react/components/hover-card#api-reference
---
<ComponentPreview
styleName="base-nova"
name="hover-card-demo"
previewClassName="h-80"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add hover-card
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="hover-card"
title="components/ui/hover-card.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card"
```
```tsx showLineNumbers
<HoverCard>
<HoverCardTrigger>Hover</HoverCardTrigger>
<HoverCardContent>
The React Framework – created and maintained by @vercel.
</HoverCardContent>
</HoverCard>
```
## Composition
Use the following composition to build a `HoverCard`:
```text
HoverCard
├── HoverCardTrigger
└── HoverCardContent
```
## Trigger Delays
Use `delay` and `closeDelay` on the trigger to control when the card opens and
closes.
```tsx showLineNumbers
<HoverCard>
<HoverCardTrigger delay={100} closeDelay={200}>
Hover
</HoverCardTrigger>
<HoverCardContent>Content</HoverCardContent>
</HoverCard>
```
## Positioning
Use the `side` and `align` props on `HoverCardContent` to control placement.
```tsx showLineNumbers
<HoverCard>
<HoverCardTrigger>Hover</HoverCardTrigger>
<HoverCardContent side="top" align="start">
Content
</HoverCardContent>
</HoverCard>
```
## Basic
<ComponentPreview
styleName="base-nova"
name="hover-card-demo"
previewClassName="h-80"
/>
## Sides
<ComponentPreview
styleName="base-nova"
name="hover-card-sides"
previewClassName="h-[22rem]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="hover-card-rtl"
direction="rtl"
previewClassName="h-80"
/>
## API Reference
See the [Base UI](https://base-ui.com/react/components/hover-card#api-reference) documentation for more information.

View File

@@ -0,0 +1,316 @@
---
title: Input Group
description: Add addons, buttons, and helper content to inputs.
base: base
component: true
---
import { IconInfoCircle } from "@tabler/icons-react"
<ComponentPreview
styleName="base-nova"
name="input-group-demo"
previewClassName="h-[26rem]"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add input-group
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="input-group"
title="components/ui/input-group.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
InputGroup,
InputGroupAddon,
InputGroupButton,
InputGroupInput,
InputGroupText,
InputGroupTextarea,
} from "@/components/ui/input-group"
```
```tsx showLineNumbers
<InputGroup>
<InputGroupInput placeholder="Search..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>
```
## Composition
Use the following composition to build an `InputGroup`:
```text
InputGroup
├── InputGroupInput or InputGroupTextarea
├── InputGroupAddon
├── InputGroupButton
└── InputGroupText
```
## Align
Use the `align` prop on `InputGroupAddon` to position the addon relative to the input.
<Callout>
For proper focus management, `InputGroupAddon` should always be placed after
`InputGroupInput` or `InputGroupTextarea` in the DOM. Use the `align` prop to
visually position the addon.
</Callout>
### inline-start
Use `align="inline-start"` to position the addon at the start of the input. This is the default.
<ComponentPreview
styleName="base-nova"
name="input-group-inline-start"
previewClassName="h-48"
/>
### inline-end
Use `align="inline-end"` to position the addon at the end of the input.
<ComponentPreview
styleName="base-nova"
name="input-group-inline-end"
previewClassName="h-48"
/>
### block-start
Use `align="block-start"` to position the addon above the input.
<ComponentPreview
styleName="base-nova"
name="input-group-block-start"
previewClassName="h-96"
/>
### block-end
Use `align="block-end"` to position the addon below the input.
<ComponentPreview
styleName="base-nova"
name="input-group-block-end"
previewClassName="h-[26rem]"
/>
## Icon
<ComponentPreview
styleName="base-nova"
name="input-group-icon"
previewClassName="h-80"
/>
## Text
<ComponentPreview
styleName="base-nova"
name="input-group-text"
previewClassName="h-80"
/>
## Button
<ComponentPreview
styleName="base-nova"
name="input-group-button"
previewClassName="h-72"
/>
## Kbd
<ComponentPreview
styleName="base-nova"
name="input-group-kbd"
previewClassName="h-40"
/>
## Dropdown
<ComponentPreview
styleName="base-nova"
name="input-group-dropdown"
previewClassName="h-56"
/>
## Spinner
<ComponentPreview
styleName="base-nova"
name="input-group-spinner"
previewClassName="h-80"
/>
## Textarea
<ComponentPreview
styleName="base-nova"
name="input-group-textarea"
previewClassName="h-96"
/>
## Custom Input
Add the `data-slot="input-group-control"` attribute to your custom input for automatic focus state handling.
Here's an example of a custom resizable textarea from a third-party library.
<ComponentPreview
styleName="base-nova"
name="input-group-custom"
previewClassName="h-56"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="input-group-rtl"
direction="rtl"
previewClassName="h-[30rem]"
/>
## API Reference
### InputGroup
The main component that wraps inputs and addons.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
```tsx
<InputGroup>
<InputGroupInput />
<InputGroupAddon />
</InputGroup>
```
### InputGroupAddon
Displays icons, text, buttons, or other content alongside inputs.
<Callout icon={<IconInfoCircle />} title="Focus Navigation">
For proper focus navigation, the `InputGroupAddon` component should be placed
after the input. Set the `align` prop to position the addon.
</Callout>
| Prop | Type | Default |
| ----------- | ---------------------------------------------------------------- | ---------------- |
| `align` | `"inline-start" \| "inline-end" \| "block-start" \| "block-end"` | `"inline-start"` |
| `className` | `string` | |
```tsx
<InputGroupAddon align="inline-end">
<SearchIcon />
</InputGroupAddon>
```
**For `<InputGroupInput />`, use the `inline-start` or `inline-end` alignment. For `<InputGroupTextarea />`, use the `block-start` or `block-end` alignment.**
The `InputGroupAddon` component can have multiple `InputGroupButton` components and icons.
```tsx
<InputGroupAddon>
<InputGroupButton>Button</InputGroupButton>
<InputGroupButton>Button</InputGroupButton>
</InputGroupAddon>
```
### InputGroupButton
Displays buttons within input groups.
| Prop | Type | Default |
| ----------- | ----------------------------------------------------------------------------- | --------- |
| `size` | `"xs" \| "icon-xs" \| "sm" \| "icon-sm"` | `"xs"` |
| `variant` | `"default" \| "destructive" \| "outline" \| "secondary" \| "ghost" \| "link"` | `"ghost"` |
| `className` | `string` | |
```tsx
<InputGroupButton>Button</InputGroupButton>
<InputGroupButton size="icon-xs" aria-label="Copy">
<CopyIcon />
</InputGroupButton>
```
### InputGroupInput
Replacement for `<Input />` when building input groups. This component has the input group styles pre-applied and uses the unified `data-slot="input-group-control"` for focus state handling.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
All other props are passed through to the underlying `<Input />` component.
```tsx
<InputGroup>
<InputGroupInput placeholder="Enter text..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>
```
### InputGroupTextarea
Replacement for `<Textarea />` when building input groups. This component has the textarea group styles pre-applied and uses the unified `data-slot="input-group-control"` for focus state handling.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | |
All other props are passed through to the underlying `<Textarea />` component.
```tsx
<InputGroup>
<InputGroupTextarea placeholder="Enter message..." />
<InputGroupAddon align="block-end">
<InputGroupButton>Send</InputGroupButton>
</InputGroupAddon>
</InputGroup>
```

View File

@@ -0,0 +1,172 @@
---
title: Input OTP
description: Accessible one-time password component with copy-paste functionality.
base: base
component: true
links:
doc: https://input-otp.rodz.dev
---
<ComponentPreview styleName="base-nova" name="input-otp-demo" />
## About
Input OTP is built on top of [input-otp](https://github.com/guilhermerodz/input-otp) by [@guilherme_rodz](https://twitter.com/guilherme_rodz).
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add input-otp
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install input-otp
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="input-otp"
title="components/ui/input-otp.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
InputOTP,
InputOTPGroup,
InputOTPSeparator,
InputOTPSlot,
} from "@/components/ui/input-otp"
```
```tsx showLineNumbers
<InputOTP maxLength={6}>
<InputOTPGroup>
<InputOTPSlot index={0} />
<InputOTPSlot index={1} />
<InputOTPSlot index={2} />
</InputOTPGroup>
<InputOTPSeparator />
<InputOTPGroup>
<InputOTPSlot index={3} />
<InputOTPSlot index={4} />
<InputOTPSlot index={5} />
</InputOTPGroup>
</InputOTP>
```
## Composition
Use the following composition to build an `InputOTP`:
```text
InputOTP
├── InputOTPGroup
│ ├── InputOTPSlot
│ ├── InputOTPSlot
│ └── InputOTPSlot
├── InputOTPSeparator
├── InputOTPGroup
│ ├── InputOTPSlot
│ ├── InputOTPSlot
│ └── InputOTPSlot
├── InputOTPSeparator
└── InputOTPGroup
├── InputOTPSlot
└── InputOTPSlot
```
## Pattern
Use the `pattern` prop to define a custom pattern for the OTP input.
```tsx showLineNumbers {1,5}
import { REGEXP_ONLY_DIGITS_AND_CHARS } from "input-otp"
;<InputOTP maxLength={6} pattern={REGEXP_ONLY_DIGITS_AND_CHARS}>
...
</InputOTP>
```
<ComponentPreview styleName="base-nova" name="input-otp-pattern" />
## Separator
Use the `<InputOTPSeparator />` component to add a separator between input groups.
<ComponentPreview styleName="base-nova" name="input-otp-separator" />
## Disabled
Use the `disabled` prop to disable the input.
<ComponentPreview styleName="base-nova" name="input-otp-disabled" />
## Controlled
Use the `value` and `onChange` props to control the input value.
<ComponentPreview styleName="base-nova" name="input-otp-controlled" />
## Invalid
Use `aria-invalid` on the slots to show an error state.
<ComponentPreview styleName="base-nova" name="input-otp-invalid" />
## Four Digits
A common pattern for PIN codes. This uses the `pattern={REGEXP_ONLY_DIGITS}` prop.
<ComponentPreview styleName="base-nova" name="input-otp-four-digits" />
## Alphanumeric
Use `REGEXP_ONLY_DIGITS_AND_CHARS` to accept both letters and numbers.
<ComponentPreview styleName="base-nova" name="input-otp-alphanumeric" />
## Form
<ComponentPreview
styleName="base-nova"
name="input-otp-form"
previewClassName="h-[30rem]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="input-otp-rtl" direction="rtl" />
## API Reference
See the [input-otp](https://input-otp.rodz.dev) documentation for more information.

View File

@@ -0,0 +1,199 @@
---
title: Input
description: A text input component for forms and user data entry with built-in styling and accessibility features.
base: base
component: true
---
<ComponentPreview
styleName="base-nova"
name="input-demo"
previewClassName="*:max-w-xs"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add input
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="input"
title="components/ui/input.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Input } from "@/components/ui/input"
```
```tsx
<Input />
```
## Basic
<ComponentPreview
styleName="base-nova"
name="input-basic"
previewClassName="*:max-w-xs"
/>
## Field
Use `Field`, `FieldLabel`, and `FieldDescription` to create an input with a
label and description.
<ComponentPreview
styleName="base-nova"
name="input-field"
previewClassName="*:max-w-xs"
/>
## Field Group
Use `FieldGroup` to show multiple `Field` blocks and to build forms.
<ComponentPreview
styleName="base-nova"
name="input-fieldgroup"
previewClassName="*:max-w-xs"
/>
## Disabled
Use the `disabled` prop to disable the input. To style the disabled state, add the `data-disabled` attribute to the `Field` component.
<ComponentPreview
styleName="base-nova"
name="input-disabled"
previewClassName="*:max-w-xs"
/>
## Invalid
Use the `aria-invalid` prop to mark the input as invalid. To style the invalid state, add the `data-invalid` attribute to the `Field` component.
<ComponentPreview
styleName="base-nova"
name="input-invalid"
previewClassName="*:max-w-xs"
/>
## File
Use the `type="file"` prop to create a file input.
<ComponentPreview
styleName="base-nova"
name="input-file"
previewClassName="*:max-w-xs"
/>
## Inline
Use `Field` with `orientation="horizontal"` to create an inline input.
Pair with `Button` to create a search input with a button.
<ComponentPreview
styleName="base-nova"
name="input-inline"
previewClassName="*:max-w-xs"
/>
## Grid
Use a grid layout to place multiple inputs side by side.
<ComponentPreview
styleName="base-nova"
name="input-grid"
previewClassName="p-6"
/>
## Required
Use the `required` attribute to indicate required inputs.
<ComponentPreview
styleName="base-nova"
name="input-required"
previewClassName="*:max-w-xs"
/>
## Badge
Use `Badge` in the label to highlight a recommended field.
<ComponentPreview
styleName="base-nova"
name="input-badge"
previewClassName="*:max-w-xs"
/>
## Input Group
To add icons, text, or buttons inside an input, use the `InputGroup` component. See the [Input Group](/docs/components/input-group) component for more examples.
<ComponentPreview
styleName="base-nova"
name="input-input-group"
previewClassName="*:max-w-xs"
/>
## Button Group
To add buttons to an input, use the `ButtonGroup` component. See the [Button Group](/docs/components/button-group) component for more examples.
<ComponentPreview
styleName="base-nova"
name="input-button-group"
previewClassName="*:max-w-xs"
/>
## Form
A full form example with multiple inputs, a select, and a button.
<ComponentPreview
styleName="base-nova"
name="input-form"
previewClassName="h-[32rem]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="input-rtl"
direction="rtl"
previewClassName="*:max-w-xs"
/>

View File

@@ -0,0 +1,296 @@
---
title: Item
description: A versatile component for displaying content with media, title, description, and actions.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="item-demo" />
The `Item` component is a straightforward flex container that can house nearly any type of content. Use it to display a title, description, and actions. Group it with the `ItemGroup` component to create a list of items.
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add item
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="item"
title="components/ui/item.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Item,
ItemActions,
ItemContent,
ItemDescription,
ItemMedia,
ItemTitle,
} from "@/components/ui/item"
```
```tsx showLineNumbers
<Item>
<ItemMedia variant="icon">
<Icon />
</ItemMedia>
<ItemContent>
<ItemTitle>Title</ItemTitle>
<ItemDescription>Description</ItemDescription>
</ItemContent>
<ItemActions>
<Button>Action</Button>
</ItemActions>
</Item>
```
## Composition
Use the following composition to build an `Item`:
```text
ItemGroup
└── Item
├── ItemHeader
├── ItemMedia
├── ItemContent
│ ├── ItemTitle
│ └── ItemDescription
├── ItemActions
└── ItemFooter
```
## Item vs Field
Use `Field` if you need to display a form input such as a checkbox, input, radio, or select.
If you only need to display content such as a title, description, and actions, use `Item`.
## Variant
Use the `variant` prop to change the visual style of the item.
<ComponentPreview
styleName="base-nova"
name="item-variant"
previewClassName="h-96"
/>
## Size
Use the `size` prop to change the size of the item. Available sizes are `default`, `sm`, and `xs`.
<ComponentPreview
styleName="base-nova"
name="item-size"
previewClassName="h-96"
/>
## Icon
Use `ItemMedia` with `variant="icon"` to display an icon.
<ComponentPreview styleName="base-nova" name="item-icon" />
## Avatar
You can use `ItemMedia` with `variant="avatar"` to display an avatar.
<ComponentPreview styleName="base-nova" name="item-avatar" />
## Image
Use `ItemMedia` with `variant="image"` to display an image.
<ComponentPreview styleName="base-nova" name="item-image" />
## Group
Use `ItemGroup` to group related items together.
<ComponentPreview
styleName="base-nova"
name="item-group"
previewClassName="h-96"
/>
## Header
Use `ItemHeader` to add a header above the item content.
<ComponentPreview
styleName="base-nova"
name="item-header"
previewClassName="h-96"
/>
## Link
Use the `render` prop to render the item as a link. The hover and focus states will be applied to the anchor element.
<ComponentPreview styleName="base-nova" name="item-link" />
```tsx showLineNumbers
<Item render={<a href="/dashboard" />}>
<ItemMedia variant="icon">
<HomeIcon />
</ItemMedia>
<ItemContent>
<ItemTitle>Dashboard</ItemTitle>
<ItemDescription>Overview of your account and activity.</ItemDescription>
</ItemContent>
</Item>
```
## Dropdown
<ComponentPreview styleName="base-nova" name="item-dropdown" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="item-rtl" direction="rtl" />
## API Reference
### Item
The main component for displaying content with media, title, description, and actions.
| Prop | Type | Default |
| --------- | ----------------------------------- | ----------- |
| `variant` | `"default" \| "outline" \| "muted"` | `"default"` |
| `size` | `"default" \| "sm" \| "xs"` | `"default"` |
| `render` | `React.ReactElement` | |
### ItemGroup
A container that groups related items together with consistent styling.
```tsx
<ItemGroup>
<Item />
<Item />
</ItemGroup>
```
### ItemSeparator
A separator between items in a group.
```tsx
<ItemGroup>
<Item />
<ItemSeparator />
<Item />
</ItemGroup>
```
### ItemMedia
Use `ItemMedia` to display media content such as icons, images, or avatars.
| Prop | Type | Default |
| --------- | -------------------------------- | ----------- |
| `variant` | `"default" \| "icon" \| "image"` | `"default"` |
```tsx
<ItemMedia variant="icon">
<Icon />
</ItemMedia>
```
```tsx
<ItemMedia variant="image">
<img src="..." alt="..." />
</ItemMedia>
```
### ItemContent
Wraps the title and description of the item.
```tsx
<ItemContent>
<ItemTitle>Title</ItemTitle>
<ItemDescription>Description</ItemDescription>
</ItemContent>
```
### ItemTitle
Displays the title of the item.
```tsx
<ItemTitle>Item Title</ItemTitle>
```
### ItemDescription
Displays the description of the item.
```tsx
<ItemDescription>Item description</ItemDescription>
```
### ItemActions
Container for action buttons or other interactive elements.
```tsx
<ItemActions>
<Button>Action</Button>
</ItemActions>
```
### ItemHeader
Displays a header above the item content.
```tsx
<Item>
<ItemHeader>Header</ItemHeader>
<ItemContent>...</ItemContent>
</Item>
```
### ItemFooter
Displays a footer below the item content.
```tsx
<Item>
<ItemContent>...</ItemContent>
<ItemFooter>Footer</ItemFooter>
</Item>
```

View File

@@ -0,0 +1,124 @@
---
title: Kbd
description: Used to display textual user input from keyboard.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="kbd-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add kbd
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="kbd"
title="components/ui/kbd.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Kbd } from "@/components/ui/kbd"
```
```tsx
<Kbd>Ctrl</Kbd>
```
## Composition
Use the following composition to build `Kbd` and `KbdGroup`:
```text
Kbd
KbdGroup
├── Kbd
└── Kbd
```
## Group
Use the `KbdGroup` component to group keyboard keys together.
<ComponentPreview styleName="base-nova" name="kbd-group" />
## Button
Use the `Kbd` component inside a `Button` component to display a keyboard key inside a button.
<ComponentPreview styleName="base-nova" name="kbd-button" />
## Tooltip
You can use the `Kbd` component inside a `Tooltip` component to display a tooltip with a keyboard key.
<ComponentPreview styleName="base-nova" name="kbd-tooltip" />
## Input Group
You can use the `Kbd` component inside a `InputGroupAddon` component to display a keyboard key inside an input group.
<ComponentPreview styleName="base-nova" name="kbd-input-group" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="kbd-rtl" direction="rtl" />
## API Reference
### Kbd
Use the `Kbd` component to display a keyboard key.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | `` |
```tsx
<Kbd>Ctrl</Kbd>
```
### KbdGroup
Use the `KbdGroup` component to group `Kbd` components together.
| Prop | Type | Default |
| ----------- | -------- | ------- |
| `className` | `string` | `` |
```tsx
<KbdGroup>
<Kbd>Ctrl</Kbd>
<Kbd>B</Kbd>
</KbdGroup>
```

View File

@@ -0,0 +1,96 @@
---
title: Label
description: Renders an accessible label associated with controls.
base: base
component: true
links:
doc: https://base-ui.com/react/components/label
api: https://base-ui.com/react/components/label#api-reference
---
<ComponentPreview styleName="base-nova" name="label-demo" />
<Callout>
For form fields, use the [Field](/docs/components/base/field) component which
includes built-in label, description, and error handling.
</Callout>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add label
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="label"
title="components/ui/label.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Label } from "@/components/ui/label"
```
```tsx
<Label htmlFor="email">Your email address</Label>
```
## Label in Field
For form fields, use the [Field](/docs/components/base/field) component which
includes built-in `FieldLabel`, `FieldDescription`, and `FieldError` components.
```tsx
<Field>
<FieldLabel htmlFor="email">Your email address</FieldLabel>
<Input id="email" />
</Field>
```
<ComponentPreview
styleName="base-nova"
name="field-demo"
previewClassName="h-[44rem]"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="label-rtl" direction="rtl" />
## API Reference
See the [Base UI Label](https://base-ui.com/react/components/label#api-reference) documentation for more information.

View File

@@ -0,0 +1,271 @@
---
title: Marker
description: Displays an inline status, system note, bordered row, or labeled separator in a conversation.
base: base
component: true
---
<ComponentPreview
styleName="base-rhea"
name="marker-demo"
previewClassName="h-auto theme-blue"
/>
The `Marker` component displays inline conversation markers such as status updates, system notes, bordered rows, and labeled separators. Compose it with [`Message`](/docs/components/message) in a conversation thread.
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add marker
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="marker"
title="components/ui/marker.tsx"
styleName="base-rhea"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Marker, MarkerContent, MarkerIcon } from "@/components/ui/marker"
```
```tsx showLineNumbers
<Marker>
<MarkerIcon>
<CheckIcon />
</MarkerIcon>
<MarkerContent>Explored 4 files</MarkerContent>
</Marker>
```
## Composition
Use the following composition to build a marker:
```text
Marker
├── MarkerIcon
└── MarkerContent
```
## Features
- Inline marker, bordered row, and labeled separator variants
- Decorative icon slot that is hidden from assistive tech
- Polymorphic root via `render` for link and button markers
- Pairs with the [`shimmer`](/docs/utils/shimmer) utility for streaming status text
- Customizable styling through the `className` prop on every part
## Variants
Use `variant` to switch between an inline marker, bordered row, and labeled separator.
<ComponentPreview
styleName="base-rhea"
name="marker-variants"
previewClassName="h-auto theme-blue"
/>
| Variant | Description |
| ----------- | ---------------------------------------------------- |
| `default` | An inline marker for status, notes, and actions. |
| `border` | A default marker with a bottom border under the row. |
| `separator` | A centered label with divider lines on each side. |
## Status
Set `role="status"` and include a [`Spinner`](/docs/components/spinner) for streaming or in-progress markers so updates are announced.
<ComponentPreview
styleName="base-rhea"
name="marker-status"
previewClassName="h-auto theme-blue"
/>
## Shimmer
Add the [`shimmer`](/docs/utils/shimmer) utility class to `MarkerContent` for an animated streaming-text effect. The utility ships with the `shadcn` package — see the shimmer docs for installation.
<ComponentPreview
styleName="base-rhea"
name="marker-shimmer"
previewClassName="h-auto theme-blue"
/>
## Separator
Use the `separator` variant for labeled dividers, such as dates or section breaks, in a conversation.
<ComponentPreview
styleName="base-rhea"
name="marker-separator"
previewClassName="h-auto theme-blue"
/>
## Border
Use the `border` variant for status rows that should keep the default marker alignment while separating the next row.
<ComponentPreview
styleName="base-rhea"
name="marker-border"
previewClassName="h-auto theme-blue"
/>
## With Icon
Use `MarkerIcon` to render an icon alongside the content. Use `flex-col` to stack the icon above the content.
<ComponentPreview
styleName="base-rhea"
name="marker-icon"
previewClassName="h-auto theme-blue"
/>
## Links and Buttons
Turn a marker into a link or button with the `render` prop on `Marker`.
<ComponentPreview
styleName="base-rhea"
name="marker-link-button"
previewClassName="h-auto theme-blue"
/>
```tsx showLineNumbers
import { Marker, MarkerContent } from "@/components/ui/marker"
export function MarkerLinkDemo() {
return (
<Marker render={<a href="#" />}>
<MarkerContent>View the pull request</MarkerContent>
</Marker>
)
}
```
## Accessibility
`Marker` is presentational by default. The correct semantics depend on how you use it, so choose the role based on intent rather than relying on a single default.
### Status and Progress
For streaming or progress markers such as "Thinking..." or a running tool, set `role="status"` so assistive tech announces the update as it appears. `Marker` forwards `role` to the underlying element.
```tsx showLineNumbers
<Marker role="status">
<MarkerIcon>
<Spinner />
</MarkerIcon>
<MarkerContent>Compacting conversation</MarkerContent>
</Marker>
```
### Labeled Separators
A separator that carries text, such as a date or a section label, needs no role. The divider lines are decorative CSS pseudo-elements, and the text is announced as ordinary content.
```tsx showLineNumbers
<Marker variant="separator">
<MarkerContent>Today</MarkerContent>
</Marker>
```
<Callout>
**Note:** Do not add `role="separator"` to a labeled divider. A separator
takes its accessible name from `aria-label`, not from its text, and its
contents are treated as presentational, so the visible label would not be
announced. Reserve `role="separator"` for a divider with no meaningful text.
</Callout>
### Bordered Markers
A bordered marker keeps the same semantics as the default marker. The bottom border is decorative, so choose `role="status"`, `render`, or no role based on the marker's purpose.
```tsx showLineNumbers
<Marker variant="border">
<MarkerIcon>
<FileTextIcon />
</MarkerIcon>
<MarkerContent>Opened implementation notes</MarkerContent>
</Marker>
```
### Decorative Icons
`MarkerIcon` is decorative and hidden from assistive tech with `aria-hidden`, so the adjacent `MarkerContent` carries the meaning. For an icon-only marker, provide an `aria-label` or visible text so it is not announced as empty.
```tsx showLineNumbers
<Marker aria-label="Synced">
<MarkerIcon>
<CheckIcon />
</MarkerIcon>
</Marker>
```
### Interactive Markers
When a marker links or triggers an action, render it as a real `<button>` or `<a>` with the `render` prop so it is focusable and exposes the correct role. The accessible name comes from the marker text.
```tsx showLineNumbers
<Marker render={<a href="/files" />}>
<MarkerIcon>
<FileTextIcon />
</MarkerIcon>
<MarkerContent>Explored 4 files</MarkerContent>
</Marker>
```
## API Reference
### Marker
The root marker element. The file also exports `markerVariants` for composing the marker styles into custom components.
| Prop | Type | Default | Description |
| ----------- | -------------------------------------- | ----------- | ------------------------------------------------ |
| `variant` | `"default" \| "border" \| "separator"` | `"default"` | The marker layout. |
| `render` | `ReactElement \| function` | - | Render as a different element, such as a link. |
| `className` | `string` | - | Additional classes to apply to the root element. |
### MarkerIcon
A decorative icon slot. Hidden from assistive tech with `aria-hidden`.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | --------------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the icon slot. |
### MarkerContent
The marker text content.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ------------------------------------------------ |
| `className` | `string` | - | Additional classes to apply to the content slot. |

View File

@@ -0,0 +1,161 @@
---
title: Menubar
description: A visually persistent menu common in desktop applications that provides quick access to a consistent set of commands.
base: base
component: true
links:
doc: https://base-ui.com/react/components/menubar
api: https://base-ui.com/react/components/menubar#api-reference
---
<ComponentPreview styleName="base-nova" name="menubar-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add menubar
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="menubar"
title="components/ui/menubar.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Menubar,
MenubarContent,
MenubarGroup,
MenubarItem,
MenubarMenu,
MenubarSeparator,
MenubarShortcut,
MenubarTrigger,
} from "@/components/ui/menubar"
```
```tsx showLineNumbers
<Menubar>
<MenubarMenu>
<MenubarTrigger>File</MenubarTrigger>
<MenubarContent>
<MenubarGroup>
<MenubarItem>
New Tab <MenubarShortcut>⌘T</MenubarShortcut>
</MenubarItem>
<MenubarItem>New Window</MenubarItem>
</MenubarGroup>
<MenubarSeparator />
<MenubarGroup>
<MenubarItem>Share</MenubarItem>
<MenubarItem>Print</MenubarItem>
</MenubarGroup>
</MenubarContent>
</MenubarMenu>
</Menubar>
```
## Composition
Use the following composition to build a `Menubar`:
```text
Menubar
├── MenubarMenu
│ ├── MenubarTrigger
│ └── MenubarContent
│ ├── MenubarGroup
│ │ ├── MenubarLabel
│ │ ├── MenubarItem
│ │ └── MenubarItem
│ ├── MenubarSeparator
│ ├── MenubarGroup
│ │ ├── MenubarLabel
│ │ ├── MenubarCheckboxItem
│ │ └── MenubarCheckboxItem
│ ├── MenubarSeparator
│ ├── MenubarGroup
│ │ ├── MenubarLabel
│ │ └── MenubarRadioGroup
│ │ ├── MenubarRadioItem
│ │ └── MenubarRadioItem
│ └── MenubarSub
│ ├── MenubarSubTrigger
│ └── MenubarSubContent
│ └── MenubarGroup
│ ├── MenubarLabel
│ ├── MenubarItem
│ └── MenubarItem
└── MenubarMenu
├── MenubarTrigger
└── MenubarContent
└── MenubarGroup
├── MenubarLabel
├── MenubarItem
└── MenubarItem
```
## Checkbox
Use `MenubarCheckboxItem` for toggleable options.
<ComponentPreview styleName="base-nova" name="menubar-checkbox" />
## Radio
Use `MenubarRadioGroup` and `MenubarRadioItem` for single-select options.
<ComponentPreview styleName="base-nova" name="menubar-radio" />
## Submenu
Use `MenubarSub`, `MenubarSubTrigger`, and `MenubarSubContent` for nested menus.
<ComponentPreview styleName="base-nova" name="menubar-submenu" />
## With Icons
<ComponentPreview styleName="base-nova" name="menubar-icons" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="menubar-rtl" direction="rtl" />
## API Reference
See the [Base UI Menubar](https://base-ui.com/react/components/menubar#api-reference) documentation.

View File

@@ -0,0 +1,632 @@
---
title: Message Scroller
description: A chat scroll container that anchors turns, opens saved transcripts, follows streamed responses, loads history without jumping, and jumps to any message.
base: base
component: true
---
<ComponentPreview
styleName="base-rhea"
name="message-scroller-demo"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
## What Makes a Great Streaming Chat Experience
Building a chat interface used to be simple. You create an inverted list with
an input. Type a message, it appends at the bottom. When a reply comes in, the
list grows and scrolls. Done.
Streaming breaks that model. Messages arrive in chunks while you may still be
reading, scrolling, or looking somewhere else entirely.
Now the challenge is preserving the reader's place while the conversation keeps
changing. Get that wrong and the experience feels jumpy: people are pulled to
the bottom, lose context, and have to find their way back.
In practice, this comes down to scroll: when to follow, when to hold, and when
to let the reader decide. A great streaming chat should:
1. **Move only when the reader asked to move.** If someone is reading, don’t pull them somewhere else. Auto-scroll should never be the default.
2. **Follow only while they’re following.** If they’re at the live edge, keep the stream in view. If they scroll away, leave them there.
3. **Every interaction is a signal.** Scrolling is not the only one. Selecting text, using the keyboard, opening a link, or searching should all stop the interface from moving.
4. **Start a new turn near the top of the viewport.** This gives the new turn somewhere it can be read from the beginning.
5. **Then stream in the answer.** The answer should grow into the screen, not immediately push everything away.
6. **Keep part of the previous conversation in context.** The prompt and reply should stay visually connected, and enough of the previous turn should remain visible so the reader knows where they are.
7. **Let new content arrive offscreen.** The conversation can keep streaming without changing what the reader is looking at.
8. **Show what’s happening out of view.** Make it clear when a response is still streaming or when new messages have arrived.
9. **Make it easy to return to the latest reply.** A “Jump to latest” action should bring the reader back and resume following.
10. **Let people jump anywhere in the conversation.** Long threads need message links, search, unread markers, and direct navigation.
11. **Reopen where the reader left off.** A saved conversation should open at the last meaningful turn. Often this is the last user message. Not the absolute bottom.
12. **Keep the reader’s place when layout changes.** Images load. Markdown expands. Code blocks render. Older messages appear above. None of that should make the reader lose their place.
13. **Handle interruptions without stealing position.** Stopping, retrying, regenerating, branching, or errors should not unexpectedly move the conversation.
14. **Stay responsive in long threads.** Streaming text, markdown, code, images, and long history should still feel responsive.
15. **Be accessible without the noise.** Keep the transcript navigable, preserve keyboard focus, and announce important events at a comfortable pace.
**Never move the reader against their intent.**
## MessageScroller
MessageScroller is a chat transcript scroller built for these behaviors.
`MessageScrollerProvider` owns the scroll state and transcript-row behavior:
opening position, streamed output, new-turn anchoring, prepended history,
visibility, and scroll controls. `MessageScroller` is the styled frame that
renders inside it.
MessageScroller is scoped to the scroll viewport. It does not own messages, AI state,
transport, persistence, branching, or model state. Your product code stays
focused on composing messages, markers, tools, attachments, and prompt inputs.
It gives you the scroll behavior that chat needs, without taking over the rest
of the chat UI. And it stays fast, even in long conversations with rich
markdown.
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add message-scroller
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @shadcn/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="message-scroller"
title="components/ui/message-scroller.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Message } from "@/components/ui/message"
import {
MessageScroller,
MessageScrollerButton,
MessageScrollerContent,
MessageScrollerItem,
MessageScrollerProvider,
MessageScrollerViewport,
} from "@/components/ui/message-scroller"
```
```tsx
<MessageScrollerProvider>
<MessageScroller>
<MessageScrollerViewport>
<MessageScrollerContent>
{messages.map((message) => (
<MessageScrollerItem
key={message.id}
messageId={message.id}
scrollAnchor={message.role === "user"}
>
<Message />
</MessageScrollerItem>
))}
</MessageScrollerContent>
</MessageScrollerViewport>
<MessageScrollerButton />
</MessageScroller>
</MessageScrollerProvider>
```
`MessageScroller` fills its parent, so place it inside a height-constrained
container.
```tsx
<div className="flex h-screen flex-col">
<MessageScrollerProvider>
<MessageScroller className="flex-1">{/* transcript */}</MessageScroller>
</MessageScrollerProvider>
</div>
```
## Composition
```tsx
<MessageScrollerProvider>
<MessageScroller>
<MessageScrollerViewport>
<MessageScrollerContent>
<MessageScrollerItem>
{/* a message, marker, or row */}
</MessageScrollerItem>
<MessageScrollerItem />
<MessageScrollerItem />
</MessageScrollerContent>
</MessageScrollerViewport>
<MessageScrollerButton />
</MessageScroller>
</MessageScrollerProvider>
```
- **`MessageScrollerProvider`** — the headless root. Owns scroll state and the
behavior props for opening position, auto-scroll, anchoring, scroll commands,
and visibility tracking.
- **`MessageScroller`** — the styled frame. Lays out the viewport, content, and
controls inside the provider.
- **`MessageScrollerViewport`** — the scrollable element. Receives native scroll
events and preserves the visible row when older messages are prepended.
- **`MessageScrollerContent`** — the transcript container. Holds the rows and
provides the live-region defaults for new messages.
- **`MessageScrollerItem`** — the transcript row boundary. Wrap every direct
child of the content so the scroller can measure, anchor, preserve position,
track visibility, and jump to it. An item can be a message, marker, typing
indicator, separator, join/leave event, or "load earlier" row.
- **`MessageScrollerButton`** — the scroll control. Scrolls to the start or end of the transcript and is inert until there is content in its direction.
## Core Concepts
### Anchoring Turns
A turn is the part of the conversation that starts a new exchange. In a simple
AI chat, that is usually the user's message and the assistant reply that follows.
An anchor is the row the viewport should treat as the start of that turn. Mark
that row with `scrollAnchor`. When a new anchor is appended, the viewport moves
it near the top and keeps a peek of the previous item above it, so the new turn
does not feel detached from its context.
```tsx
// This tells the scroller to anchor the user's message for the next turn.
<MessageScrollerItem
messageId={message.id}
scrollAnchor={message.role === "user"}
/>
```
Scroll anchors are not tied to message role. You can turn any row into an anchor:
a user message, a system marker, a handoff event, or anything else that starts a
meaningful turn. `MessageScroller` only needs to know which row should anchor the
viewport.
In the following example, the user's message is anchored. When you send a new message, the viewport anchors it near the top and appends the assistant reply below it. Toggle the anchor to the assistant's message to see the difference.
<ComponentPreview
styleName="base-rhea"
name="message-scroller-anchoring"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
### Group Chat
In a group chat, the turn boundary is more specific than "the user message". It is often
the message that asks the model to respond, or a marker like "Marcus joined the
chat". Typing indicators and history controls usually should not anchor.
Because anchoring is role-independent, you can anchor a marker just as easily as
a message.
```tsx
<MessageScrollerItem messageId="marcus-joined" scrollAnchor>
<Marker variant="separator">
<MarkerContent>Marcus joined the chat</MarkerContent>
</Marker>
</MessageScrollerItem>
```
<ComponentPreview
styleName="base-rhea"
name="message-scroller-group-chat"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
### Keeping Context Visible
When a new turn starts, it should still feel like part of the same continuous
thread. `scrollPreviousItemPeek` keeps a slice of the previous item visible
above the anchor, so the reader keeps their context instead of feeling like the
conversation restarted on a blank page.
```tsx
// Keep 64px of the previous turn visible above the newly anchored row.
<MessageScrollerProvider scrollPreviousItemPeek={64}>
<MessageScroller>{/* anchored turns */}</MessageScroller>
</MessageScrollerProvider>
```
Adjust the peek amount in the example below to see how it affects the conversation.
<ComponentPreview
styleName="base-rhea"
name="message-scroller-previous-context"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
### Following the Live Edge
When the reader is at the live edge, either because they stayed there or
returned there, `autoScroll` keeps streamed replies in view as they grow.
Scrolling away from the live edge releases the view, whether by wheel, touch,
keyboard scroll keys, or dragging the scrollbar. An explicit message jump
releases it too. New chunks can then arrive without moving the reader.
`autoScroll` composes with turn anchoring. When a new turn anchors near the
top, the view stays put while the reply streams into the room below it. Once
the reply fills the viewport, the reader is back at the live edge and
follow-output takes over from the anchor.
```tsx
<MessageScrollerProvider autoScroll>
<MessageScroller>{/* streamed turns */}</MessageScroller>
</MessageScrollerProvider>
```
<ComponentPreview
styleName="base-rhea"
name="message-scroller-streaming"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
Calling `scrollToEnd`, or pressing `MessageScrollerButton`, re-engages
follow-output when `autoScroll` is enabled, so a reader who scrolled away can
return to the live edge and keep following. The root and viewport expose
`data-autoscrolling` while that programmatic scroll to the latest message runs,
so you can conditionally apply styles during the transition.
### Opening Saved Threads
It can seem reasonable to reopen a saved thread at the absolute end of the
transcript, but that often drops the reader into the conversation without enough
context. A better default is `"last-anchor"`: show the last meaningful turn,
like the user's latest message, with the reply below it.
That gives the reader an immediate place in the thread. They can see what they
asked, where the answer starts, and continue from there without reconstructing
the conversation from the bottom edge.
```tsx
<MessageScrollerProvider defaultScrollPosition="last-anchor">
<MessageScroller>{/* transcript */}</MessageScroller>
</MessageScrollerProvider>
```
<ComponentPreview
styleName="base-rhea"
name="message-scroller-opening-position"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
hideCode
/>
`"last-anchor"` is keyed on `scrollAnchor`, not message role. If no anchor
exists, or the last anchored turn already fits in the viewport, it falls back to
`"end"`.
Use `"start"` when you want to resume at the beginning of a conversation, or
`"end"` when the absolute latest message is the right place to land.
### Avoiding a Flash on Reload
A scroll container always opens at the top. HTML has no way to set `scrollTop`,
so a server-rendered transcript shows the oldest messages first. After
JavaScript runs, `defaultScrollPosition` moves the view, and you see a jump.
When `defaultScrollPosition` is `"end"` or `"last-anchor"`, the viewport has
`data-pending-scroll` until that position is applied. The styled viewport stays
hidden while the attribute is present, so you see the frame instead of the jump.
`"start"` does not need this.
If you want `"end"` visible on first paint, add an inline script right after the
viewport. Give the viewport an `id`, scroll it to the bottom, and remove
`data-pending-scroll`.
```tsx
const scrollToEndScript = `(function () {
var viewport = document.getElementById("messages")
if (!viewport) {
return
}
viewport.scrollTop = viewport.scrollHeight
viewport.removeAttribute("data-pending-scroll")
})()`
<MessageScroller>
<MessageScrollerViewport id="messages" suppressHydrationWarning>
<MessageScrollerContent>{/* transcript */}</MessageScrollerContent>
</MessageScrollerViewport>
<script dangerouslySetInnerHTML={{ __html: scrollToEndScript }} />
<MessageScrollerButton />
</MessageScroller>
```
Put the script in your page, not in the scroller. It only works for `"end"`, and
only when the messages are already in the HTML. Add `suppressHydrationWarning` on
the viewport. If you use a Content Security Policy, pass a `nonce`.
Do not use this script with `"last-anchor"`. Skip it when messages load on the
client.
### Loading Earlier Messages
Loading earlier messages should not move the conversation the reader is already
looking at. When older rows are prepended above the current transcript,
`MessageScrollerViewport` preserves the visible row so the reader stays in the
same place while history loads above them.
This is enabled by default through `preserveScrollOnPrepend`.
<ComponentPreview
styleName="base-rhea"
name="message-scroller-load-history"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
Use stable `messageId` values for message rows. That gives the scroller a
specific row to preserve instead of guessing from whichever pixel happens to sit
at the viewport edge.
### Animating New Messages
`MessageScrollerItem` can be animated directly. Create a motion version of the
item, keep `messageId` and `scrollAnchor` on it, and use transform and opacity
for the entrance.
A common chat pattern is to animate the user's message when it is sent, then let
the assistant reply stream into a regular row below it. Start the user row below
its final position so it feels like it rises from the live edge of the viewport.
```tsx
const MotionMessageScrollerItem = motion.create(MessageScrollerItem)
```
<ComponentPreview
styleName="base-rhea"
name="message-scroller-animation"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
Avoid animating height, margin, or padding for row entrances; those changes can
fight the scroller's positioning work. If the reader prefers reduced motion,
skip the entrance animation and keep the scroll behavior the same.
### Jumping to Messages
Search results, permalinks, outline items, and toolbar buttons often need to
drive the transcript from outside the message list. Use `useMessageScroller` for
those controls. Because the hooks read from `MessageScrollerProvider`, they work
in any component inside the provider, including controls rendered outside the
`MessageScroller` frame.
```tsx
import { useMessageScroller } from "@/components/ui/message-scroller"
```
```tsx
const { scrollToMessage, scrollToEnd, scrollToStart } = useMessageScroller()
```
<ComponentPreview
styleName="base-rhea"
name="message-scroller-commands"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
hideCode
/>
`scrollToMessage` targets the `messageId` on `MessageScrollerItem`, so rows that
need to be addressable should have stable ids. `scrollToMessage` returns `false`
when the target is not mounted and cannot be queued.
`scrollToMessage` can queue a target before items exist, which covers
client-resolved permalinks while the transcript mounts. After rows have mounted,
a missing id returns `false` instead of starting a guessed retry loop. A `true`
result means the scroll ran or was queued, not that the row is already in view.
### Tracking the Reader's Position
Use `useMessageScrollerVisibility` to track the reader's position in the
conversation. A common example is a table-of-contents or a jump menu that
highlights the current anchored turn.
```tsx
import { useMessageScrollerVisibility } from "@/components/ui/message-scroller"
```
```tsx
const { currentAnchorId, visibleMessageIds } = useMessageScrollerVisibility()
```
<ComponentPreview
styleName="base-rhea"
name="message-scroller-visibility"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
hideCode
/>
`currentAnchorId` answers "where am I" by reporting the current anchored turn,
and it stays set after that anchor scrolls above the viewport. `visibleMessageIds`
answers "what is on screen", in document order.
Visibility is pay-for-what-you-use. Tracking only runs while something
subscribes to `useMessageScrollerVisibility`, and rows need a `messageId` to
participate.
### Reading Scroll State
Use `useMessageScrollerScrollable` when you need scroll state in JavaScript, such
as a status indicator or a custom "jump to latest" control. It reports which
edges the viewport can still scroll toward; "at the start/end" is the negation
(`!start` / `!end`), and "scrollable at all" is `start || end`. For styling the
scroller itself, prefer the `data-scrollable` attribute.
```tsx
import { useMessageScrollerScrollable } from "@/components/ui/message-scroller"
```
```tsx
const { start, end } = useMessageScrollerScrollable()
```
<ComponentPreview
styleName="base-rhea"
name="message-scroller-scrollable"
className="rounded-[34px] sm:rounded-4xl"
previewClassName="h-auto theme-blue bg-surface dark:bg-background p-4 min-[480px]:p-8 min-[560px]:p-10 sm:px-10 sm:py-16"
/>
## Performance
`MessageScroller` is benchmarked against large transcripts with markdown and
composed message rows.
Our performance goal for `MessageScroller` is to keep the scroll hot path outside of React state: no React rerenders for
transcript rows, no forced layout on every scroll, and as little off-screen paint
work as the browser can avoid.
Scroll position, anchoring, and follow-output are tracked imperatively and mirrored onto the root and viewport through `data-*` attributes, so scrolling and streaming do not rerender transcript rows.
The styled `MessageScrollerItem` also ships with `content-visibility: auto` and
`contain-intrinsic-size`. Rows stay in the DOM for selection, copy,
find-in-page, SSR, and assistive tech, but the browser can skip rendering work
for rows far outside the viewport.
Visibility tracking is pay-for-what-you-use. A jump menu or active
turn indicator costs nothing until something subscribes to
`useMessageScrollerVisibility`.
This is comfortable for the expected range of a chat transcript: hundreds to low
thousands of turns, including messages with markdown and composed components.
## Virtualization
Virtualization is intentionally left outside the primitive. `MessageScroller`
renders real DOM rows and stays fast well into the thousands of turns (see
[Performance](#performance)), so most transcripts never need it.
When a transcript is large enough to need virtualization, use
`MessageScrollerViewport` as the scroll element and let the virtualizer own the
rows.
```tsx showLineNumbers
import * as React from "react"
import { useVirtualizer } from "@tanstack/react-virtual"
function VirtualizedTranscript({
messages,
}: {
messages: Array<{ id: string; content: React.ReactNode }>
}) {
const viewportRef = React.useRef<HTMLDivElement>(null)
const virtualizer = useVirtualizer({
count: messages.length,
getScrollElement: () => viewportRef.current,
estimateSize: () => 86,
getItemKey: (index) => messages[index]?.id ?? index,
overscan: 8,
})
return (
<MessageScrollerProvider>
<MessageScroller>
<MessageScrollerViewport ref={viewportRef}>
<MessageScrollerContent className="block min-h-full">
<div
className="relative w-full"
style={{ height: virtualizer.getTotalSize() }}
>
{virtualizer.getVirtualItems().map((virtualItem) => {
const message = messages[virtualItem.index]
if (!message) {
return null
}
return (
<div
key={virtualItem.key}
ref={virtualizer.measureElement}
data-index={virtualItem.index}
className="absolute start-0 top-0 w-full"
style={{
transform: `translateY(${virtualItem.start}px)`,
}}
>
<Message>{message.content}</Message>
</div>
)
})}
</div>
</MessageScrollerContent>
</MessageScrollerViewport>
<MessageScrollerButton />
</MessageScroller>
</MessageScrollerProvider>
)
}
```
## Accessibility
`MessageScroller` keeps the scroll container keyboard reachable and the
transcript announceable without forcing a specific message UI.
`MessageScrollerViewport` is a labelled, keyboard-focusable scroll region by
default. It uses `role="region"`, `aria-label="Messages"`, and `tabIndex={0}`,
so keyboard users can focus the transcript and scroll it directly.
`MessageScrollerContent` marks the transcript as a live region with
`role="log"` and `aria-relevant="additions"`. New rows can be announced, but
streamed text mutations do not have to be announced token by token.
```tsx
<MessageScrollerContent aria-busy={status === "streaming"}>
{/* messages */}
</MessageScrollerContent>
```
Pass `aria-busy` while a turn streams if announcements should wait for the
completed message row.
`MessageScrollerButton` renders a real button. When there is nothing to scroll
toward, it sets `inert`, uses `tabIndex={-1}`, and exposes `data-active="false"`
so inactive scroll controls do not create extra focus stops.
## Unstyled
The behavior in `MessageScroller` comes from the `@shadcn/react` package. To use
it directly with your own markup and styles, see
[Message Scroller](/docs/react/message-scroller) under @shadcn/react.
## API Reference
The props, data attributes, and hooks for every part are documented on the
[@shadcn/react Message Scroller](/docs/react/message-scroller#api-reference) page.
They are identical for the styled component and the unstyled parts.

View File

@@ -0,0 +1,246 @@
---
title: Message
description: Displays a message in a conversation, with optional avatar, header, footer, and alignment.
base: base
component: true
---
<ComponentPreview
styleName="base-rhea"
name="message-demo"
previewClassName="h-auto theme-blue"
/>
The `Message` component lays out a single message in a conversation. It handles the avatar, alignment, header, and footer around the message surface.
For AI apps, you can render reasoning steps, tool calls and assistant messages using the `Message` component.
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add message
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="message"
title="components/ui/message.tsx"
styleName="base-rhea"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Bubble, BubbleContent } from "@/components/ui/bubble"
import { Message, MessageAvatar, MessageContent } from "@/components/ui/message"
```
```tsx showLineNumbers
<Message>
<MessageAvatar>
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" alt="@shadcn" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
</MessageAvatar>
<MessageContent>
<Bubble>
<BubbleContent>How can I help you today?</BubbleContent>
</Bubble>
</MessageContent>
</Message>
```
**Note:** `Message` owns the row layout—avatar, alignment, header, and footer.
Render the visible message surface inside it with
[`Bubble`](/docs/components/bubble). For the scroll container around a
conversation, use [`MessageScroller`](/docs/components/message-scroller).
## Composition
Use the following composition to build a message:
```text
Message
├── MessageAvatar
└── MessageContent
├── MessageHeader
├── Bubble
└── MessageFooter
```
Use `MessageGroup` to stack consecutive messages from the same sender:
```text
MessageGroup
├── Message
└── Message
```
## Features
- Start and end alignment for sender and receiver rows via the `align` prop
- Avatar slot that anchors to the bottom of the message and stays clear of the footer
- Header and footer slots for sender names, status, and message actions
- Footer follows the message side; actions stay aligned on `align="end"` rows
- Group wrapper for stacking consecutive messages from the same sender
- Customizable styling through the `className` prop on every part
## Avatar
Use `MessageAvatar` to render an avatar next to the message. Set `align="end"` on the message to align the avatar to the end of the message.
<ComponentPreview
styleName="base-rhea"
name="message-avatar"
previewClassName="h-auto theme-blue"
/>
| align | Description |
| ------- | --------------------------------------------------- |
| `start` | Align the message to the start of the conversation. |
| `end` | Align the message to the end of the conversation. |
## Group
Use `MessageGroup` to stack consecutive messages from the same sender. Render an empty `MessageAvatar` on the earlier messages to keep them aligned with the avatar on the last one.
<ComponentPreview
styleName="base-rhea"
name="message-group"
previewClassName="h-auto theme-blue"
/>
## Header and Footer
Use `MessageHeader` for a sender name and `MessageFooter` for metadata such as a delivery or read status.
<ComponentPreview
styleName="base-rhea"
name="message-header-footer"
previewClassName="h-auto theme-blue"
/>
## Actions
Place message-level actions in `MessageFooter`, such as copy, retry, or feedback buttons.
<ComponentPreview
styleName="base-rhea"
name="message-actions"
previewClassName="h-auto theme-blue"
/>
## Attachment
<ComponentPreview
styleName="base-rhea"
name="message-attachment"
previewClassName="h-auto theme-blue"
/>
## Accessibility
`Message` is a presentational layout wrapper. Accessibility comes from the content you place inside it.
### Label icon-only actions
Action buttons in `MessageFooter` are usually icon-only, so give each one an `aria-label`.
```tsx showLineNumbers
<MessageFooter>
<Button variant="ghost" size="icon" aria-label="Copy">
<CopyIcon />
</Button>
</MessageFooter>
```
### Status updates
For in-progress messages, use a [`Marker`](/docs/components/marker) with `role="status"` so assistive tech announces the update as it appears.
```tsx showLineNumbers
<Message>
<Marker role="status">
<MarkerIcon>
<Spinner />
</MarkerIcon>
<MarkerContent>Checking the logs...</MarkerContent>
</Marker>
</Message>
```
## API Reference
### Message
The message row wrapper.
| Prop | Type | Default | Description |
| ----------- | ------------------ | --------- | ------------------------------------------------- |
| `align` | `"start" \| "end"` | `"start"` | The alignment of the message in the conversation. |
| `className` | `string` | - | Additional classes to apply to the row. |
### MessageGroup
Groups consecutive messages from the same sender.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ---------------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the group root. |
### MessageAvatar
The avatar slot, aligned to the bottom of the message. When the message has a `MessageFooter`, the avatar shifts up to stay aligned with the message surface instead of the footer.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ----------------------------------------------- |
| `className` | `string` | - | Additional classes to apply to the avatar slot. |
### MessageContent
Wraps the header, message surface, and footer.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ------------------------------------------------ |
| `className` | `string` | - | Additional classes to apply to the content slot. |
### MessageHeader
Displays content above the message, such as a sender name. Stays aligned to the start regardless of `align`.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ------------------------------------------ |
| `className` | `string` | - | Additional classes to apply to the header. |
### MessageFooter
Displays content below the message, such as status or actions. Aligns to the message side.
| Prop | Type | Default | Description |
| ----------- | -------- | ------- | ------------------------------------------ |
| `className` | `string` | - | Additional classes to apply to the footer. |

View File

@@ -0,0 +1,70 @@
{
"title": "Base UI",
"pages": [
"accordion",
"alert",
"alert-dialog",
"aspect-ratio",
"attachment",
"avatar",
"badge",
"breadcrumb",
"bubble",
"button",
"button-group",
"calendar",
"card",
"carousel",
"chart",
"checkbox",
"collapsible",
"combobox",
"command",
"context-menu",
"data-table",
"date-picker",
"dialog",
"direction",
"drawer",
"dropdown-menu",
"empty",
"field",
"form",
"hover-card",
"input",
"input-group",
"input-otp",
"item",
"kbd",
"label",
"marker",
"menubar",
"message",
"message-scroller",
"native-select",
"navigation-menu",
"pagination",
"popover",
"progress",
"questionnaire",
"radio-group",
"resizable",
"scroll-area",
"select",
"separator",
"sheet",
"sidebar",
"skeleton",
"slider",
"spinner",
"switch",
"table",
"tabs",
"textarea",
"toast",
"toggle",
"toggle-group",
"tooltip",
"typography"
]
}

View File

@@ -0,0 +1,170 @@
---
title: Native Select
description: A styled native HTML select element with consistent design system integration.
base: base
component: true
---
import { InfoIcon } from "lucide-react"
<Callout variant="info" icon={<InfoIcon className="translate-y-[3px]!" />}>
For a styled select component, see the [Select](/docs/components/select)
component.
</Callout>
<ComponentPreview styleName="base-nova" name="native-select-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add native-select
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="native-select"
title="components/ui/native-select.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
NativeSelect,
NativeSelectOptGroup,
NativeSelectOption,
} from "@/components/ui/native-select"
```
```tsx showLineNumbers
<NativeSelect>
<NativeSelectOption value="">Select a fruit</NativeSelectOption>
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
<NativeSelectOption value="blueberry">Blueberry</NativeSelectOption>
<NativeSelectOption value="pineapple">Pineapple</NativeSelectOption>
</NativeSelect>
```
## Composition
### Simple
Options placed directly under `NativeSelect` (no `NativeSelectOptGroup`).
```text
NativeSelect
├── NativeSelectOption
├── NativeSelectOption
├── NativeSelectOption
└── NativeSelectOption
```
### With groups
Use `NativeSelectOptGroup` to organize options into categories.
```text
NativeSelect
├── NativeSelectOptGroup
│ ├── NativeSelectOption
│ └── NativeSelectOption
└── NativeSelectOptGroup
├── NativeSelectOption
└── NativeSelectOption
```
## Groups
Use `NativeSelectOptGroup` to organize options into categories.
<ComponentPreview styleName="base-nova" name="native-select-groups" />
## Disabled
Add the `disabled` prop to the `NativeSelect` component to disable the select.
<ComponentPreview styleName="base-nova" name="native-select-disabled" />
## Invalid
Use `aria-invalid` to show validation errors and the `data-invalid` attribute to the `Field` component for styling.
<ComponentPreview styleName="base-nova" name="native-select-invalid" />
## Native Select vs Select
- Use `NativeSelect` for native browser behavior, better performance, or mobile-optimized dropdowns.
- Use `Select` for custom styling, animations, or complex interactions.
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="native-select-rtl"
direction="rtl"
/>
## API Reference
### NativeSelect
The main select component that wraps the native HTML select element.
```tsx
<NativeSelect>
<NativeSelectOption value="option1">Option 1</NativeSelectOption>
<NativeSelectOption value="option2">Option 2</NativeSelectOption>
</NativeSelect>
```
### NativeSelectOption
Represents an individual option within the select.
| Prop | Type | Default |
| ---------- | --------- | ------- |
| `value` | `string` | |
| `disabled` | `boolean` | `false` |
### NativeSelectOptGroup
Groups related options together for better organization.
| Prop | Type | Default |
| ---------- | --------- | ------- |
| `label` | `string` | |
| `disabled` | `boolean` | `false` |
```tsx
<NativeSelectOptGroup label="Fruits">
<NativeSelectOption value="apple">Apple</NativeSelectOption>
<NativeSelectOption value="banana">Banana</NativeSelectOption>
</NativeSelectOptGroup>
```

View File

@@ -0,0 +1,142 @@
---
title: Navigation Menu
description: A collection of links for navigating websites.
base: base
component: true
links:
doc: https://base-ui.com/react/components/navigation-menu
api: https://base-ui.com/react/components/navigation-menu#api-reference
---
<ComponentPreview
styleName="base-nova"
name="navigation-menu-demo"
previewClassName="h-96"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add navigation-menu
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="navigation-menu"
title="components/ui/navigation-menu.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
NavigationMenu,
NavigationMenuContent,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
NavigationMenuTrigger,
} from "@/components/ui/navigation-menu"
```
```tsx showLineNumbers
<NavigationMenu>
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger>Item One</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuLink>Link</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenu>
```
## Composition
Use the following composition to build a `NavigationMenu`:
```text
NavigationMenu
├── NavigationMenuList
│ ├── NavigationMenuItem
│ │ ├── NavigationMenuTrigger
│ │ └── NavigationMenuContent
│ │ ├── NavigationMenuLink
│ │ └── NavigationMenuLink
│ └── NavigationMenuItem
│ └── NavigationMenuLink
└── NavigationMenuIndicator
```
## Link Component
Use the `render` prop to compose a custom link component such as Next.js `Link`.
```tsx showLineNumbers
import Link from "next/link"
import {
NavigationMenuItem,
NavigationMenuLink,
navigationMenuTriggerStyle,
} from "@/components/ui/navigation-menu"
export function NavigationMenuDemo() {
return (
<NavigationMenuItem>
<NavigationMenuLink
render={<Link href="/docs" />}
className={navigationMenuTriggerStyle()}
>
Documentation
</NavigationMenuLink>
</NavigationMenuItem>
)
}
```
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="navigation-menu-rtl"
direction="rtl"
previewClassName="h-96"
/>
## API Reference
See the [Base UI Navigation Menu](https://base-ui.com/react/components/navigation-menu#api-reference) documentation for more information.

View File

@@ -0,0 +1,210 @@
---
title: Pagination
description: Pagination with page navigation, next and previous links.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="pagination-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add pagination
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="pagination"
title="components/ui/pagination.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination"
```
```tsx showLineNumbers
<Pagination>
<PaginationContent>
<PaginationItem>
<PaginationPrevious href="#" />
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">1</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#" isActive>
2
</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationLink href="#">3</PaginationLink>
</PaginationItem>
<PaginationItem>
<PaginationEllipsis />
</PaginationItem>
<PaginationItem>
<PaginationNext href="#" />
</PaginationItem>
</PaginationContent>
</Pagination>
```
## Composition
Use the following composition to build a `Pagination`:
```text
Pagination
└── PaginationContent
├── PaginationItem
│ └── PaginationPrevious
├── PaginationItem
│ └── PaginationLink
├── PaginationItem
│ └── PaginationEllipsis
└── PaginationItem
└── PaginationNext
```
## Simple
A simple pagination with only page numbers.
<ComponentPreview styleName="base-nova" name="pagination-simple" />
## Icons Only
Use just the previous and next buttons without page numbers. This is useful for data tables with a rows per page selector.
<ComponentPreview styleName="base-nova" name="pagination-icons-only" />
## Next.js
By default the `<PaginationLink />` component will render an `<a />` tag.
To use the Next.js `<Link />` component, make the following updates to `pagination.tsx`.
```diff showLineNumbers /typeof Link/ {1}
+ import Link from "next/link"
- type PaginationLinkProps = ... & React.ComponentProps<"a">
+ type PaginationLinkProps = ... & React.ComponentProps<typeof Link>
const PaginationLink = ({...props }: ) => (
<PaginationItem>
- <a>
+ <Link>
// ...
- </a>
+ </Link>
</PaginationItem>
)
```
<Callout className="mt-6">
**Note:** We are making updates to the cli to automatically do this for you.
</Callout>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="pagination-rtl" direction="rtl" />
## Changelog
### RTL Support
If you're upgrading from a previous version of the `Pagination` component, you'll need to apply the following updates to add the `text` prop:
<Steps>
<Step>Update `PaginationPrevious`.</Step>
```diff
function PaginationPrevious({
className,
+ text = "Previous",
...props
- }: React.ComponentProps<typeof PaginationLink>) {
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
return (
<PaginationLink
aria-label="Go to previous page"
size="default"
className={cn("cn-pagination-previous", className)}
{...props}
>
<ChevronLeftIcon />
<span className="cn-pagination-previous-text hidden sm:block">
- Previous
+ {text}
</span>
</PaginationLink>
)
}
```
<Step>Update `PaginationNext`.</Step>
```diff
function PaginationNext({
className,
+ text = "Next",
...props
- }: React.ComponentProps<typeof PaginationLink>) {
+ }: React.ComponentProps<typeof PaginationLink> & { text?: string }) {
return (
<PaginationLink
aria-label="Go to next page"
size="default"
className={cn("cn-pagination-next", className)}
{...props}
>
- <span className="cn-pagination-next-text hidden sm:block">Next</span>
+ <span className="cn-pagination-next-text hidden sm:block">{text}</span>
<ChevronRightIcon />
</PaginationLink>
)
}
```
</Steps>

View File

@@ -0,0 +1,118 @@
---
title: Popover
description: Displays rich content in a portal, triggered by a button.
base: base
component: true
links:
doc: https://base-ui.com/react/components/popover
api: https://base-ui.com/react/components/popover#api-reference
---
<ComponentPreview styleName="base-nova" name="popover-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add popover
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="popover"
title="components/ui/popover.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Popover,
PopoverContent,
PopoverDescription,
PopoverHeader,
PopoverTitle,
PopoverTrigger,
} from "@/components/ui/popover"
```
```tsx showLineNumbers
<Popover>
<PopoverTrigger render={<Button variant="outline" />}>
Open Popover
</PopoverTrigger>
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Title</PopoverTitle>
<PopoverDescription>Description text here.</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>
```
## Composition
Use the following composition to build a `Popover`:
```text
Popover
├── PopoverTrigger
└── PopoverContent
```
## Basic
A simple popover with a header, title, and description.
<ComponentPreview styleName="base-nova" name="popover-basic" />
## Align
Use the `align` prop on `PopoverContent` to control the horizontal alignment.
<ComponentPreview styleName="base-nova" name="popover-alignments" />
## With Form
A popover with form fields inside.
<ComponentPreview styleName="base-nova" name="popover-form" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="popover-rtl" direction="rtl" />
## API Reference
See the [Base UI Popover](https://base-ui.com/react/components/popover#api-reference) documentation.

View File

@@ -0,0 +1,112 @@
---
title: Progress
description: Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.
base: base
component: true
links:
doc: https://base-ui.com/react/components/progress
api: https://base-ui.com/react/components/progress#api-reference
---
<ComponentPreview styleName="base-nova" name="progress-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add progress
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="progress"
title="components/ui/progress.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Progress } from "@/components/ui/progress"
```
```tsx showLineNumbers
<Progress value={33} />
```
## Composition
### With label and value
Use `ProgressLabel` and `ProgressValue` to add a label and value display.
```tsx showLineNumbers
import {
Progress,
ProgressLabel,
ProgressValue,
} from "@/components/ui/progress"
;<Progress value={56} className="w-full max-w-sm">
<ProgressLabel>Upload progress</ProgressLabel>
<ProgressValue />
</Progress>
```
```text
Progress
├── ProgressLabel
├── ProgressValue
└── ProgressTrack
└── ProgressIndicator
```
## Label
Use `ProgressLabel` and `ProgressValue` to add a label and value display.
<ComponentPreview styleName="base-nova" name="progress-label" />
## Controlled
A progress bar that can be controlled by a slider.
<ComponentPreview styleName="base-nova" name="progress-controlled" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="progress-rtl" direction="rtl" />
## API Reference
See the [Base UI Progress](https://base-ui.com/react/components/progress#api-reference) documentation.

View File

@@ -0,0 +1,367 @@
---
title: Questionnaire
description: A multi-step questionnaire with single-choice, multiple-choice, freeform, and skippable questions.
base: base
component: true
---
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-demo"
previewClassName="min-h-[560px] p-4 sm:p-8"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add questionnaire
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependency:</Step>
```bash
npm install @shadcn/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="questionnaire"
title="components/ui/questionnaire.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import {
Questionnaire,
QuestionnaireActions,
QuestionnaireChoice,
QuestionnaireChoices,
QuestionnaireDescription,
QuestionnaireError,
QuestionnaireInput,
QuestionnaireItem,
QuestionnaireNext,
QuestionnairePrevious,
QuestionnaireProgress,
QuestionnaireSkip,
QuestionnaireSubmit,
QuestionnaireTitle,
} from "@/components/ui/questionnaire"
```
```tsx
const items = [
{
name: "direction",
required: true,
prompt: "What should we prototype next?",
description: "Choose a direction or write your own.",
choices: [
{
value: "delegation",
label: "Delegation",
description: "Show how work moves to a specialist.",
},
{
value: "questions",
label: "Question prompts",
description: "Show choices while the interface waits.",
},
{ value: "both", label: "Both together" },
],
input: { label: "Another answer", placeholder: "Type another answer…" },
},
{
name: "detail",
required: false,
prompt: "How much detail should it include?",
description: "Skip this if you are not sure yet.",
choices: [
{ value: "focused", label: "Focused" },
{ value: "complete", label: "Complete flow" },
],
},
] as const
```
Define the collection once: pass it to `Questionnaire` for server-rendered
progress, actions, and shortcuts, then map it into the parts.
```tsx
<Questionnaire items={items} onSubmit={handleSubmit}>
<QuestionnaireProgress />
{items.map((question) => (
<QuestionnaireItem
key={question.name}
name={question.name}
required={question.required}
>
<QuestionnaireTitle>{question.prompt}</QuestionnaireTitle>
<QuestionnaireDescription>
{question.description}
</QuestionnaireDescription>
<QuestionnaireChoices>
{question.choices.map((choice) => (
<QuestionnaireChoice key={choice.value} value={choice.value}>
<span className="font-medium">{choice.label}</span>
{"description" in choice ? (
<span className="text-muted-foreground">
{choice.description}
</span>
) : null}
</QuestionnaireChoice>
))}
{"input" in question ? (
<QuestionnaireInput
aria-label={question.input.label}
placeholder={question.input.placeholder}
/>
) : null}
</QuestionnaireChoices>
<QuestionnaireError />
</QuestionnaireItem>
))}
<QuestionnaireActions>
<QuestionnairePrevious />
<QuestionnaireSkip />
<QuestionnaireNext />
<QuestionnaireSubmit />
</QuestionnaireActions>
</Questionnaire>
```
```tsx
function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault()
const answers = new FormData(event.currentTarget)
// answers.get("direction"), answers.getAll(...) for multiple items.
}
```
## Composition
```text
Questionnaire
├── QuestionnaireProgress
├── QuestionnaireItem
│ ├── QuestionnaireTitle
│ ├── QuestionnaireDescription
│ ├── QuestionnaireChoices
│ │ ├── QuestionnaireChoice
│ │ └── QuestionnaireInput
│ └── QuestionnaireError
└── QuestionnaireActions
├── QuestionnairePrevious
├── QuestionnaireSkip
├── QuestionnaireNext
└── QuestionnaireSubmit
```
Questionnaire owns the ordered items, active item, answer state, validation,
progress, and navigation. The containing page, card, dialog, or drawer owns
close and cancellation behavior, persistence, transport, and branching.
## Server Rendering
Pass `items` to server-render the active item, progress, actions, and answer
shortcuts. See the
[headless Questionnaire](/docs/react/questionnaire) for the complete behavior.
## Multiple Selection
Use `multiple` for an item that accepts more than one fixed answer.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-multiple"
previewClassName="min-h-[420px] p-4 sm:p-8"
/>
## Freeform Answer
Compose `QuestionnaireInput` with fixed choices when the user can provide another answer.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-freeform"
previewClassName="min-h-[420px] p-4 sm:p-8"
/>
## Explicit Skip
Add `QuestionnaireSkip` when an optional item may be intentionally left unanswered.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-skip"
previewClassName="min-h-[520px] p-4 sm:p-8"
/>
## Shortcuts
Assign a letter or number key to each answer with `shortcuts`.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-shortcuts"
previewClassName="min-h-[480px] p-4 sm:p-8"
/>
## Custom Validation
Combine controlled navigation with an external schema such as Zod to return to an invalid item and present its error.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-validation"
previewClassName="min-h-[520px] p-4 sm:p-8"
/>
## Controlled
Control the active item from host state, such as returning to an invalid step.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-controlled"
previewClassName="min-h-[520px] p-4 sm:p-8"
/>
## Resume
Restore a saved active item and default answers, then reset changes back to that saved state.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-resume"
previewClassName="min-h-[520px] p-4 sm:p-8"
/>
## Conditional Items
Disable items that do not apply to the user's earlier answers.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-conditional"
previewClassName="min-h-[520px] p-4 sm:p-8"
/>
## Navigation State
Read item status to opt into disabled navigation and custom action styling.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-navigation-state"
previewClassName="min-h-[480px] p-4 sm:p-8"
/>
## Custom Progress
Use the Progress render state to build a custom progress indicator.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-progress"
previewClassName="min-h-[520px] p-4 sm:p-8"
/>
## Animated Items
Animate the active item while keeping progress and navigation stationary.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-animated"
previewClassName="min-h-[520px] p-4 sm:p-8"
/>
## Card
Compose Questionnaire with Card slots while keeping the question title and description semantic.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-card"
previewClassName="min-h-[560px] p-4 sm:p-8"
/>
## Dialog
Compose Questionnaire inside a Dialog while keeping cancellation and dismissal host-owned.
<ComponentPreview
align="end"
styleName="base-nova"
name="questionnaire-dialog"
previewClassName="min-h-[320px] p-4 sm:p-8"
/>
## Accessibility
`QuestionnaireItem` renders a `fieldset`, and `QuestionnaireTitle` renders its
`legend`. Descriptions and active errors are associated with the current item,
and invalid items and answer controls expose `aria-invalid`.
Fixed choices preserve native radio and checkbox behavior. Progress is exposed
as a named progressbar, navigation uses real buttons, and inactive items and
actions are hidden and inert. Successful navigation focuses the newly active
item; failed validation focuses an available answer control.
Always give `QuestionnaireInput` an accessible name with a visible label,
`aria-label`, or `aria-labelledby`. A placeholder is not a label. See the
[Questionnaire accessibility guide](/docs/react/questionnaire#accessibility)
for labeling custom compositions and the complete keyboard behavior.
## Unstyled
The behavior in `Questionnaire` comes from the `@shadcn/react` package. To use
it directly with your own markup and styles, see
[Questionnaire](/docs/react/questionnaire) under @shadcn/react.
## API Reference
The props, data attributes, and render states for every part are documented on
the [@shadcn/react Questionnaire](/docs/react/questionnaire#api-reference) page.
The styled components inherit the corresponding unstyled props. Navigation
components also accept Button `size` and `variant` props, and
`QuestionnaireActions` is a styled-only layout helper.

View File

@@ -0,0 +1,127 @@
---
title: Radio Group
description: A set of checkable buttons—known as radio buttons—where no more than one of the buttons can be checked at a time.
base: base
component: true
links:
doc: https://base-ui.com/react/components/radio-group
api: https://base-ui.com/react/components/radio-group#api-reference
---
<ComponentPreview styleName="base-nova" name="radio-group-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add radio-group
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="radio-group"
title="components/ui/radio-group.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Label } from "@/components/ui/label"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"
```
```tsx showLineNumbers
<RadioGroup defaultValue="option-one">
<div className="flex items-center gap-3">
<RadioGroupItem value="option-one" id="option-one" />
<Label htmlFor="option-one">Option One</Label>
</div>
<div className="flex items-center gap-3">
<RadioGroupItem value="option-two" id="option-two" />
<Label htmlFor="option-two">Option Two</Label>
</div>
</RadioGroup>
```
## Composition
Use the following composition to build a `RadioGroup`:
```text
RadioGroup
├── RadioGroupItem
└── RadioGroupItem
```
## Description
Radio group items with a description using the `Field` component.
<ComponentPreview styleName="base-nova" name="radio-group-description" />
## Choice Card
Use `FieldLabel` to wrap the entire `Field` for a clickable card-style selection.
<ComponentPreview styleName="base-nova" name="radio-group-choice-card" />
## Fieldset
Use `FieldSet` and `FieldLegend` to group radio items with a label and description.
<ComponentPreview styleName="base-nova" name="radio-group-fieldset" />
## Disabled
Use the `disabled` prop on `RadioGroup` to disable all items.
<ComponentPreview styleName="base-nova" name="radio-group-disabled" />
## Invalid
Use `aria-invalid` on `RadioGroupItem` and `data-invalid` on `Field` to show validation errors.
<ComponentPreview styleName="base-nova" name="radio-group-invalid" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="radio-group-rtl"
direction="rtl"
/>
## API Reference
See the [Base UI Radio Group](https://base-ui.com/react/components/radio-group#api-reference) documentation.

View File

@@ -0,0 +1,136 @@
---
title: Resizable
description: Accessible resizable panel groups and layouts with keyboard support.
base: base
component: true
links:
doc: https://github.com/bvaughn/react-resizable-panels
api: https://github.com/bvaughn/react-resizable-panels/tree/main/packages/react-resizable-panels
---
<ComponentPreview
styleName="base-nova"
name="resizable-demo"
previewClassName="h-80"
/>
## About
The `Resizable` component is built on top of [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels) by [bvaughn](https://github.com/bvaughn).
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add resizable
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install react-resizable-panels
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="resizable"
title="components/ui/resizable.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
```
```tsx showLineNumbers
<ResizablePanelGroup orientation="horizontal">
<ResizablePanel>One</ResizablePanel>
<ResizableHandle />
<ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>
```
## Composition
Use the following composition to build a `ResizablePanelGroup`:
```text
ResizablePanelGroup
├── ResizablePanel
├── ResizableHandle
└── ResizablePanel
```
## Vertical
Use `orientation="vertical"` for vertical resizing.
<ComponentPreview styleName="base-nova" name="resizable-vertical" />
## Handle
Use the `withHandle` prop on `ResizableHandle` to show a visible handle.
<ComponentPreview styleName="base-nova" name="resizable-handle" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="resizable-rtl" direction="rtl" />
## API Reference
See the [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels/tree/main/packages/react-resizable-panels) documentation.
## Changelog
### 2025-02-02 `react-resizable-panels` v4
Updated to `react-resizable-panels` v4. See the [v4.0.0 release notes](https://github.com/bvaughn/react-resizable-panels/releases/tag/4.0.0) for full details.
If you're using `react-resizable-panels` primitives directly, note the following changes:
| v3 | v4 |
| ---------------------------- | ----------------------- |
| `PanelGroup` | `Group` |
| `PanelResizeHandle` | `Separator` |
| `direction` prop | `orientation` prop |
| `defaultSize={50}` | `defaultSize="50%"` |
| `onLayout` | `onLayoutChange` |
| `ImperativePanelHandle` | `PanelImperativeHandle` |
| `ref` prop on Panel | `panelRef` prop |
| `data-panel-group-direction` | `aria-orientation` |
<Callout>
The shadcn/ui wrapper components (`ResizablePanelGroup`, `ResizablePanel`,
`ResizableHandle`) remain unchanged.
</Callout>

View File

@@ -0,0 +1,99 @@
---
title: Scroll Area
description: Augments native scroll functionality for custom, cross-browser styling.
base: base
component: true
links:
doc: https://base-ui.com/react/components/scroll-area
api: https://base-ui.com/react/components/scroll-area#api-reference
---
<ComponentPreview
styleName="base-nova"
name="scroll-area-demo"
previewClassName="h-96"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add scroll-area
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="scroll-area"
title="components/ui/scroll-area.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"
```
```tsx showLineNumbers
<ScrollArea className="h-[200px] w-[350px] rounded-md border p-4">
Your scrollable content here.
</ScrollArea>
```
## Composition
Use the following composition to build a `ScrollArea`:
```text
ScrollArea
└── ScrollBar
```
## Horizontal
Use `ScrollBar` with `orientation="horizontal"` for horizontal scrolling.
<ComponentPreview styleName="base-nova" name="scroll-area-horizontal-demo" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="scroll-area-rtl"
direction="rtl"
previewClassName="h-auto"
/>
## API Reference
See the [Base UI Scroll Area](https://base-ui.com/react/components/scroll-area#api-reference) documentation.

View File

@@ -0,0 +1,157 @@
---
title: Select
description: Displays a list of options for the user to pick from—triggered by a button.
base: base
component: true
featured: true
links:
doc: https://base-ui.com/react/components/select
api: https://base-ui.com/react/components/select#api-reference
---
<ComponentPreview styleName="base-nova" name="select-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add select
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="select"
title="components/ui/select.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Select,
SelectContent,
SelectGroup,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select"
```
```tsx showLineNumbers
const items = [
{ label: "Light", value: "light" },
{ label: "Dark", value: "dark" },
{ label: "System", value: "system" },
]
<Select items={items}>
<SelectTrigger className="w-[180px]">
<SelectValue placeholder="Theme" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
{items.map((item) => (
<SelectItem key={item.value} value={item.value}>
{item.label}
</SelectItem>
))}
</SelectGroup>
</SelectContent>
</Select>
```
## Composition
Use the following composition to build a `Select`:
```text
Select
├── SelectTrigger
│ └── SelectValue
└── SelectContent
├── SelectGroup
│ ├── SelectLabel
│ ├── SelectItem
│ └── SelectItem
├── SelectSeparator
└── SelectGroup
├── SelectLabel
├── SelectItem
└── SelectItem
```
## Align Item With Trigger
Use `alignItemWithTrigger` on `SelectContent` to control whether the selected item aligns with the trigger. When `true` (default), the popup positions so the selected item appears over the trigger. When `false`, the popup aligns to the trigger edge.
<ComponentPreview styleName="base-nova" name="select-align-item" />
## Groups
Use `SelectGroup`, `SelectLabel`, and `SelectSeparator` to organize items.
<ComponentPreview styleName="base-nova" name="select-groups" />
## Scrollable
A select with many items that scrolls.
<ComponentPreview styleName="base-nova" name="select-scrollable" />
## Disabled
<ComponentPreview styleName="base-nova" name="select-disabled" />
## Invalid
Add the `data-invalid` attribute to the `Field` component and the `aria-invalid` attribute to the `SelectTrigger` component to show an error state.
```tsx showLineNumbers /data-invalid/ /aria-invalid/
<Field data-invalid>
<FieldLabel>Fruit</FieldLabel>
<SelectTrigger aria-invalid>
<SelectValue />
</SelectTrigger>
</Field>
```
<ComponentPreview styleName="base-nova" name="select-invalid" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="select-rtl" direction="rtl" />
## API Reference
See the [Base UI Select](https://base-ui.com/react/components/select#api-reference) documentation.

View File

@@ -0,0 +1,91 @@
---
title: Separator
description: Visually or semantically separates content.
base: base
component: true
links:
doc: https://base-ui.com/react/components/separator
api: https://base-ui.com/react/components/separator#api-reference
---
<ComponentPreview styleName="base-nova" name="separator-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add separator
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="separator"
title="components/ui/separator.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Separator } from "@/components/ui/separator"
```
```tsx showLineNumbers
<Separator />
```
## Vertical
Use `orientation="vertical"` for a vertical separator.
<ComponentPreview styleName="base-nova" name="separator-vertical" />
## Menu
Vertical separators between menu items with descriptions.
<ComponentPreview styleName="base-nova" name="separator-menu" />
## List
Horizontal separators between list items.
<ComponentPreview styleName="base-nova" name="separator-list" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="separator-rtl" direction="rtl" />
## API Reference
See the [Base UI Separator](https://base-ui.com/react/components/separator#api-reference) documentation.

View File

@@ -0,0 +1,116 @@
---
title: Sheet
description: Extends the Dialog component to display content that complements the main content of the screen.
base: base
component: true
links:
doc: https://base-ui.com/react/components/dialog
api: https://base-ui.com/react/components/dialog#api-reference
---
<ComponentPreview styleName="base-nova" name="sheet-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add sheet
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="sheet"
title="components/ui/sheet.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@/components/ui/sheet"
```
```tsx showLineNumbers
<Sheet>
<SheetTrigger>Open</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Are you absolutely sure?</SheetTitle>
<SheetDescription>This action cannot be undone.</SheetDescription>
</SheetHeader>
</SheetContent>
</Sheet>
```
## Composition
Use the following composition to build a `Sheet`:
```text
Sheet
├── SheetTrigger
└── SheetContent
├── SheetHeader
│ ├── SheetTitle
│ └── SheetDescription
└── SheetFooter
```
## Side
Use the `side` prop on `SheetContent` to set the edge of the screen where the sheet appears. Values are `top`, `right`, `bottom`, or `left`.
<ComponentPreview styleName="base-nova" name="sheet-side" />
## No Close Button
Use `showCloseButton={false}` on `SheetContent` to hide the close button.
<ComponentPreview styleName="base-nova" name="sheet-no-close-button" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="sheet-rtl" direction="rtl" />
## API Reference
See the [Base UI Dialog](https://base-ui.com/react/components/dialog#api-reference) documentation.

View File

@@ -0,0 +1,656 @@
---
title: Sidebar
description: A composable, themeable and customizable sidebar component.
base: base
component: true
---
import { ExternalLinkIcon } from "lucide-react"
<figure className="flex flex-col gap-4">
<ComponentPreview
styleName="base-nova"
name="sidebar-demo"
type="block"
className="w-full"
/>
<figcaption className="text-center text-sm text-gray-500">
A sidebar that collapses to icons.
</figcaption>
</figure>
Sidebars are one of the most complex components to build. They are central
to any application and often contain a lot of moving parts.
We now have a solid foundation to build on top of. Composable. Themeable.
Customizable.
[Browse the Blocks Library](/blocks).
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add sidebar
```
</TabsContent>
<TabsContent value="manual">
<ComponentSource
name="sidebar"
title="components/ui/sidebar.tsx"
styleName="base-nova"
/>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers title="app/layout.tsx"
import { SidebarProvider, SidebarTrigger } from "@/components/ui/sidebar"
import { AppSidebar } from "@/components/app-sidebar"
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<SidebarProvider>
<AppSidebar />
<main>
<SidebarTrigger />
{children}
</main>
</SidebarProvider>
)
}
```
```tsx showLineNumbers title="components/app-sidebar.tsx"
import {
Sidebar,
SidebarContent,
SidebarFooter,
SidebarGroup,
SidebarHeader,
} from "@/components/ui/sidebar"
export function AppSidebar() {
return (
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
</Sidebar>
)
}
```
## Composition
Use the following composition to build a `Sidebar` layout:
```text
SidebarProvider
├── Sidebar
│ ├── SidebarHeader
│ ├── SidebarContent
│ │ ├── SidebarGroup
│ │ │ ├── SidebarGroupLabel
│ │ │ ├── SidebarGroupAction
│ │ │ ├── SidebarGroupContent
│ │ │ └── SidebarMenu
│ │ │ ├── SidebarMenuItem
│ │ │ │ ├── SidebarMenuButton
│ │ │ │ ├── SidebarMenuAction
│ │ │ │ └── SidebarMenuBadge
│ │ │ └── SidebarMenuItem
│ │ │ ├── SidebarMenuButton
│ │ │ └── SidebarMenuSub
│ │ │ ├── SidebarMenuSubItem
│ │ │ └── SidebarMenuSubItem
│ │ └── SidebarGroup
│ │ └── SidebarMenu
│ │ ├── SidebarMenuItem
│ │ └── SidebarMenuItem
│ ├── SidebarFooter
│ └── SidebarRail
├── SidebarInset
└── SidebarTrigger
```
## Structure
- **SidebarProvider** — Handles collapsible state and provides sidebar context to child components.
- **Sidebar** — The main collapsible sidebar panel.
- **SidebarHeader** — Sticky at the top; use for branding, titles, or workspace switchers.
- **SidebarFooter** — Sticky at the bottom; use for user menus, settings, or actions.
- **SidebarContent** — Scrollable region between the header and footer.
- **SidebarGroup** — Groups related navigation with optional label, action, and content areas.
- **SidebarMenu** / **SidebarMenuItem** — Menu structure for links, badges, actions, and nested submenus.
- **SidebarRail** — Resize handle for adjusting sidebar width when applicable.
- **SidebarInset** — Wraps main content when using the `inset` variant.
- **SidebarTrigger** — Control that toggles the sidebar open or collapsed.
<Image
src="/images/sidebar-structure.png"
width="716"
height="420"
alt="Sidebar Structure"
className="mt-6 w-full overflow-hidden rounded-2xl border dark:hidden"
/>
<Image
src="/images/sidebar-structure-dark.png"
width="716"
height="420"
alt="Sidebar Structure"
className="mt-6 hidden w-full overflow-hidden rounded-2xl border dark:block"
/>
## SidebarProvider
The `SidebarProvider` component is used to provide the sidebar context to the `Sidebar` component. You should always wrap your application in a `SidebarProvider` component.
### Props
| Name | Type | Description |
| -------------- | ------------------------- | -------------------------------------------- |
| `defaultOpen` | `boolean` | Default open state of the sidebar. |
| `open` | `boolean` | Open state of the sidebar (controlled). |
| `onOpenChange` | `(open: boolean) => void` | Sets open state of the sidebar (controlled). |
### Width
If you have a single sidebar in your application, you can use the `SIDEBAR_WIDTH` and `SIDEBAR_WIDTH_MOBILE` variables in `sidebar.tsx` to set the width of the sidebar.
```tsx showLineNumbers title="components/ui/sidebar.tsx"
const SIDEBAR_WIDTH = "16rem"
const SIDEBAR_WIDTH_MOBILE = "18rem"
```
For multiple sidebars in your application, you can use the `--sidebar-width` and `--sidebar-width-mobile` CSS variables in the `style` prop.
```tsx showLineNumbers
<SidebarProvider
style={
{
"--sidebar-width": "20rem",
"--sidebar-width-mobile": "20rem",
} as React.CSSProperties
}
>
<Sidebar />
</SidebarProvider>
```
### Keyboard Shortcut
To trigger the sidebar, you use the `cmd+b` keyboard shortcut on Mac and `ctrl+b` on Windows.
```tsx showLineNumbers title="components/ui/sidebar.tsx"
const SIDEBAR_KEYBOARD_SHORTCUT = "b"
```
## Sidebar
The main `Sidebar` component used to render a collapsible sidebar.
### Props
| Property | Type | Description |
| ------------- | --------------------------------- | --------------------------------- |
| `side` | `left` or `right` | The side of the sidebar. |
| `variant` | `sidebar`, `floating`, or `inset` | The variant of the sidebar. |
| `collapsible` | `offcanvas`, `icon`, or `none` | Collapsible state of the sidebar. |
| Prop | Description |
| ----------- | ------------------------------------------------------------ |
| `offcanvas` | A collapsible sidebar that slides in from the left or right. |
| `icon` | A sidebar that collapses to icons. |
| `none` | A non-collapsible sidebar. |
<Callout>
**Note:** If you use the `inset` variant, remember to wrap your main content
in a `SidebarInset` component.
</Callout>
```tsx showLineNumbers
<SidebarProvider>
<Sidebar variant="inset" />
<SidebarInset>
<main>{children}</main>
</SidebarInset>
</SidebarProvider>
```
## useSidebar
The `useSidebar` hook is used to control the sidebar.
```tsx showLineNumbers
import { useSidebar } from "@/components/ui/sidebar"
export function AppSidebar() {
const {
state,
open,
setOpen,
openMobile,
setOpenMobile,
isMobile,
toggleSidebar,
} = useSidebar()
}
```
| Property | Type | Description |
| --------------- | ------------------------- | --------------------------------------------- |
| `state` | `expanded` or `collapsed` | The current state of the sidebar. |
| `open` | `boolean` | Whether the sidebar is open. |
| `setOpen` | `(open: boolean) => void` | Sets the open state of the sidebar. |
| `openMobile` | `boolean` | Whether the sidebar is open on mobile. |
| `setOpenMobile` | `(open: boolean) => void` | Sets the open state of the sidebar on mobile. |
| `isMobile` | `boolean` | Whether the sidebar is on mobile. |
| `toggleSidebar` | `() => void` | Toggles the sidebar. Desktop and mobile. |
## SidebarHeader
Use the `SidebarHeader` component to add a sticky header to the sidebar.
```tsx showLineNumbers title="components/app-sidebar.tsx"
<Sidebar>
<SidebarHeader>
<SidebarMenu>
<SidebarMenuItem>
<DropdownMenu>
<DropdownMenuTrigger render={<SidebarMenuButton />}>
Select Workspace
<ChevronDown className="ml-auto" />
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>
<span>Acme Inc</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</SidebarMenuItem>
</SidebarMenu>
</SidebarHeader>
</Sidebar>
```
## SidebarFooter
Use the `SidebarFooter` component to add a sticky footer to the sidebar.
```tsx showLineNumbers
<Sidebar>
<SidebarFooter>
<SidebarMenu>
<SidebarMenuItem>
<SidebarMenuButton>
<User2 /> Username
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarFooter>
</Sidebar>
```
## SidebarContent
The `SidebarContent` component is used to wrap the content of the sidebar. This is where you add your `SidebarGroup` components. It is scrollable.
```tsx showLineNumbers
<Sidebar>
<SidebarContent>
<SidebarGroup />
<SidebarGroup />
</SidebarContent>
</Sidebar>
```
## SidebarGroup
Use the `SidebarGroup` component to create a section within the sidebar.
A `SidebarGroup` has a `SidebarGroupLabel`, a `SidebarGroupContent` and an optional `SidebarGroupAction`.
```tsx showLineNumbers
<SidebarGroup>
<SidebarGroupLabel>Application</SidebarGroupLabel>
<SidebarGroupAction>
<Plus /> <span className="sr-only">Add Project</span>
</SidebarGroupAction>
<SidebarGroupContent></SidebarGroupContent>
</SidebarGroup>
```
To make a `SidebarGroup` collapsible, wrap it in a `Collapsible`.
```tsx showLineNumbers
<Collapsible defaultOpen className="group/collapsible">
<SidebarGroup>
<SidebarGroupLabel render={<CollapsibleTrigger />}>
Help
<ChevronDown className="ml-auto transition-transform group-data-open/collapsible:rotate-180" />
</SidebarGroupLabel>
<CollapsibleContent>
<SidebarGroupContent />
</CollapsibleContent>
</SidebarGroup>
</Collapsible>
```
## SidebarMenu
The `SidebarMenu` component is used for building a menu within a `SidebarGroup`.
<Image
src="/images/sidebar-menu.png"
width="716"
height="420"
alt="Sidebar Menu"
className="mt-6 w-full overflow-hidden rounded-2xl border dark:hidden"
/>
<Image
src="/images/sidebar-menu-dark.png"
width="716"
height="420"
alt="Sidebar Menu"
className="mt-6 hidden w-full overflow-hidden rounded-2xl border dark:block"
/>
```tsx showLineNumbers
<SidebarMenu>
{projects.map((project) => (
<SidebarMenuItem key={project.name}>
<SidebarMenuButton render={<a href={project.url} />}>
<project.icon />
<span>{project.name}</span>
</SidebarMenuButton>
</SidebarMenuItem>
))}
</SidebarMenu>
```
## SidebarMenuButton
The `SidebarMenuButton` component is used to render a menu button within a `SidebarMenuItem`.
By default, the `SidebarMenuButton` renders a button but you can use the `render` prop to render a different component such as a `Link` or an `a` tag.
Use the `isActive` prop to mark a menu item as active.
```tsx showLineNumbers
<SidebarMenuButton render={<a href="#" />} isActive>
Home
</SidebarMenuButton>
```
## SidebarMenuAction
The `SidebarMenuAction` component is used to render a menu action within a `SidebarMenuItem`.
```tsx showLineNumbers
<SidebarMenuItem>
<SidebarMenuButton render={<a href="#" />}>
<Home />
<span>Home</span>
</SidebarMenuButton>
<SidebarMenuAction>
<Plus /> <span className="sr-only">Add Project</span>
</SidebarMenuAction>
</SidebarMenuItem>
```
## SidebarMenuSub
The `SidebarMenuSub` component is used to render a submenu within a `SidebarMenu`.
```tsx showLineNumbers
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuSub>
<SidebarMenuSubItem>
<SidebarMenuSubButton />
</SidebarMenuSubItem>
</SidebarMenuSub>
</SidebarMenuItem>
```
## SidebarMenuBadge
The `SidebarMenuBadge` component is used to render a badge within a `SidebarMenuItem`.
```tsx showLineNumbers
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuBadge>24</SidebarMenuBadge>
</SidebarMenuItem>
```
## SidebarMenuSkeleton
The `SidebarMenuSkeleton` component is used to render a skeleton for a `SidebarMenu`.
```tsx showLineNumbers
<SidebarMenu>
{Array.from({ length: 5 }).map((_, index) => (
<SidebarMenuItem key={index}>
<SidebarMenuSkeleton />
</SidebarMenuItem>
))}
</SidebarMenu>
```
## SidebarTrigger
Use the `SidebarTrigger` component to render a button that toggles the sidebar.
```tsx showLineNumbers
import { useSidebar } from "@/components/ui/sidebar"
export function CustomTrigger() {
const { toggleSidebar } = useSidebar()
return <button onClick={toggleSidebar}>Toggle Sidebar</button>
}
```
## SidebarRail
The `SidebarRail` component is used to render a rail within a `Sidebar`. This rail can be used to toggle the sidebar.
```tsx showLineNumbers
<Sidebar>
<SidebarHeader />
<SidebarContent>
<SidebarGroup />
</SidebarContent>
<SidebarFooter />
<SidebarRail />
</Sidebar>
```
## Controlled Sidebar
Use the `open` and `onOpenChange` props to control the sidebar.
```tsx showLineNumbers
export function AppSidebar() {
const [open, setOpen] = React.useState(false)
return (
<SidebarProvider open={open} onOpenChange={setOpen}>
<Sidebar />
</SidebarProvider>
)
}
```
## Theming
We use the following CSS variables to theme the sidebar.
```css
@layer base {
:root {
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 0 0% 98%;
--sidebar-primary-foreground: 240 5.9% 10%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}
```
## Styling
Here are some tips for styling the sidebar based on different states.
```tsx
<Sidebar collapsible="icon">
<SidebarContent>
<SidebarGroup className="group-data-[collapsible=icon]:hidden" />
</SidebarContent>
</Sidebar>
```
```tsx
<SidebarMenuItem>
<SidebarMenuButton />
<SidebarMenuAction className="peer-data-[active=true]/menu-button:opacity-100" />
</SidebarMenuItem>
```
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
{/* prettier-ignore */}
<Button asChild size="sm" className="mt-6">
<a href="/view/base-nova/sidebar-rtl" target="_blank">View RTL Sidebar <ExternalLinkIcon /></a>
</Button>
## Changelog
### RTL Support
If you're upgrading from a previous version of the `Sidebar` component, you'll need to apply the following updates to add RTL support:
<Steps>
<Step>Add `dir` prop to Sidebar component.</Step>
Add `dir` to the destructured props and pass it to `SheetContent` for mobile:
```diff
function Sidebar({
side = "left",
variant = "sidebar",
collapsible = "offcanvas",
className,
children,
+ dir,
...props
}: React.ComponentProps<"div"> & {
side?: "left" | "right"
variant?: "sidebar" | "floating" | "inset"
collapsible?: "offcanvas" | "icon" | "none"
}) {
```
Then pass it to `SheetContent` in the mobile view:
```diff
<Sheet open={openMobile} onOpenChange={setOpenMobile} {...props}>
<SheetContent
+ dir={dir}
data-sidebar="sidebar"
data-slot="sidebar"
data-mobile="true"
```
<Step>Add `data-side` attribute to sidebar container.</Step>
Add `data-side={side}` to the sidebar container element:
```diff
<div
data-slot="sidebar-container"
+ data-side={side}
className={cn(
```
<Step>Update sidebar container positioning classes.</Step>
Replace JavaScript ternary conditional classes with CSS data attribute selectors:
```diff
className={cn(
- "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex",
- side === "left"
- ? "left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]"
- : "right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
+ "fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-width) transition-[left,right,width] duration-200 ease-linear md:flex data-[side=left]:left-0 data-[side=right]:right-0 data-[side=left]:group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)] data-[side=right]:group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]",
```
<Step>Update SidebarRail positioning classes.</Step>
Update the `SidebarRail` component to use physical positioning for the rail:
```diff
className={cn(
- "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear group-data-[side=left]:-end-4 group-data-[side=right]:start-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] sm:flex",
+ "hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 ltr:-translate-x-1/2 rtl:-translate-x-1/2 transition-all ease-linear group-data-[side=left]:-right-4 group-data-[side=right]:left-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] sm:flex",
```
<Step>Add RTL flip to SidebarTrigger icon.</Step>
Add `className="rtl:rotate-180"` to the icon in `SidebarTrigger` to flip it in RTL mode:
```diff
<Button ...>
- <PanelLeftIcon />
+ <PanelLeftIcon className="rtl:rotate-180" />
<span className="sr-only">Toggle Sidebar</span>
</Button>
```
</Steps>
After applying these changes, you can use the `dir` prop to set the direction:
```tsx
<Sidebar dir="rtl" side="right">
{/* ... */}
</Sidebar>
```
The sidebar will correctly position itself and handle interactions in both LTR and RTL layouts.

View File

@@ -0,0 +1,84 @@
---
title: Skeleton
description: Use to show a placeholder while content is loading.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="skeleton-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add skeleton
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="skeleton"
title="components/ui/skeleton.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Skeleton } from "@/components/ui/skeleton"
```
```tsx
<Skeleton className="h-[20px] w-[100px] rounded-full" />
```
## Avatar
<ComponentPreview styleName="base-nova" name="skeleton-avatar" />
## Card
<ComponentPreview
styleName="base-nova"
name="skeleton-card"
previewClassName="h-80"
/>
## Text
<ComponentPreview styleName="base-nova" name="skeleton-text" />
## Form
<ComponentPreview styleName="base-nova" name="skeleton-form" />
## Table
<ComponentPreview styleName="base-nova" name="skeleton-table" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="skeleton-rtl" direction="rtl" />

View File

@@ -0,0 +1,101 @@
---
title: Slider
description: An input where the user selects a value from within a given range.
base: base
component: true
links:
doc: https://base-ui.com/react/components/slider
api: https://base-ui.com/react/components/slider#api-reference
---
<ComponentPreview styleName="base-nova" name="slider-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add slider
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="slider"
title="components/ui/slider.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Slider } from "@/components/ui/slider"
```
```tsx
<Slider defaultValue={[33]} max={100} step={1} />
```
## Range
Use an array with two values for a range slider.
<ComponentPreview styleName="base-nova" name="slider-range" />
## Multiple Thumbs
Use an array with multiple values for multiple thumbs.
<ComponentPreview styleName="base-nova" name="slider-multiple" />
## Vertical
Use `orientation="vertical"` for a vertical slider.
<ComponentPreview styleName="base-nova" name="slider-vertical" />
## Controlled
<ComponentPreview styleName="base-nova" name="slider-controlled" />
## Disabled
Use the `disabled` prop to disable the slider.
<ComponentPreview styleName="base-nova" name="slider-disabled" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="slider-rtl" direction="rtl" />
## API Reference
See the [Base UI Slider](https://base-ui.com/react/components/slider#api-reference) documentation.

View File

@@ -0,0 +1,110 @@
---
title: Spinner
description: An indicator that can be used to show a loading state.
base: base
component: true
---
<ComponentPreview styleName="base-nova" name="spinner-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add spinner
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="spinner"
title="components/ui/spinner.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Spinner } from "@/components/ui/spinner"
```
```tsx
<Spinner />
```
## Customization
You can replace the default spinner icon with any other icon by editing the `Spinner` component.
<ComponentPreview styleName="base-nova" name="spinner-custom" />
```tsx showLineNumbers title="components/ui/spinner.tsx"
import { cn } from "cn"
import { LoaderIcon } from "lucide-react"
function Spinner({ className, ...props }: React.ComponentProps<"svg">) {
return (
<LoaderIcon
role="status"
aria-label="Loading"
className={cn("size-4 animate-spin", className)}
{...props}
/>
)
}
export { Spinner }
```
## Size
Use the `size-*` utility class to change the size of the spinner.
<ComponentPreview styleName="base-nova" name="spinner-size" />
## Button
Add a spinner to a button to indicate a loading state. Place the `<Spinner />` before the label with `data-icon="inline-start"` for a start position, or after the label with `data-icon="inline-end"` for an end position.
<ComponentPreview styleName="base-nova" name="spinner-button" />
## Badge
Add a spinner to a badge to indicate a loading state. Place the `<Spinner />` before the label with `data-icon="inline-start"` for a start position, or after the label with `data-icon="inline-end"` for an end position.
<ComponentPreview styleName="base-nova" name="spinner-badge" />
## Input Group
<ComponentPreview styleName="base-nova" name="spinner-input-group" />
## Empty
<ComponentPreview styleName="base-nova" name="spinner-empty" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="spinner-rtl" direction="rtl" />

View File

@@ -0,0 +1,101 @@
---
title: Switch
description: A control that allows the user to toggle between checked and not checked.
base: base
component: true
links:
doc: https://base-ui.com/react/components/switch
api: https://base-ui.com/react/components/switch#api-reference
---
<ComponentPreview styleName="base-nova" name="switch-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add switch
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="switch"
title="components/ui/switch.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Switch } from "@/components/ui/switch"
```
```tsx
<Switch />
```
## Description
<ComponentPreview styleName="base-nova" name="switch-description" />
## Choice Card
Card-style selection where `FieldLabel` wraps the entire `Field` for a clickable card pattern.
<ComponentPreview styleName="base-nova" name="switch-choice-card" />
## Disabled
Add the `disabled` prop to the `Switch` component to disable the switch. Add the `data-disabled` prop to the `Field` component for styling.
<ComponentPreview styleName="base-nova" name="switch-disabled" />
## Invalid
Add the `aria-invalid` prop to the `Switch` component to indicate an invalid state. Add the `data-invalid` prop to the `Field` component for styling.
<ComponentPreview styleName="base-nova" name="switch-invalid" />
## Size
Use the `size` prop to change the size of the switch.
<ComponentPreview styleName="base-nova" name="switch-sizes" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="switch-rtl" direction="rtl" />
## API Reference
See the [Base UI Switch](https://base-ui.com/react/components/switch#api-reference) documentation.

View File

@@ -0,0 +1,142 @@
---
title: Table
description: A responsive table component.
base: base
component: true
---
<ComponentPreview
styleName="base-nova"
name="table-demo"
previewClassName="h-[30rem]"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add table
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="table"
title="components/ui/table.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
```
```tsx showLineNumbers
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[100px]">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="font-medium">INV001</TableCell>
<TableCell>Paid</TableCell>
<TableCell>Credit Card</TableCell>
<TableCell className="text-right">$250.00</TableCell>
</TableRow>
</TableBody>
</Table>
```
## Composition
Use the following composition to build a `Table`:
```text
Table
├── TableCaption
├── TableHeader
│ └── TableRow
│ ├── TableHead
│ ├── TableHead
│ ├── TableHead
│ └── TableHead
├── TableBody
│ ├── TableRow
│ │ ├── TableCell
│ │ ├── TableCell
│ │ ├── TableCell
│ │ └── TableCell
│ └── TableRow
│ ├── TableCell
│ ├── TableCell
│ ├── TableCell
│ └── TableCell
└── TableFooter
```
## Footer
Use the `<TableFooter />` component to add a footer to the table.
<ComponentPreview styleName="base-nova" name="table-footer" />
## Actions
A table showing actions for each row using a `<DropdownMenu />` component.
<ComponentPreview styleName="base-nova" name="table-actions" />
## Data Table
You can use the `<Table />` component to build more complex data tables. Combine it with [@tanstack/react-table](https://tanstack.com/table/latest) to create tables with sorting, filtering and pagination.
See the [Data Table](/docs/components/data-table) documentation for more information.
You can also see an example of a data table in the [Tasks](/examples/tasks) demo.
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="table-rtl"
direction="rtl"
previewClassName="h-auto"
/>

View File

@@ -0,0 +1,117 @@
---
title: Tabs
description: A set of layered sections of content—known as tab panels—that are displayed one at a time.
base: base
component: true
links:
doc: https://base-ui.com/react/components/tabs
api: https://base-ui.com/react/components/tabs#api-reference
---
<ComponentPreview
styleName="base-nova"
name="tabs-demo"
previewClassName="h-96"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add tabs
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="tabs"
title="components/ui/tabs.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
```
```tsx showLineNumbers
<Tabs defaultValue="account" className="w-[400px]">
<TabsList>
<TabsTrigger value="account">Account</TabsTrigger>
<TabsTrigger value="password">Password</TabsTrigger>
</TabsList>
<TabsContent value="account">Make changes to your account here.</TabsContent>
<TabsContent value="password">Change your password here.</TabsContent>
</Tabs>
```
## Composition
Use the following composition to build `Tabs`:
```text
Tabs
├── TabsList
│ ├── TabsTrigger
│ └── TabsTrigger
├── TabsContent
└── TabsContent
```
## Line
Use the `variant="line"` prop on `TabsList` for a line style.
<ComponentPreview styleName="base-nova" name="tabs-line" />
## Vertical
Use `orientation="vertical"` for vertical tabs.
<ComponentPreview styleName="base-nova" name="tabs-vertical" />
## Disabled
<ComponentPreview styleName="base-nova" name="tabs-disabled" />
## Icons
<ComponentPreview styleName="base-nova" name="tabs-icons" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="tabs-rtl" direction="rtl" />
## API Reference
See the [Base UI Tabs](https://base-ui.com/react/components/tabs#api-reference) documentation.

View File

@@ -0,0 +1,104 @@
---
title: Textarea
description: Displays a form textarea or a component that looks like a textarea.
base: base
component: true
---
<ComponentPreview
styleName="base-nova"
name="textarea-demo"
previewClassName="*:max-w-xs"
/>
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add textarea
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="textarea"
title="components/ui/textarea.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Textarea } from "@/components/ui/textarea"
```
```tsx
<Textarea />
```
## Field
Use `Field`, `FieldLabel`, and `FieldDescription` to create a textarea with a label and description.
<ComponentPreview
styleName="base-nova"
name="textarea-field"
previewClassName="*:max-w-xs"
/>
## Disabled
Use the `disabled` prop to disable the textarea. To style the disabled state, add the `data-disabled` attribute to the `Field` component.
<ComponentPreview
styleName="base-nova"
name="textarea-disabled"
previewClassName="*:max-w-xs"
/>
## Invalid
Use the `aria-invalid` prop to mark the textarea as invalid. To style the invalid state, add the `data-invalid` attribute to the `Field` component.
<ComponentPreview
styleName="base-nova"
name="textarea-invalid"
previewClassName="*:max-w-xs"
/>
## Button
Pair with `Button` to create a textarea with a submit button.
<ComponentPreview
styleName="base-nova"
name="textarea-button"
previewClassName="*:max-w-xs"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="textarea-rtl" direction="rtl" />

View File

@@ -0,0 +1,142 @@
---
title: Toast
description: A succinct message that is displayed temporarily.
base: base
component: true
links:
doc: https://base-ui.com/react/components/toast
api: https://base-ui.com/react/components/toast#api-reference
---
<ComponentPreview styleName="base-nova" name="toast-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
<Steps className="mb-0 pt-2">
<Step>Run the following command:</Step>
```bash
npx shadcn@latest add toast
```
<Step>Add the Toaster component.</Step>
```tsx title="app/layout.tsx" {1,9} showLineNumbers
import { Toaster } from "@/components/ui/toast"
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<main>{children}</main>
<Toaster />
</body>
</html>
)
}
```
</Steps>
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependency:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="toast"
title="components/ui/toast.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
<Step>Add the Toaster component.</Step>
```tsx title="app/layout.tsx" {1,8} showLineNumbers
import { Toaster } from "@/components/ui/toast"
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Toaster />
</body>
</html>
)
}
```
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { toast } from "@/components/ui/toast"
```
```tsx
toast.add({
title: "Event created",
description: "Sunday, December 3 at 9:00 AM",
})
```
## Types
Set the `type` option to render a status icon. The built-in renderer recognizes
`success`, `info`, `warning`, `error`, and `loading`.
<ComponentPreview styleName="base-nova" name="toast-types" />
## Action
Pass button props with `actionProps` to render an action.
```tsx
const id = toast.add({
title: "Event created",
actionProps: {
children: "Undo",
onClick() {
toast.close(id)
},
},
})
```
## Promise
Use `toast.promise` to update one toast as an asynchronous task moves through
loading, success, and error states.
<ComponentPreview styleName="base-nova" name="toast-promise" />
## API Reference
See the [Base UI Toast documentation](https://base-ui.com/react/components/toast)
for details about manager options, stacking, swipe dismissal, and the primitive
API.

View File

@@ -0,0 +1,135 @@
---
title: Toggle Group
description: A set of two-state buttons that can be toggled on or off.
base: base
component: true
links:
doc: https://base-ui.com/react/components/toggle-group
api: https://base-ui.com/react/components/toggle-group#api-reference
---
<ComponentPreview styleName="base-nova" name="toggle-group-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add toggle-group
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="toggle-group"
title="components/ui/toggle-group.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
```
```tsx
<ToggleGroup type="single">
<ToggleGroupItem value="a">A</ToggleGroupItem>
<ToggleGroupItem value="b">B</ToggleGroupItem>
<ToggleGroupItem value="c">C</ToggleGroupItem>
</ToggleGroup>
```
## Composition
Use the following composition to build a `ToggleGroup`:
```text
ToggleGroup
├── ToggleGroupItem
└── ToggleGroupItem
```
## Outline
Use `variant="outline"` for an outline style.
<ComponentPreview styleName="base-nova" name="toggle-group-outline" />
## Size
Use the `size` prop to change the size of the toggle group.
<ComponentPreview styleName="base-nova" name="toggle-group-sizes" />
## Spacing
Use `spacing` to add spacing between toggle group items.
<ComponentPreview styleName="base-nova" name="toggle-group-spacing" />
## Vertical
Use `orientation="vertical"` for vertical toggle groups.
<ComponentPreview styleName="base-nova" name="toggle-group-vertical" />
## Disabled
<ComponentPreview styleName="base-nova" name="toggle-group-disabled" />
## Custom
A custom toggle group example.
<ComponentPreview
styleName="base-nova"
name="toggle-group-font-weight-selector"
previewClassName="*:data-[slot=field]:max-w-xs"
/>
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="toggle-group-rtl"
direction="rtl"
/>
## API Reference
See the [Base UI Toggle Group](https://base-ui.com/react/components/toggle-group#api-reference) documentation.
## Changelog
### 2026-05-17 Default Spacing
Changed the default `spacing` from `0` to `2` so toggle groups render with space between items by default. Use `spacing={0}` for connected items.

View File

@@ -0,0 +1,93 @@
---
title: Toggle
description: A two-state button that can be either on or off.
base: base
component: true
links:
doc: https://base-ui.com/react/components/toggle
api: https://base-ui.com/react/components/toggle#api-reference
---
<ComponentPreview styleName="base-nova" name="toggle-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
```bash
npx shadcn@latest add toggle
```
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="toggle"
title="components/ui/toggle.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx
import { Toggle } from "@/components/ui/toggle"
```
```tsx
<Toggle>Toggle</Toggle>
```
## Outline
Use `variant="outline"` for an outline style.
<ComponentPreview styleName="base-nova" name="toggle-outline" />
## With Text
<ComponentPreview styleName="base-nova" name="toggle-text" />
## Size
Use the `size` prop to change the size of the toggle.
<ComponentPreview styleName="base-nova" name="toggle-sizes" />
## Disabled
<ComponentPreview styleName="base-nova" name="toggle-disabled" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="toggle-rtl" direction="rtl" />
## API Reference
See the [Base UI Toggle](https://base-ui.com/react/components/toggle#api-reference) documentation.

View File

@@ -0,0 +1,146 @@
---
title: Tooltip
description: A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
base: base
component: true
links:
doc: https://base-ui.com/react/components/tooltip
api: https://base-ui.com/react/components/tooltip#api-reference
---
<ComponentPreview styleName="base-nova" name="tooltip-demo" />
## Installation
<CodeTabs>
<TabsList>
<TabsTrigger value="cli">Command</TabsTrigger>
<TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">
<Steps className="mb-0 pt-2">
<Step>Run the following command:</Step>
```bash
npx shadcn@latest add tooltip
```
<Step>Add the `TooltipProvider` to the root of your app.</Step>
```tsx title="app/layout.tsx" showLineNumbers {1,7}
import { TooltipProvider } from "@/components/ui/tooltip"
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<TooltipProvider>{children}</TooltipProvider>
</body>
</html>
)
}
```
</Steps>
</TabsContent>
<TabsContent value="manual">
<Steps className="mb-0 pt-2">
<Step>Install the following dependencies:</Step>
```bash
npm install @base-ui/react
```
<Step>Copy and paste the following code into your project.</Step>
<ComponentSource
name="tooltip"
title="components/ui/tooltip.tsx"
styleName="base-nova"
/>
<Step>Update the import paths to match your project setup.</Step>
<Step>Add the `TooltipProvider` to the root of your app.</Step>
```tsx title="app/layout.tsx" showLineNumbers {1,7}
import { TooltipProvider } from "@/components/ui/tooltip"
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
<TooltipProvider>{children}</TooltipProvider>
</body>
</html>
)
}
```
</Steps>
</TabsContent>
</CodeTabs>
## Usage
```tsx showLineNumbers
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip"
```
```tsx showLineNumbers
<Tooltip>
<TooltipTrigger>Hover</TooltipTrigger>
<TooltipContent>
<p>Add to library</p>
</TooltipContent>
</Tooltip>
```
## Composition
Use the following composition to build a `Tooltip`:
```text
Tooltip
├── TooltipTrigger
└── TooltipContent
```
## Side
Use the `side` prop to change the position of the tooltip.
<ComponentPreview styleName="base-nova" name="tooltip-sides" />
## With Keyboard Shortcut
<ComponentPreview styleName="base-nova" name="tooltip-keyboard" />
## Disabled Button
Show a tooltip on a disabled button by wrapping it with a span.
<ComponentPreview styleName="base-nova" name="tooltip-disabled" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview styleName="base-nova" name="tooltip-rtl" direction="rtl" />
## API Reference
See the [Base UI Tooltip](https://base-ui.com/react/components/tooltip#api-reference) documentation.

View File

@@ -0,0 +1,78 @@
---
title: Typography
description: Styles for headings, paragraphs, lists, etc.
base: base
component: true
---
We do not ship any typography styles by default. This page is an example of how you can use utility classes to style your text.
<ComponentPreview
styleName="base-nova"
name="typography-demo"
className="[&_.preview]:h-auto!"
hideCode
/>
## h1
<ComponentPreview styleName="base-nova" name="typography-h1" />
## h2
<ComponentPreview styleName="base-nova" name="typography-h2" />
## h3
<ComponentPreview styleName="base-nova" name="typography-h3" />
## h4
<ComponentPreview styleName="base-nova" name="typography-h4" />
## p
<ComponentPreview styleName="base-nova" name="typography-p" />
## blockquote
<ComponentPreview styleName="base-nova" name="typography-blockquote" />
## table
<ComponentPreview styleName="base-nova" name="typography-table" />
## list
<ComponentPreview styleName="base-nova" name="typography-list" />
## Inline code
<ComponentPreview styleName="base-nova" name="typography-inline-code" />
## Lead
<ComponentPreview styleName="base-nova" name="typography-lead" />
## Large
<ComponentPreview styleName="base-nova" name="typography-large" />
## Small
<ComponentPreview styleName="base-nova" name="typography-small" />
## Muted
<ComponentPreview styleName="base-nova" name="typography-muted" />
## RTL
To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl).
<ComponentPreview
styleName="base-nova"
name="typography-rtl"
direction="rtl"
className="[&_.preview]:h-auto!"
/>