mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-24 21:25:55 +00:00
feat: update skill
This commit is contained in:
@@ -42,6 +42,7 @@ These rules are **always enforced**. See [patterns.md](./patterns.md) for full e
|
||||
11. **Toast via `sonner`.** Use `toast()` from `sonner`. Don't build custom toast/notification markup.
|
||||
12. **Pass icons as objects, not string keys.** Use `icon={CheckIcon}`, not a string key to a lookup map.
|
||||
13. **Buttons inside inputs use `InputGroup` + `InputGroupAddon`.** Never place a `Button` directly inside or adjacent to an `Input` with custom positioning. Wrap in `InputGroup` and use `InputGroupAddon` for the button.
|
||||
14. **Never decode or fetch preset codes manually.** Preset codes are opaque. Pass them directly to `shadcn init --preset <code>` and let the CLI handle resolution.
|
||||
|
||||
## Key Fields
|
||||
|
||||
@@ -79,7 +80,10 @@ shadcn docs button dialog select
|
||||
5. **Install or update** — MCP `shadcn:get_add_command_for_items` or `shadcn add`. When updating existing components, use `--dry-run` and `--diff` to preview changes first (see [Updating Components](#updating-components) below).
|
||||
6. **Fix imports in third-party components** — After adding components from community registries (e.g. `@bundui`, `@magicui`), check the added non-UI files for hardcoded import paths like `@/components/ui/...`. These won't match the project's actual aliases. Use `shadcn info` to get the correct `ui` alias (e.g. `@workspace/ui/components`) and rewrite the imports accordingly. The CLI rewrites imports for its own UI files, but third-party registry components may use default paths that don't match the project.
|
||||
7. **Verify** — MCP `shadcn:get_audit_checklist`.
|
||||
8. **Switching presets** — Before running `shadcn init --preset <code>` in an existing project, always ask the user if they'd like to reinstall existing UI components. If yes, use the `--reinstall` flag to overwrite them with the new preset styles.
|
||||
8. **Switching presets** — Ask the user first: **reinstall**, **merge**, or **skip**?
|
||||
- **Reinstall**: `shadcn init --preset <code> --force --reinstall`. Overwrites all components.
|
||||
- **Merge**: `shadcn init --preset <code> --force --no-reinstall`, then `shadcn info` to get installed components, then [smart merge](#updating-components) each one.
|
||||
- **Skip**: `shadcn init --preset <code> --force --no-reinstall`. Only updates config and CSS, leaves components as-is.
|
||||
|
||||
If MCP is unavailable, use CLI: `shadcn search`, `shadcn view`, `shadcn add`.
|
||||
|
||||
@@ -140,5 +144,6 @@ shadcn view @shadcn/button
|
||||
- [cli.md](./cli.md) — Commands, flags, presets, templates
|
||||
- [mcp.md](./mcp.md) — MCP server setup, tools, registry configuration
|
||||
- [patterns.md](./patterns.md) — UI patterns and component composition rules
|
||||
- [base-patterns.md](./base-patterns.md) — API differences between base and radix (asChild vs render, Select items, ToggleGroup type, Slider values, Accordion)
|
||||
- [customization.md](./customization.md) — Theming, CSS variables, extending components
|
||||
- [registry-authoring.md](./registry-authoring.md) — Building and publishing custom registries
|
||||
|
||||
230
skills/shadcn/base-patterns.md
Normal file
230
skills/shadcn/base-patterns.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# Base-specific patterns
|
||||
|
||||
API differences between `base` and `radix`. Check the `base` field from `shadcn info` to determine which patterns to use.
|
||||
|
||||
## Contents
|
||||
|
||||
- Composition: asChild vs render
|
||||
- Button / trigger as non-button element
|
||||
- Select
|
||||
- ToggleGroup
|
||||
- Slider
|
||||
- Accordion
|
||||
|
||||
---
|
||||
|
||||
## Composition: asChild (radix) vs render (base)
|
||||
|
||||
Radix uses `asChild` to replace the default element. Base uses `render`.
|
||||
|
||||
```tsx
|
||||
// radix.
|
||||
<DialogTrigger asChild>
|
||||
<Button>Open</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
// base.
|
||||
<DialogTrigger render={<Button />}>Open</DialogTrigger>
|
||||
```
|
||||
|
||||
This applies to all trigger and close components: `DialogTrigger`, `SheetTrigger`, `AlertDialogTrigger`, `DropdownMenuTrigger`, `PopoverTrigger`, `TooltipTrigger`, `CollapsibleTrigger`, `DialogClose`, `SheetClose`, `NavigationMenuLink`, `BreadcrumbLink`, `SidebarMenuButton`, `Badge`, `Item`.
|
||||
|
||||
---
|
||||
|
||||
## Button / trigger as non-button element (base only)
|
||||
|
||||
When `render` changes an element to a non-button (`<a>`, `<span>`), add `nativeButton={false}`.
|
||||
|
||||
```tsx
|
||||
// base — button as link.
|
||||
<Button render={<a href="/docs" />} nativeButton={false}>
|
||||
Read the docs
|
||||
</Button>
|
||||
|
||||
// radix equivalent.
|
||||
<Button asChild>
|
||||
<a href="/docs">Read the docs</a>
|
||||
</Button>
|
||||
```
|
||||
|
||||
Same for triggers whose `render` is not a `Button`:
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<PopoverTrigger render={<InputGroupAddon />} nativeButton={false}>
|
||||
Pick date
|
||||
</PopoverTrigger>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Select
|
||||
|
||||
**items prop (base only).** Base requires an `items` prop on the root. Radix uses inline JSX only.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
const items = [
|
||||
{ label: "Select a fruit", value: null },
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
]
|
||||
|
||||
<Select items={items}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
// radix.
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
```
|
||||
|
||||
**Placeholder.** Base uses a `{ value: null }` item in the items array. Radix uses `<SelectValue placeholder="...">`.
|
||||
|
||||
**Multiple selection and object values (base only).** Base supports `multiple`, render-function children on `SelectValue`, and object values with `itemToStringValue`. Radix is single-select with string values only.
|
||||
|
||||
```tsx
|
||||
// base — multiple selection.
|
||||
<Select items={items} multiple defaultValue={[]}>
|
||||
<SelectTrigger>
|
||||
<SelectValue>
|
||||
{(value: string[]) => value.length === 0 ? "Select fruits" : `${value.length} selected`}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
...
|
||||
</Select>
|
||||
|
||||
// base — object values.
|
||||
<Select defaultValue={plans[0]} itemToStringValue={(plan) => plan.name}>
|
||||
<SelectTrigger>
|
||||
<SelectValue>{(value) => value.name}</SelectValue>
|
||||
</SelectTrigger>
|
||||
...
|
||||
</Select>
|
||||
```
|
||||
|
||||
**Content positioning.** Base uses `alignItemWithTrigger`. Radix uses `position`.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<SelectContent alignItemWithTrigger={false} side="bottom">
|
||||
|
||||
// radix.
|
||||
<SelectContent position="popper">
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ToggleGroup
|
||||
|
||||
Base uses a `multiple` boolean prop. Radix uses `type="single"` or `type="multiple"`.
|
||||
|
||||
```tsx
|
||||
// base — single (no prop needed), defaultValue is always an array.
|
||||
<ToggleGroup defaultValue={["daily"]} spacing={2}>
|
||||
<ToggleGroupItem value="daily">Daily</ToggleGroupItem>
|
||||
<ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
|
||||
// base — multi-selection.
|
||||
<ToggleGroup multiple>
|
||||
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
|
||||
// radix — single, defaultValue is a string.
|
||||
<ToggleGroup type="single" defaultValue="daily" spacing={2}>
|
||||
<ToggleGroupItem value="daily">Daily</ToggleGroupItem>
|
||||
<ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
|
||||
// radix — multi-selection.
|
||||
<ToggleGroup type="multiple">
|
||||
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
```
|
||||
|
||||
**Controlled single value.** Base wraps/unwraps arrays. Radix uses a plain string.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
const [value, setValue] = React.useState("normal")
|
||||
<ToggleGroup value={[value]} onValueChange={(v) => setValue(v[0])}>
|
||||
|
||||
// radix.
|
||||
const [value, setValue] = React.useState("normal")
|
||||
<ToggleGroup type="single" value={value} onValueChange={setValue}>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Slider
|
||||
|
||||
Base accepts a plain number for a single thumb. Radix always requires an array.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<Slider defaultValue={50} max={100} step={1} />
|
||||
|
||||
// radix.
|
||||
<Slider defaultValue={[50]} max={100} step={1} />
|
||||
```
|
||||
|
||||
Both use arrays for range sliders. Controlled `onValueChange` in base may need a cast.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
const [value, setValue] = React.useState([0.3, 0.7])
|
||||
<Slider value={value} onValueChange={(v) => setValue(v as number[])} />
|
||||
|
||||
// radix.
|
||||
const [value, setValue] = React.useState([0.3, 0.7])
|
||||
<Slider value={value} onValueChange={setValue} />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Accordion
|
||||
|
||||
Radix requires `type="single"` or `type="multiple"` and supports `collapsible`. `defaultValue` is a string.
|
||||
|
||||
```tsx
|
||||
// radix.
|
||||
<Accordion type="single" collapsible defaultValue="item-1">
|
||||
<AccordionItem value="item-1">...</AccordionItem>
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
Base uses no `type` prop. Use `multiple` for multi-select. `defaultValue` is an array.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<Accordion defaultValue={["item-1"]}>
|
||||
<AccordionItem value="item-1">...</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
// base — multi-select.
|
||||
<Accordion multiple defaultValue={["item-1", "item-2"]}>
|
||||
<AccordionItem value="item-1">...</AccordionItem>
|
||||
<AccordionItem value="item-2">...</AccordionItem>
|
||||
</Accordion>
|
||||
```
|
||||
@@ -239,6 +239,8 @@ Three ways to specify a preset via `--preset`:
|
||||
2. **Code:** `--preset a2r6bw` (base62 string, starts with lowercase `a`)
|
||||
3. **URL:** `--preset "https://ui.shadcn.com/init?base=radix&style=nova&..."`
|
||||
|
||||
> **IMPORTANT:** Never try to decode, fetch, or resolve preset codes manually. Preset codes are opaque — pass them directly to `shadcn init --preset <code>` and let the CLI handle resolution.
|
||||
|
||||
### Named Presets
|
||||
|
||||
| Name | Base | Style | Font | Icon Library |
|
||||
@@ -266,11 +268,8 @@ Both use neutral base color, neutral theme, default radius, subtle menu accent,
|
||||
|
||||
## Switching Presets
|
||||
|
||||
To change an existing project's preset:
|
||||
Ask the user first: **reinstall**, **merge**, or **skip** existing components?
|
||||
|
||||
```bash
|
||||
shadcn init --preset a2r6bw --force
|
||||
shadcn init --reinstall # optional: update existing components
|
||||
```
|
||||
|
||||
Always confirm with the user before `--reinstall` — it overwrites component files.
|
||||
- **Reinstall** → `shadcn init --preset <code> --force --reinstall`. Overwrites all component files with the new preset styles. Use when the user hasn't customized components.
|
||||
- **Merge** → `shadcn init --preset <code> --force --no-reinstall`, then run `shadcn info` to get the list of installed components and use the [smart merge workflow](./SKILL.md#updating-components) to update them one by one, preserving local changes. Use when the user has customized components.
|
||||
- **Skip** → `shadcn init --preset <code> --force --no-reinstall`. Only updates config and CSS variables, leaves existing components as-is.
|
||||
|
||||
@@ -13,7 +13,8 @@ Rules and examples for composing shadcn/ui components.
|
||||
- Overlays
|
||||
- Empty states
|
||||
- Toast notifications
|
||||
- Base-specific patterns
|
||||
|
||||
**Base-conditional API differences**: See [base-patterns.md](./base-patterns.md) for `asChild` vs `render`, Select `items` prop, ToggleGroup `type` vs `multiple`, Slider value types, and Accordion differences.
|
||||
|
||||
---
|
||||
|
||||
@@ -100,25 +101,15 @@ Use `Field orientation="horizontal"` for inline label + control layouts (e.g. se
|
||||
|
||||
## Toggle Groups
|
||||
|
||||
Use `ToggleGroup` + `ToggleGroupItem` when the user picks from a small set of options (2–7). Don't manually loop `Button` components with active state.
|
||||
Use `ToggleGroup` + `ToggleGroupItem` when the user picks from a small set of options (2–7). Don't manually loop `Button` components with active state. See [base-patterns.md](./base-patterns.md#togglegroup) for `type` vs `multiple` prop differences.
|
||||
|
||||
```tsx
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
|
||||
|
||||
// Single selection (e.g. schedule type).
|
||||
<ToggleGroup defaultValue={["daily"]} spacing={2}>
|
||||
<ToggleGroup spacing={2}>
|
||||
<ToggleGroupItem value="daily">Daily</ToggleGroupItem>
|
||||
<ToggleGroupItem value="interval">Interval</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
|
||||
// Multi-selection (e.g. weekday picker).
|
||||
<ToggleGroup value={activeDays} onValueChange={setActiveDays} spacing={2}>
|
||||
{["Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"].map((day) => (
|
||||
<ToggleGroupItem key={day} value={day} className="size-7 rounded-full text-xs">
|
||||
{day}
|
||||
</ToggleGroupItem>
|
||||
))}
|
||||
</ToggleGroup>
|
||||
```
|
||||
|
||||
Combine with `Field` for labelled toggle groups:
|
||||
@@ -126,7 +117,7 @@ Combine with `Field` for labelled toggle groups:
|
||||
```tsx
|
||||
<Field orientation="horizontal">
|
||||
<FieldTitle id="theme-label">Theme</FieldTitle>
|
||||
<ToggleGroup aria-labelledby="theme-label" defaultValue={["system"]} spacing={2}>
|
||||
<ToggleGroup aria-labelledby="theme-label" spacing={2}>
|
||||
<ToggleGroupItem value="light">Light</ToggleGroupItem>
|
||||
<ToggleGroupItem value="dark">Dark</ToggleGroupItem>
|
||||
<ToggleGroupItem value="system">System</ToggleGroupItem>
|
||||
@@ -134,6 +125,8 @@ Combine with `Field` for labelled toggle groups:
|
||||
</Field>
|
||||
```
|
||||
|
||||
> **Note:** `defaultValue` and `type`/`multiple` props differ between base and radix. See [base-patterns.md](./base-patterns.md#togglegroup).
|
||||
|
||||
---
|
||||
|
||||
## Alerts
|
||||
@@ -201,246 +194,6 @@ toast("File deleted.", {
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Base-Specific Patterns
|
||||
|
||||
Check the `base` field from `shadcn info` to determine which patterns to use.
|
||||
|
||||
### Composition: asChild (radix) vs render (base)
|
||||
|
||||
Radix uses `asChild` to replace the default element. Base UI uses `render` instead.
|
||||
|
||||
```tsx
|
||||
// radix.
|
||||
<DialogTrigger asChild>
|
||||
<Button>Open</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
// base.
|
||||
<DialogTrigger render={<Button />}>Open</DialogTrigger>
|
||||
```
|
||||
|
||||
```tsx
|
||||
// radix.
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" size="icon">Menu</Button>
|
||||
</DropdownMenuTrigger>
|
||||
|
||||
// base.
|
||||
<DropdownMenuTrigger render={<Button variant="ghost" size="icon" />}>
|
||||
Menu
|
||||
</DropdownMenuTrigger>
|
||||
```
|
||||
|
||||
### Button as a link (base only)
|
||||
|
||||
When `render` changes a `Button` to a non-button element (`<a>`, `<span>`), add `nativeButton={false}` so Base UI doesn't apply button-specific behavior.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<Button render={<a href="/docs" />} nativeButton={false}>
|
||||
Read the docs
|
||||
</Button>
|
||||
|
||||
// radix equivalent.
|
||||
<Button asChild>
|
||||
<a href="/docs">Read the docs</a>
|
||||
</Button>
|
||||
```
|
||||
|
||||
### Non-button trigger elements (base only)
|
||||
|
||||
When a trigger's `render` is not a `Button` (e.g. `InputGroupAddon`), add `nativeButton={false}`.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<PopoverTrigger render={<InputGroupAddon />} nativeButton={false}>
|
||||
Pick date
|
||||
</PopoverTrigger>
|
||||
```
|
||||
|
||||
### Select (base vs radix)
|
||||
|
||||
**items prop (base only).** Base `Select` requires an `items` prop on the root. Radix uses JSX only — no `items` prop.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
const items = [
|
||||
{ label: "Select a fruit", value: null },
|
||||
{ label: "Apple", value: "apple" },
|
||||
{ label: "Banana", value: "banana" },
|
||||
]
|
||||
|
||||
<Select items={items}>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{items.map((item) => (
|
||||
<SelectItem key={item.value} value={item.value}>{item.label}</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
// radix.
|
||||
<Select>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a fruit" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="banana">Banana</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
```
|
||||
|
||||
**Placeholder.** Base uses a `{ value: null }` item in the items array. Radix uses `<SelectValue placeholder="...">`.
|
||||
|
||||
**Multiple selection (base only).** Base supports `multiple` and render-function children on `SelectValue`. Radix has no multi-select.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<Select items={items} multiple defaultValue={[]}>
|
||||
<SelectTrigger>
|
||||
<SelectValue>
|
||||
{(value: string[]) => {
|
||||
if (value.length === 0) return "Select fruits"
|
||||
return `${value.length} selected`
|
||||
}}
|
||||
</SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>...</SelectContent>
|
||||
</Select>
|
||||
```
|
||||
|
||||
**Object values (base only).** Base supports object values with `itemToStringValue` and a render function on `SelectValue`. Radix uses string values only.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<Select
|
||||
defaultValue={plans[0]}
|
||||
itemToStringValue={(plan) => plan.name}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue>{(value) => value.name}</SelectValue>
|
||||
</SelectTrigger>
|
||||
...
|
||||
</Select>
|
||||
|
||||
// radix — string values, controlled state.
|
||||
const [plan, setPlan] = React.useState<string>("starter")
|
||||
<Select value={plan} onValueChange={setPlan}>...</Select>
|
||||
```
|
||||
|
||||
**Content positioning.** Base uses `alignItemWithTrigger`. Radix uses `position`.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<SelectContent alignItemWithTrigger={false} side="bottom">
|
||||
|
||||
// radix.
|
||||
<SelectContent position="popper">
|
||||
```
|
||||
|
||||
### ToggleGroup: multiple (base) vs type (radix)
|
||||
|
||||
Base uses a `multiple` boolean prop. Radix uses `type="single"` or `type="multiple"`.
|
||||
|
||||
```tsx
|
||||
// base — single selection (no prop needed).
|
||||
<ToggleGroup defaultValue={["daily"]} spacing={2}>
|
||||
<ToggleGroupItem value="daily">Daily</ToggleGroupItem>
|
||||
<ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
|
||||
// base — multi-selection.
|
||||
<ToggleGroup multiple>
|
||||
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
|
||||
// radix — single selection.
|
||||
<ToggleGroup type="single" defaultValue="daily" spacing={2}>
|
||||
<ToggleGroupItem value="daily">Daily</ToggleGroupItem>
|
||||
<ToggleGroupItem value="weekly">Weekly</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
|
||||
// radix — multi-selection.
|
||||
<ToggleGroup type="multiple">
|
||||
<ToggleGroupItem value="bold">Bold</ToggleGroupItem>
|
||||
<ToggleGroupItem value="italic">Italic</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
```
|
||||
|
||||
**defaultValue / value type.** Base always uses arrays. Radix uses string for single, array for multiple.
|
||||
|
||||
```tsx
|
||||
// base — controlled single.
|
||||
const [value, setValue] = React.useState("normal")
|
||||
<ToggleGroup value={[value]} onValueChange={(v) => setValue(v[0])}>
|
||||
|
||||
// radix — controlled single.
|
||||
const [value, setValue] = React.useState("normal")
|
||||
<ToggleGroup type="single" value={value} onValueChange={setValue}>
|
||||
```
|
||||
|
||||
### Slider: defaultValue (base vs radix)
|
||||
|
||||
Base accepts a plain number for a single thumb. Radix always requires an array.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<Slider defaultValue={50} max={100} step={1} />
|
||||
|
||||
// radix.
|
||||
<Slider defaultValue={[50]} max={100} step={1} />
|
||||
```
|
||||
|
||||
Both use arrays for range sliders. Controlled `onValueChange` in base may need a cast.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
const [value, setValue] = React.useState([0.3, 0.7])
|
||||
<Slider value={value} onValueChange={(v) => setValue(v as number[])} />
|
||||
|
||||
// radix.
|
||||
const [value, setValue] = React.useState([0.3, 0.7])
|
||||
<Slider value={value} onValueChange={setValue} />
|
||||
```
|
||||
|
||||
### Accordion: type prop (radix only)
|
||||
|
||||
Radix requires `type="single"` or `type="multiple"` and supports `collapsible`. The `defaultValue` is a string.
|
||||
|
||||
```tsx
|
||||
// radix.
|
||||
<Accordion type="single" collapsible defaultValue="item-1">
|
||||
<AccordionItem value="item-1">...</AccordionItem>
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
Base uses no `type` prop. Use the `multiple` prop for multi-select. The `defaultValue` is an array.
|
||||
|
||||
```tsx
|
||||
// base.
|
||||
<Accordion defaultValue={["item-1"]}>
|
||||
<AccordionItem value="item-1">...</AccordionItem>
|
||||
</Accordion>
|
||||
|
||||
// base multi-select.
|
||||
<Accordion multiple defaultValue={["item-1", "item-2"]}>
|
||||
<AccordionItem value="item-1">...</AccordionItem>
|
||||
<AccordionItem value="item-2">...</AccordionItem>
|
||||
</Accordion>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
For composition rules (asChild/render, className usage, Groups, data-icon, InputGroup, etc.), see the **Critical Rules** section in [SKILL.md](./SKILL.md#critical-rules).
|
||||
For className usage, Groups, data-icon, InputGroup, and other composition rules, see the **Critical Rules** section in [SKILL.md](./SKILL.md#critical-rules). For asChild/render and other base-conditional APIs, see [base-patterns.md](./base-patterns.md).
|
||||
|
||||
Reference in New Issue
Block a user