snapshot of https://github.com/shadcn-ui/ui.git (main, 2026-09-15; blobs > 131072B omitted)
This commit is contained in:
165
apps/v4/content/docs/components/base/accordion.mdx
Normal file
165
apps/v4/content/docs/components/base/accordion.mdx
Normal 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.
|
||||
185
apps/v4/content/docs/components/base/alert-dialog.mdx
Normal file
185
apps/v4/content/docs/components/base/alert-dialog.mdx
Normal 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).
|
||||
169
apps/v4/content/docs/components/base/alert.mdx
Normal file
169
apps/v4/content/docs/components/base/alert.mdx
Normal 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` | - |
|
||||
102
apps/v4/content/docs/components/base/aspect-ratio.mdx
Normal file
102
apps/v4/content/docs/components/base/aspect-ratio.mdx
Normal 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).
|
||||
302
apps/v4/content/docs/components/base/attachment.mdx
Normal file
302
apps/v4/content/docs/components/base/attachment.mdx
Normal 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. |
|
||||
220
apps/v4/content/docs/components/base/avatar.mdx
Normal file
220
apps/v4/content/docs/components/base/avatar.mdx
Normal 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).
|
||||
101
apps/v4/content/docs/components/base/badge.mdx
Normal file
101
apps/v4/content/docs/components/base/badge.mdx
Normal 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` | - |
|
||||
202
apps/v4/content/docs/components/base/breadcrumb.mdx
Normal file
202
apps/v4/content/docs/components/base/breadcrumb.mdx
Normal 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` | - |
|
||||
298
apps/v4/content/docs/components/base/bubble.mdx
Normal file
298
apps/v4/content/docs/components/base/bubble.mdx
Normal 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. |
|
||||
241
apps/v4/content/docs/components/base/button-group.mdx
Normal file
241
apps/v4/content/docs/components/base/button-group.mdx
Normal 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>
|
||||
)
|
||||
}
|
||||
```
|
||||
161
apps/v4/content/docs/components/base/button.mdx
Normal file
161
apps/v4/content/docs/components/base/button.mdx
Normal 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"` |
|
||||
402
apps/v4/content/docs/components/base/calendar.mdx
Normal file
402
apps/v4/content/docs/components/base/calendar.mdx
Normal 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} />
|
||||
```
|
||||
267
apps/v4/content/docs/components/base/card.mdx
Normal file
267
apps/v4/content/docs/components/base/card.mdx
Normal 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>
|
||||
}
|
||||
```
|
||||
333
apps/v4/content/docs/components/base/carousel.mdx
Normal file
333
apps/v4/content/docs/components/base/carousel.mdx
Normal 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.
|
||||
602
apps/v4/content/docs/components/base/chart.mdx
Normal file
602
apps/v4/content/docs/components/base/chart.mdx
Normal 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"
|
||||
/>
|
||||
136
apps/v4/content/docs/components/base/checkbox.mdx
Normal file
136
apps/v4/content/docs/components/base/checkbox.mdx
Normal 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.
|
||||
142
apps/v4/content/docs/components/base/collapsible.mdx
Normal file
142
apps/v4/content/docs/components/base/collapsible.mdx
Normal 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.
|
||||
326
apps/v4/content/docs/components/base/combobox.mdx
Normal file
326
apps/v4/content/docs/components/base/combobox.mdx
Normal 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.
|
||||
153
apps/v4/content/docs/components/base/command.mdx
Normal file
153
apps/v4/content/docs/components/base/command.mdx
Normal 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.
|
||||
193
apps/v4/content/docs/components/base/context-menu.mdx
Normal file
193
apps/v4/content/docs/components/base/context-menu.mdx
Normal 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.
|
||||
901
apps/v4/content/docs/components/base/data-table.mdx
Normal file
901
apps/v4/content/docs/components/base/data-table.mdx
Normal 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
|
||||
/>
|
||||
116
apps/v4/content/docs/components/base/date-picker.mdx
Normal file
116
apps/v4/content/docs/components/base/date-picker.mdx
Normal 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"
|
||||
/>
|
||||
134
apps/v4/content/docs/components/base/dialog.mdx
Normal file
134
apps/v4/content/docs/components/base/dialog.mdx
Normal 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.
|
||||
93
apps/v4/content/docs/components/base/direction.mdx
Normal file
93
apps/v4/content/docs/components/base/direction.mdx
Normal 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>
|
||||
}
|
||||
```
|
||||
325
apps/v4/content/docs/components/base/drawer.mdx
Normal file
325
apps/v4/content/docs/components/base/drawer.mdx
Normal 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.
|
||||
205
apps/v4/content/docs/components/base/dropdown-menu.mdx
Normal file
205
apps/v4/content/docs/components/base/dropdown-menu.mdx
Normal 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.
|
||||
240
apps/v4/content/docs/components/base/empty.mdx
Normal file
240
apps/v4/content/docs/components/base/empty.mdx
Normal 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>
|
||||
```
|
||||
404
apps/v4/content/docs/components/base/field.mdx
Normal file
404
apps/v4/content/docs/components/base/field.mdx
Normal 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.
|
||||
144
apps/v4/content/docs/components/base/hover-card.mdx
Normal file
144
apps/v4/content/docs/components/base/hover-card.mdx
Normal 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.
|
||||
316
apps/v4/content/docs/components/base/input-group.mdx
Normal file
316
apps/v4/content/docs/components/base/input-group.mdx
Normal 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>
|
||||
```
|
||||
172
apps/v4/content/docs/components/base/input-otp.mdx
Normal file
172
apps/v4/content/docs/components/base/input-otp.mdx
Normal 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.
|
||||
199
apps/v4/content/docs/components/base/input.mdx
Normal file
199
apps/v4/content/docs/components/base/input.mdx
Normal 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"
|
||||
/>
|
||||
296
apps/v4/content/docs/components/base/item.mdx
Normal file
296
apps/v4/content/docs/components/base/item.mdx
Normal 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>
|
||||
```
|
||||
124
apps/v4/content/docs/components/base/kbd.mdx
Normal file
124
apps/v4/content/docs/components/base/kbd.mdx
Normal 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>
|
||||
```
|
||||
96
apps/v4/content/docs/components/base/label.mdx
Normal file
96
apps/v4/content/docs/components/base/label.mdx
Normal 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.
|
||||
271
apps/v4/content/docs/components/base/marker.mdx
Normal file
271
apps/v4/content/docs/components/base/marker.mdx
Normal 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. |
|
||||
161
apps/v4/content/docs/components/base/menubar.mdx
Normal file
161
apps/v4/content/docs/components/base/menubar.mdx
Normal 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.
|
||||
632
apps/v4/content/docs/components/base/message-scroller.mdx
Normal file
632
apps/v4/content/docs/components/base/message-scroller.mdx
Normal 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.
|
||||
246
apps/v4/content/docs/components/base/message.mdx
Normal file
246
apps/v4/content/docs/components/base/message.mdx
Normal 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. |
|
||||
70
apps/v4/content/docs/components/base/meta.json
Normal file
70
apps/v4/content/docs/components/base/meta.json
Normal 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"
|
||||
]
|
||||
}
|
||||
170
apps/v4/content/docs/components/base/native-select.mdx
Normal file
170
apps/v4/content/docs/components/base/native-select.mdx
Normal 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>
|
||||
```
|
||||
142
apps/v4/content/docs/components/base/navigation-menu.mdx
Normal file
142
apps/v4/content/docs/components/base/navigation-menu.mdx
Normal 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.
|
||||
210
apps/v4/content/docs/components/base/pagination.mdx
Normal file
210
apps/v4/content/docs/components/base/pagination.mdx
Normal 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>
|
||||
118
apps/v4/content/docs/components/base/popover.mdx
Normal file
118
apps/v4/content/docs/components/base/popover.mdx
Normal 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.
|
||||
112
apps/v4/content/docs/components/base/progress.mdx
Normal file
112
apps/v4/content/docs/components/base/progress.mdx
Normal 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.
|
||||
367
apps/v4/content/docs/components/base/questionnaire.mdx
Normal file
367
apps/v4/content/docs/components/base/questionnaire.mdx
Normal 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.
|
||||
127
apps/v4/content/docs/components/base/radio-group.mdx
Normal file
127
apps/v4/content/docs/components/base/radio-group.mdx
Normal 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.
|
||||
136
apps/v4/content/docs/components/base/resizable.mdx
Normal file
136
apps/v4/content/docs/components/base/resizable.mdx
Normal 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>
|
||||
99
apps/v4/content/docs/components/base/scroll-area.mdx
Normal file
99
apps/v4/content/docs/components/base/scroll-area.mdx
Normal 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.
|
||||
157
apps/v4/content/docs/components/base/select.mdx
Normal file
157
apps/v4/content/docs/components/base/select.mdx
Normal 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.
|
||||
91
apps/v4/content/docs/components/base/separator.mdx
Normal file
91
apps/v4/content/docs/components/base/separator.mdx
Normal 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.
|
||||
116
apps/v4/content/docs/components/base/sheet.mdx
Normal file
116
apps/v4/content/docs/components/base/sheet.mdx
Normal 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.
|
||||
656
apps/v4/content/docs/components/base/sidebar.mdx
Normal file
656
apps/v4/content/docs/components/base/sidebar.mdx
Normal 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.
|
||||
84
apps/v4/content/docs/components/base/skeleton.mdx
Normal file
84
apps/v4/content/docs/components/base/skeleton.mdx
Normal 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" />
|
||||
101
apps/v4/content/docs/components/base/slider.mdx
Normal file
101
apps/v4/content/docs/components/base/slider.mdx
Normal 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.
|
||||
110
apps/v4/content/docs/components/base/spinner.mdx
Normal file
110
apps/v4/content/docs/components/base/spinner.mdx
Normal 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" />
|
||||
101
apps/v4/content/docs/components/base/switch.mdx
Normal file
101
apps/v4/content/docs/components/base/switch.mdx
Normal 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.
|
||||
142
apps/v4/content/docs/components/base/table.mdx
Normal file
142
apps/v4/content/docs/components/base/table.mdx
Normal 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"
|
||||
/>
|
||||
117
apps/v4/content/docs/components/base/tabs.mdx
Normal file
117
apps/v4/content/docs/components/base/tabs.mdx
Normal 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.
|
||||
104
apps/v4/content/docs/components/base/textarea.mdx
Normal file
104
apps/v4/content/docs/components/base/textarea.mdx
Normal 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" />
|
||||
142
apps/v4/content/docs/components/base/toast.mdx
Normal file
142
apps/v4/content/docs/components/base/toast.mdx
Normal 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.
|
||||
135
apps/v4/content/docs/components/base/toggle-group.mdx
Normal file
135
apps/v4/content/docs/components/base/toggle-group.mdx
Normal 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.
|
||||
93
apps/v4/content/docs/components/base/toggle.mdx
Normal file
93
apps/v4/content/docs/components/base/toggle.mdx
Normal 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.
|
||||
146
apps/v4/content/docs/components/base/tooltip.mdx
Normal file
146
apps/v4/content/docs/components/base/tooltip.mdx
Normal 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.
|
||||
78
apps/v4/content/docs/components/base/typography.mdx
Normal file
78
apps/v4/content/docs/components/base/typography.mdx
Normal 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!"
|
||||
/>
|
||||
Reference in New Issue
Block a user