mirror of
https://github.com/shadcn-ui/ui.git
synced 2026-06-27 22:54:18 +00:00
feat: add shadcn skills
This commit is contained in:
5
.changeset/forty-lions-repair.md
Normal file
5
.changeset/forty-lions-repair.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"shadcn": minor
|
||||
---
|
||||
|
||||
add shadcn/skills
|
||||
128
skills/shadcn/SKILL.md
Normal file
128
skills/shadcn/SKILL.md
Normal file
@@ -0,0 +1,128 @@
|
||||
---
|
||||
name: shadcn
|
||||
description: Manages shadcn/ui components — adding, searching, fixing, debugging, styling, and composing UI. Provides project context, component docs, and usage examples. Applies when working with shadcn/ui, component registries, presets, --preset codes, or any project with a components.json file. Also triggers for "shadcn init", "create an app with --preset", or "switch to --preset".
|
||||
user-invocable: false
|
||||
---
|
||||
|
||||
# shadcn/ui
|
||||
|
||||
Copy-paste component library. Components are added as source code to the user's project via the CLI or MCP tools.
|
||||
|
||||
> **IMPORTANT:** Always use the `shadcn` command directly. Never prefix with `npx`, `pnpm dlx`, or any package runner.
|
||||
|
||||
## Current Project Context
|
||||
|
||||
```json
|
||||
!`shadcn info --json 2>/dev/null || echo '{"error": "No shadcn project found. Run shadcn init first."}'`
|
||||
```
|
||||
|
||||
The JSON above contains the project config and installed components. Use `shadcn docs <component>` to get documentation and example URLs for any component.
|
||||
|
||||
## Principles
|
||||
|
||||
1. **Use existing components first.** Check registries via MCP or `shadcn search` before writing custom UI. Check community registries too.
|
||||
2. **Compose, don't reinvent.** Settings page = Tabs + Card + form controls. Dashboard = Sidebar + Card + Chart + Table.
|
||||
3. **Use built-in variants before custom styles.** `variant="outline"`, `size="sm"`, etc.
|
||||
4. **Use semantic colors.** `bg-primary`, `text-muted-foreground` — never raw values like `bg-blue-500`.
|
||||
|
||||
## Critical Rules
|
||||
|
||||
These rules are **always enforced**. See [patterns.md](./patterns.md) for full examples.
|
||||
|
||||
1. **Forms use `FieldGroup` + `Field`.** Never use raw `div` with `space-y-*` or `grid gap-*` for form layout.
|
||||
2. **Items always inside their Group.** `SelectItem`/`SelectLabel` → `SelectGroup`. `DropdownMenuItem`/`DropdownMenuLabel`/`DropdownMenuSub` → `DropdownMenuGroup`. `MenubarItem` → `MenubarGroup`. `ContextMenuItem` → `ContextMenuGroup`. `CommandItem` → `CommandGroup`.
|
||||
3. **Icons in `Button` use `data-icon`.** Add `data-icon="inline-start"` (prefix) or `data-icon="inline-end"` (suffix). No sizing classes on the icon.
|
||||
4. **`InputGroup` uses `InputGroupInput`/`InputGroupTextarea`.** Never use raw `Input` or `Textarea` inside an `InputGroup`.
|
||||
5. **Option sets (2–7 choices) use `ToggleGroup`.** Don't loop `Button` components with manual active state.
|
||||
6. **Callouts use `Alert`.** Don't build custom styled `div` containers for info/warning messages.
|
||||
7. **Empty states use `Empty`.** Don't build custom empty state markup.
|
||||
8. **Use existing components before custom markup.** Check if a component exists before writing a styled `div`.
|
||||
9. **`className` for layout, not styling.** Add layout utilities (`w-full`, `grid`, `flex`, `gap-*`) but never override component colors or typography.
|
||||
10. **Use `asChild` (radix) or `render` (base) for custom triggers.** Don't wrap triggers in extra elements. Check the `base` field from `shadcn info` to determine which prop to use.
|
||||
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.
|
||||
|
||||
## Key Fields
|
||||
|
||||
The injected project context contains these key fields:
|
||||
|
||||
- **`aliases`** → use the actual alias prefix for imports (e.g. `@/`, `~/`), never hardcode.
|
||||
- **`isRSC`** → when `true`, components using `useState`, `useEffect`, event handlers, or browser APIs need `"use client"`.
|
||||
- **`tailwindVersion`** → `"v4"` uses `@theme inline` blocks; `"v3"` uses `tailwind.config.js`.
|
||||
- **`tailwindCssFile`** → the global CSS file where custom CSS variables are defined. Always edit this file, never create a new one.
|
||||
- **`style`** → component visual treatment (e.g. `nova`, `vega`).
|
||||
- **`base`** → primitive library (`radix` or `base`). Affects component APIs and available props.
|
||||
- **`iconLibrary`** → determines icon imports. Use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, etc. Never assume `lucide-react`.
|
||||
- **`resolvedPaths`** → exact file-system destinations for components, utils, hooks, etc.
|
||||
- **`framework`** → routing and file conventions (e.g. Next.js App Router vs Vite SPA).
|
||||
- **`packageManager`** → use this for any non-shadcn dependency installs (e.g. `pnpm add date-fns` vs `npm install date-fns`).
|
||||
|
||||
See [cli.md — `info` command](./cli.md) for the full field reference.
|
||||
|
||||
## Component Docs, Examples, and Usage
|
||||
|
||||
Run `shadcn docs <component>` to get the URLs for a component's documentation, examples, and API reference. Fetch these URLs to get the actual content.
|
||||
|
||||
```bash
|
||||
shadcn docs button dialog select
|
||||
```
|
||||
|
||||
**When creating, fixing, debugging, or using a component, always run `shadcn docs` and fetch the URLs first.** This ensures you're working with the correct API and usage patterns rather than guessing.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Get project context** — already injected above. Run `shadcn info` again if you need to refresh.
|
||||
2. **Check installed components** — look in the `resolvedPaths.ui` directory before importing or adding. Don't import components that haven't been added, and don't re-add ones already installed.
|
||||
3. **Find components** — MCP `shadcn:search_items_in_registries` or `shadcn search`.
|
||||
4. **Get docs and examples** — run `shadcn docs <component>` to get URLs, then fetch them. Alternatively use MCP `shadcn:view_items_in_registries` or `shadcn view`.
|
||||
5. **Install** — MCP `shadcn:get_add_command_for_items` or `shadcn add`.
|
||||
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.
|
||||
|
||||
If MCP is unavailable, use CLI: `shadcn search`, `shadcn view`, `shadcn add`.
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```bash
|
||||
# Create a new project.
|
||||
shadcn init --name my-app --preset base-nova
|
||||
shadcn init --name my-app --preset a2r6bw --template vite
|
||||
|
||||
# Create a monorepo project.
|
||||
shadcn init --name my-app --preset base-nova --monorepo
|
||||
shadcn init --name my-app --preset base-nova --template next --monorepo
|
||||
|
||||
# Initialize existing project.
|
||||
shadcn init --preset base-nova
|
||||
shadcn init --defaults # shortcut: --template=next --preset=base-nova
|
||||
|
||||
# Add components.
|
||||
shadcn add button card dialog
|
||||
shadcn add @magicui/shimmer-button
|
||||
shadcn add --all
|
||||
|
||||
# Search registries.
|
||||
shadcn search @shadcn -q "sidebar"
|
||||
shadcn search @blocks -q "stats"
|
||||
|
||||
# Get component docs and example URLs.
|
||||
shadcn docs button dialog select
|
||||
|
||||
# View item details.
|
||||
shadcn view @shadcn/button
|
||||
```
|
||||
|
||||
**Named presets:** `base-nova`, `radix-nova`
|
||||
**Templates:** `next`, `vite`, `start`, `react-router`, `astro` (all support `--monorepo`)
|
||||
**Preset codes:** Base62 strings starting with `a` (e.g. `a2r6bw`), from [ui.shadcn.com](https://ui.shadcn.com).
|
||||
|
||||
## Detailed References
|
||||
|
||||
- [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
|
||||
- [customization.md](./customization.md) — Theming, CSS variables, extending components
|
||||
- [registry-authoring.md](./registry-authoring.md) — Building and publishing custom registries
|
||||
5
skills/shadcn/agents/openai.yml
Normal file
5
skills/shadcn/agents/openai.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
interface:
|
||||
display_name: "shadcn/ui"
|
||||
short_description: "Manages shadcn/ui components — adding, searching, fixing, debugging, styling, and composing UI."
|
||||
icon_small: "./assets/shadcn-small.png"
|
||||
icon_large: "./assets/shadcn.png"
|
||||
BIN
skills/shadcn/assets/shadcn-small.png
Normal file
BIN
skills/shadcn/assets/shadcn-small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 KiB |
BIN
skills/shadcn/assets/shadcn.png
Normal file
BIN
skills/shadcn/assets/shadcn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
229
skills/shadcn/cli.md
Normal file
229
skills/shadcn/cli.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# shadcn CLI Reference
|
||||
|
||||
All commands use `shadcn <command>`. Configuration is read from `components.json`.
|
||||
|
||||
> **IMPORTANT:** Always use the `shadcn` command directly. Never prefix with `npx`, `pnpm dlx`, or any package runner.
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
### `init` — Initialize or create a project
|
||||
|
||||
```bash
|
||||
shadcn init [components...] [options]
|
||||
```
|
||||
|
||||
Initializes shadcn/ui in an existing project or creates a new project (when `--name` is provided). Optionally installs components in the same step.
|
||||
|
||||
| Flag | Short | Description | Default |
|
||||
|------|-------|-------------|---------|
|
||||
| `--template <template>` | `-t` | Template (next, start, vite, next-monorepo, react-router) | — |
|
||||
| `--preset [name]` | `-p` | Preset configuration (named, code, or URL) | — |
|
||||
| `--yes` | `-y` | Skip confirmation prompt | `true` |
|
||||
| `--defaults` | `-d` | Use defaults (`--template=next --preset=base-nova`) | `false` |
|
||||
| `--force` | `-f` | Force overwrite existing configuration | `false` |
|
||||
| `--cwd <cwd>` | `-c` | Working directory | current |
|
||||
| `--name <name>` | `-n` | Name for new project | — |
|
||||
| `--silent` | `-s` | Mute output | `false` |
|
||||
| `--rtl` | | Enable RTL support | — |
|
||||
| `--reinstall` | | Re-install existing UI components | `false` |
|
||||
| `--monorepo` | | Scaffold a monorepo project | — |
|
||||
| `--no-monorepo` | | Skip the monorepo prompt | — |
|
||||
|
||||
`shadcn create` is an alias for `shadcn init`.
|
||||
|
||||
### `add` — Add components
|
||||
|
||||
```bash
|
||||
shadcn add [components...] [options]
|
||||
```
|
||||
|
||||
Accepts component names, registry-prefixed names (`@magicui/shimmer-button`), URLs, or local paths.
|
||||
|
||||
| Flag | Short | Description | Default |
|
||||
|------|-------|-------------|---------|
|
||||
| `--yes` | `-y` | Skip confirmation prompt | `false` |
|
||||
| `--overwrite` | `-o` | Overwrite existing files | `false` |
|
||||
| `--cwd <cwd>` | `-c` | Working directory | current |
|
||||
| `--all` | `-a` | Add all available components | `false` |
|
||||
| `--path <path>` | `-p` | Target path for the component | — |
|
||||
| `--silent` | `-s` | Mute output | `false` |
|
||||
|
||||
### `search` — Search registries
|
||||
|
||||
```bash
|
||||
shadcn search <registries...> [options]
|
||||
```
|
||||
|
||||
Fuzzy search across registries. Also aliased as `shadcn list`. Without `-q`, lists all items.
|
||||
|
||||
| Flag | Short | Description | Default |
|
||||
|------|-------|-------------|---------|
|
||||
| `--query <query>` | `-q` | Search query | — |
|
||||
| `--limit <number>` | `-l` | Max items per registry | `100` |
|
||||
| `--offset <number>` | `-o` | Items to skip | `0` |
|
||||
| `--cwd <cwd>` | `-c` | Working directory | current |
|
||||
|
||||
### `view` — View item details
|
||||
|
||||
```bash
|
||||
shadcn view <items...> [options]
|
||||
```
|
||||
|
||||
Displays item info including file contents. Example: `shadcn view @shadcn/button`.
|
||||
|
||||
### `docs` — Get component documentation URLs
|
||||
|
||||
```bash
|
||||
shadcn docs <components...> [options]
|
||||
```
|
||||
|
||||
Outputs resolved URLs for component documentation, examples, and API references. Accepts one or more component names. Fetch the URLs to get the actual content.
|
||||
|
||||
Example output for `shadcn docs input button`:
|
||||
|
||||
```
|
||||
base radix
|
||||
|
||||
input
|
||||
docs https://ui.shadcn.com/docs/components/radix/input
|
||||
examples https://raw.githubusercontent.com/.../examples/input-example.tsx
|
||||
|
||||
button
|
||||
docs https://ui.shadcn.com/docs/components/radix/button
|
||||
examples https://raw.githubusercontent.com/.../examples/button-example.tsx
|
||||
```
|
||||
|
||||
Some components include an `api` link to the underlying library (e.g. `cmdk` for the command component).
|
||||
|
||||
### `diff` — Check for updates
|
||||
|
||||
```bash
|
||||
shadcn diff [component] [options]
|
||||
```
|
||||
|
||||
Compares local components against the registry. Without a component name, shows all with updates.
|
||||
|
||||
### `info` — Project information
|
||||
|
||||
```bash
|
||||
shadcn info [options]
|
||||
```
|
||||
|
||||
Displays project info and `components.json` configuration. Run this first to discover the project's framework, aliases, Tailwind version, and resolved paths.
|
||||
|
||||
| Flag | Short | Description | Default |
|
||||
|------|-------|-------------|---------|
|
||||
| `--cwd <cwd>` | `-c` | Working directory | current |
|
||||
|
||||
**Project Info fields:**
|
||||
|
||||
| Field | Type | Meaning |
|
||||
|-------|------|---------|
|
||||
| `framework` | `string` | Detected framework (`next`, `vite`, `react-router`, `start`, etc.) |
|
||||
| `frameworkVersion` | `string` | Framework version (e.g. `15.2.4`) |
|
||||
| `isSrcDir` | `boolean` | Whether the project uses a `src/` directory |
|
||||
| `isRSC` | `boolean` | Whether React Server Components are enabled |
|
||||
| `isTsx` | `boolean` | Whether the project uses TypeScript |
|
||||
| `tailwindVersion` | `string` | `"v3"` or `"v4"` |
|
||||
| `tailwindConfigFile` | `string` | Path to the Tailwind config file |
|
||||
| `tailwindCssFile` | `string` | Path to the global CSS file |
|
||||
| `aliasPrefix` | `string` | Import alias prefix (e.g. `@`, `~`, `@/`) |
|
||||
| `packageManager` | `string` | Detected package manager (`npm`, `pnpm`, `yarn`, `bun`) |
|
||||
|
||||
**Components.json fields:**
|
||||
|
||||
| Field | Type | Meaning |
|
||||
|-------|------|---------|
|
||||
| `base` | `string` | Primitive library (`radix` or `base`) — determines component APIs and available props |
|
||||
| `style` | `string` | Visual style (e.g. `nova`, `vega`) |
|
||||
| `rsc` | `boolean` | RSC flag from config |
|
||||
| `tsx` | `boolean` | TypeScript flag |
|
||||
| `tailwind.config` | `string` | Tailwind config path |
|
||||
| `tailwind.css` | `string` | Global CSS path — this is where custom CSS variables go |
|
||||
| `iconLibrary` | `string` | Icon library — determines icon import package (e.g. `lucide-react`, `@tabler/icons-react`) |
|
||||
| `aliases.components` | `string` | Component import alias (e.g. `@/components`) |
|
||||
| `aliases.utils` | `string` | Utils import alias (e.g. `@/lib/utils`) |
|
||||
| `aliases.ui` | `string` | UI component alias (e.g. `@/components/ui`) |
|
||||
| `aliases.lib` | `string` | Lib alias (e.g. `@/lib`) |
|
||||
| `aliases.hooks` | `string` | Hooks alias (e.g. `@/hooks`) |
|
||||
| `resolvedPaths` | `object` | Absolute file-system paths for each alias |
|
||||
| `registries` | `object` | Configured custom registries |
|
||||
|
||||
**Links fields:**
|
||||
|
||||
The `info` output includes a **Links** section with templated URLs for component docs, source, and examples. For resolved URLs, use `shadcn docs <component>` instead.
|
||||
|
||||
### `build` — Build a custom registry
|
||||
|
||||
```bash
|
||||
shadcn build [registry] [options]
|
||||
```
|
||||
|
||||
Builds `registry.json` into individual JSON files for distribution. Default input: `./registry.json`, default output: `./public/r`.
|
||||
|
||||
| Flag | Short | Description | Default |
|
||||
|------|-------|-------------|---------|
|
||||
| `--output <path>` | `-o` | Output directory | `./public/r` |
|
||||
| `--cwd <cwd>` | `-c` | Working directory | current |
|
||||
|
||||
---
|
||||
|
||||
## Templates
|
||||
|
||||
| Value | Framework | Monorepo support |
|
||||
|-------|-----------|-----------------|
|
||||
| `next` | Next.js | Yes |
|
||||
| `vite` | Vite | Yes |
|
||||
| `start` | TanStack Start | Yes |
|
||||
| `react-router` | React Router | Yes |
|
||||
| `astro` | Astro | Yes |
|
||||
|
||||
All templates support monorepo scaffolding via the `--monorepo` flag. When passed, the CLI uses a monorepo-specific template directory (e.g. `next-monorepo`, `vite-monorepo`). When neither `--monorepo` nor `--no-monorepo` is passed, the CLI prompts interactively.
|
||||
|
||||
---
|
||||
|
||||
## Presets
|
||||
|
||||
Three ways to specify a preset via `--preset`:
|
||||
|
||||
1. **Named:** `--preset base-nova` or `--preset radix-nova`
|
||||
2. **Code:** `--preset a2r6bw` (base62 string, starts with lowercase `a`)
|
||||
3. **URL:** `--preset "https://ui.shadcn.com/init?base=radix&style=nova&..."`
|
||||
|
||||
### Named Presets
|
||||
|
||||
| Name | Base | Style | Font | Icon Library |
|
||||
|------|------|-------|------|-------------|
|
||||
| `radix-nova` | radix | nova | geist | lucide |
|
||||
| `base-nova` | base | nova | geist | lucide |
|
||||
|
||||
Both use neutral base color, neutral theme, default radius, subtle menu accent, default menu color.
|
||||
|
||||
### Preset Fields
|
||||
|
||||
| Field | Valid Values | Default |
|
||||
|-------|-------------|---------|
|
||||
| `base` | `radix`, `base` | `radix` |
|
||||
| `style` | `nova`, `vega`, `maia`, `lyra`, `mira` | `nova` |
|
||||
| `baseColor` | `neutral`, `stone`, `zinc`, `gray` | `neutral` |
|
||||
| `theme` | `neutral`, `stone`, `zinc`, `gray`, `amber`, `blue`, `cyan`, `emerald`, `fuchsia`, `green`, `indigo`, `lime`, `orange`, `pink`, `purple`, `red`, `rose`, `sky`, `teal`, `violet`, `yellow` | `neutral` |
|
||||
| `iconLibrary` | `lucide`, `hugeicons`, `tabler`, `phosphor`, `remixicon` | `lucide` |
|
||||
| `font` | `inter`, `noto-sans`, `nunito-sans`, `figtree`, `roboto`, `raleway`, `dm-sans`, `public-sans`, `outfit`, `jetbrains-mono`, `geist`, `geist-mono` | `inter` |
|
||||
| `radius` | `default`, `none`, `small`, `medium`, `large` | `default` |
|
||||
| `menuAccent` | `subtle`, `bold` | `subtle` |
|
||||
| `menuColor` | `default`, `inverted` | `default` |
|
||||
|
||||
---
|
||||
|
||||
## Switching Presets
|
||||
|
||||
To change an existing project's preset:
|
||||
|
||||
```bash
|
||||
shadcn init --preset a2r6bw --force
|
||||
shadcn init --reinstall # optional: update existing components
|
||||
```
|
||||
|
||||
Always confirm with the user before `--reinstall` — it overwrites component files.
|
||||
180
skills/shadcn/customization.md
Normal file
180
skills/shadcn/customization.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# Customization & Theming
|
||||
|
||||
Components reference semantic CSS variable tokens. Change the variables to change every component.
|
||||
|
||||
---
|
||||
|
||||
## How It Works
|
||||
|
||||
1. CSS variables defined in `:root` (light) and `.dark` (dark mode).
|
||||
2. Tailwind maps them to utilities: `bg-primary`, `text-muted-foreground`, etc.
|
||||
3. Components use these utilities — changing a variable changes all components that reference it.
|
||||
|
||||
---
|
||||
|
||||
## Color Variables
|
||||
|
||||
Every color follows the `name` / `name-foreground` convention. The base variable is for backgrounds, `-foreground` is for text/icons on that background.
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `--background` / `--foreground` | Page background and default text |
|
||||
| `--card` / `--card-foreground` | Card surfaces |
|
||||
| `--primary` / `--primary-foreground` | Primary buttons and actions |
|
||||
| `--secondary` / `--secondary-foreground` | Secondary actions |
|
||||
| `--muted` / `--muted-foreground` | Muted/disabled states |
|
||||
| `--accent` / `--accent-foreground` | Hover and accent states |
|
||||
| `--destructive` / `--destructive-foreground` | Error and destructive actions |
|
||||
| `--border` | Default border color |
|
||||
| `--input` | Form input borders |
|
||||
| `--ring` | Focus ring color |
|
||||
| `--chart-1` through `--chart-5` | Chart/data visualization |
|
||||
| `--sidebar-*` | Sidebar-specific colors |
|
||||
| `--surface` / `--surface-foreground` | Secondary surface |
|
||||
|
||||
Colors use OKLCH: `--primary: oklch(0.205 0 0)` where values are lightness (0–1), chroma (0 = gray), and hue (0–360).
|
||||
|
||||
---
|
||||
|
||||
## Dark Mode
|
||||
|
||||
Class-based toggle via `.dark` on the root element. In Next.js, use `next-themes`:
|
||||
|
||||
```tsx
|
||||
import { ThemeProvider } from "next-themes"
|
||||
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
{children}
|
||||
</ThemeProvider>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Changing the Theme
|
||||
|
||||
```bash
|
||||
# Apply a preset code from ui.shadcn.com.
|
||||
shadcn init --preset a2r6bw --force
|
||||
|
||||
# Switch to a named preset.
|
||||
shadcn init --preset radix-nova --force
|
||||
shadcn init --reinstall # update existing components to match
|
||||
|
||||
# Use a custom theme URL.
|
||||
shadcn init --preset "https://ui.shadcn.com/init?base=radix&style=nova&theme=blue&..." --force
|
||||
```
|
||||
|
||||
Or edit CSS variables directly in `globals.css`.
|
||||
|
||||
---
|
||||
|
||||
## Adding Custom Colors
|
||||
|
||||
Add variables to the file at `tailwindCssFile` from `shadcn info` (typically `globals.css`). Never create a new CSS file for this.
|
||||
|
||||
```css
|
||||
/* 1. Define in the global CSS file. */
|
||||
:root {
|
||||
--warning: oklch(0.84 0.16 84);
|
||||
--warning-foreground: oklch(0.28 0.07 46);
|
||||
}
|
||||
.dark {
|
||||
--warning: oklch(0.41 0.11 46);
|
||||
--warning-foreground: oklch(0.99 0.02 95);
|
||||
}
|
||||
```
|
||||
|
||||
```css
|
||||
/* 2a. Register with Tailwind v4 (@theme inline). */
|
||||
@theme inline {
|
||||
--color-warning: var(--warning);
|
||||
--color-warning-foreground: var(--warning-foreground);
|
||||
}
|
||||
```
|
||||
|
||||
When `tailwindVersion` is `"v3"` (check via `shadcn info`), register in `tailwind.config.js` instead:
|
||||
|
||||
```js
|
||||
// 2b. Register with Tailwind v3 (tailwind.config.js).
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
warning: "oklch(var(--warning) / <alpha-value>)",
|
||||
"warning-foreground": "oklch(var(--warning-foreground) / <alpha-value>)",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
```tsx
|
||||
// 3. Use in components.
|
||||
<div className="bg-warning text-warning-foreground">Warning</div>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Border Radius
|
||||
|
||||
`--radius` controls border radius globally. Components derive values from it (`rounded-lg` = `var(--radius)`, `rounded-md` = `calc(var(--radius) - 2px)`).
|
||||
|
||||
---
|
||||
|
||||
## Customizing Components
|
||||
|
||||
Prefer these approaches in order:
|
||||
|
||||
### 1. Built-in variants
|
||||
|
||||
```tsx
|
||||
<Button variant="outline" size="sm">Click</Button>
|
||||
```
|
||||
|
||||
### 2. Tailwind classes via `className`
|
||||
|
||||
```tsx
|
||||
<Card className="max-w-md mx-auto">...</Card>
|
||||
```
|
||||
|
||||
### 3. Add a new variant
|
||||
|
||||
Edit the component source to add a variant via `cva`:
|
||||
|
||||
```tsx
|
||||
// components/ui/button.tsx
|
||||
warning: "bg-warning text-warning-foreground hover:bg-warning/90",
|
||||
```
|
||||
|
||||
### 4. Wrapper components
|
||||
|
||||
Compose shadcn/ui primitives into higher-level components:
|
||||
|
||||
```tsx
|
||||
export function ConfirmDialog({ title, description, onConfirm, children }) {
|
||||
return (
|
||||
<AlertDialog>
|
||||
<AlertDialogTrigger asChild>{children}</AlertDialogTrigger>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{title}</AlertDialogTitle>
|
||||
<AlertDialogDescription>{description}</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction onClick={onConfirm}>Confirm</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checking for Updates
|
||||
|
||||
```bash
|
||||
shadcn diff # all components with available updates
|
||||
shadcn diff button # specific component
|
||||
```
|
||||
94
skills/shadcn/mcp.md
Normal file
94
skills/shadcn/mcp.md
Normal file
@@ -0,0 +1,94 @@
|
||||
# shadcn MCP Server
|
||||
|
||||
The CLI includes an MCP server that lets AI assistants search, browse, view, and install components from registries.
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
shadcn mcp # start the MCP server (stdio)
|
||||
shadcn mcp init # write config for your editor
|
||||
```
|
||||
|
||||
Editor config files:
|
||||
|
||||
| Editor | Config file |
|
||||
|--------|------------|
|
||||
| Claude Code | `.mcp.json` |
|
||||
| Cursor | `.cursor/mcp.json` |
|
||||
| VS Code | `.vscode/mcp.json` |
|
||||
| OpenCode | `opencode.json` |
|
||||
| Codex | `~/.codex/config.toml` (manual) |
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
|
||||
> **Tip:** MCP tools handle registry operations (search, view, install). For project configuration (aliases, framework, Tailwind version), use `shadcn info` — there is no MCP equivalent.
|
||||
|
||||
### `shadcn:get_project_registries`
|
||||
|
||||
Returns registry names from `components.json`. Errors if no `components.json` exists.
|
||||
|
||||
**Input:** none
|
||||
|
||||
### `shadcn:list_items_in_registries`
|
||||
|
||||
Lists all items from one or more registries.
|
||||
|
||||
**Input:** `registries` (string[]), `limit` (number, optional), `offset` (number, optional)
|
||||
|
||||
### `shadcn:search_items_in_registries`
|
||||
|
||||
Fuzzy search across registries.
|
||||
|
||||
**Input:** `registries` (string[]), `query` (string), `limit` (number, optional), `offset` (number, optional)
|
||||
|
||||
### `shadcn:view_items_in_registries`
|
||||
|
||||
View item details including full file contents.
|
||||
|
||||
**Input:** `items` (string[]) — e.g. `["@shadcn/button", "@shadcn/card"]`
|
||||
|
||||
### `shadcn:get_item_examples_from_registries`
|
||||
|
||||
Find usage examples and demos with source code.
|
||||
|
||||
**Input:** `registries` (string[]), `query` (string) — e.g. `"accordion-demo"`, `"button example"`
|
||||
|
||||
### `shadcn:get_add_command_for_items`
|
||||
|
||||
Returns the CLI install command.
|
||||
|
||||
**Input:** `items` (string[]) — e.g. `["@shadcn/button"]`
|
||||
|
||||
### `shadcn:get_audit_checklist`
|
||||
|
||||
Returns a checklist for verifying components (imports, deps, lint, TypeScript).
|
||||
|
||||
**Input:** none
|
||||
|
||||
---
|
||||
|
||||
## Configuring Registries
|
||||
|
||||
Registries are set in `components.json`. The `@shadcn` registry is always built-in.
|
||||
|
||||
```json
|
||||
{
|
||||
"registries": {
|
||||
"@acme": "https://acme.com/r/{name}.json",
|
||||
"@private": {
|
||||
"url": "https://private.com/r/{name}.json",
|
||||
"headers": { "Authorization": "Bearer ${MY_TOKEN}" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Names must start with `@`.
|
||||
- URLs must contain `{name}`.
|
||||
- `${VAR}` references are resolved from environment variables.
|
||||
|
||||
Community registry index: `https://ui.shadcn.com/r/registries.json`
|
||||
230
skills/shadcn/patterns.md
Normal file
230
skills/shadcn/patterns.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# Component Patterns
|
||||
|
||||
Rules and examples for composing shadcn/ui components.
|
||||
|
||||
> **Note:** Examples below use `@/` as the import prefix. Always use the actual `aliasPrefix` from `shadcn info` for the target project. Similarly, icon imports depend on the project's `iconLibrary` — use `lucide-react` for `lucide`, `@tabler/icons-react` for `tabler`, `@phosphor-icons/react` for `phosphor`, etc. Never assume `lucide-react`.
|
||||
|
||||
---
|
||||
|
||||
## Component Selection
|
||||
|
||||
| Need | Use |
|
||||
|------|-----|
|
||||
| Button/action | `Button` with appropriate variant |
|
||||
| Form inputs | `Input`, `Select`, `Combobox`, `Switch`, `Checkbox`, `RadioGroup`, `Textarea`, `InputOTP`, `Slider` |
|
||||
| Toggle between 2–5 options | `ToggleGroup` + `ToggleGroupItem` |
|
||||
| Data display | `Table`, `Card`, `Badge`, `Avatar` |
|
||||
| Navigation | `Sidebar`, `NavigationMenu`, `Breadcrumb`, `Tabs`, `Pagination` |
|
||||
| Overlays | `Dialog` (modal), `Sheet` (side panel), `Drawer` (bottom sheet), `AlertDialog` (confirmation) |
|
||||
| Feedback | `sonner` (toast), `Alert`, `Progress`, `Skeleton`, `Spinner` |
|
||||
| Command palette | `Command` inside `Dialog` |
|
||||
| Charts | `Chart` (wraps Recharts) |
|
||||
| Layout | `Card`, `Separator`, `Resizable`, `ScrollArea`, `Accordion`, `Collapsible` |
|
||||
| Empty states | `Empty` |
|
||||
| Menus | `DropdownMenu`, `ContextMenu`, `Menubar` |
|
||||
| Tooltips/info | `Tooltip`, `HoverCard`, `Popover` |
|
||||
|
||||
---
|
||||
|
||||
## Forms
|
||||
|
||||
Always use `FieldGroup` and `Field` to structure forms. Never use raw `div` with `grid`/`gap` or `space-y-*` for form layout. Use `FieldLabel` for labelled inputs, `FieldTitle` for section headings, and `FieldDescription` for helper text.
|
||||
|
||||
```tsx
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Field, FieldDescription, FieldGroup, FieldLabel, FieldTitle } from "@/components/ui/field"
|
||||
import { Input } from "@/components/ui/input"
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
|
||||
import { Textarea } from "@/components/ui/textarea"
|
||||
|
||||
<form>
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="email">Email</FieldLabel>
|
||||
<Input id="email" type="email" placeholder="you@example.com" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="password">Password</FieldLabel>
|
||||
<Input id="password" type="password" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldTitle>Role</FieldTitle>
|
||||
<FieldDescription>Select the user's role in the organization.</FieldDescription>
|
||||
<Select>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Choose a role" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="admin">Admin</SelectItem>
|
||||
<SelectItem value="member">Member</SelectItem>
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel htmlFor="bio">Bio</FieldLabel>
|
||||
<Textarea id="bio" placeholder="Tell us about yourself" />
|
||||
</Field>
|
||||
<Button type="submit" className="w-full">Sign In</Button>
|
||||
</FieldGroup>
|
||||
</form>
|
||||
```
|
||||
|
||||
Use `Field orientation="horizontal"` for inline label + control layouts (e.g. settings pages). Use `FieldLabel className="sr-only"` for inputs that don't need a visible label but still need one for accessibility.
|
||||
|
||||
**Choosing form controls:**
|
||||
|
||||
- Simple text input → `Input`
|
||||
- Dropdown with predefined options → `Select`
|
||||
- Searchable dropdown → `Combobox`
|
||||
- Native HTML select (no JS) → `native-select`
|
||||
- Boolean toggle → `Switch` (for settings) or `Checkbox` (for forms)
|
||||
- Single choice from few options → `RadioGroup`
|
||||
- Toggle between 2–5 options → `ToggleGroup` + `ToggleGroupItem`
|
||||
- OTP/verification code → `InputOTP`
|
||||
- Multi-line text → `Textarea`
|
||||
|
||||
---
|
||||
|
||||
## 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.
|
||||
|
||||
```tsx
|
||||
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
|
||||
|
||||
// Single selection (e.g. schedule type).
|
||||
<ToggleGroup defaultValue={["daily"]} 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:
|
||||
|
||||
```tsx
|
||||
<Field orientation="horizontal">
|
||||
<FieldTitle id="theme-label">Theme</FieldTitle>
|
||||
<ToggleGroup aria-labelledby="theme-label" defaultValue={["system"]} spacing={2}>
|
||||
<ToggleGroupItem value="light">Light</ToggleGroupItem>
|
||||
<ToggleGroupItem value="dark">Dark</ToggleGroupItem>
|
||||
<ToggleGroupItem value="system">System</ToggleGroupItem>
|
||||
</ToggleGroup>
|
||||
</Field>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Alerts
|
||||
|
||||
Use `Alert` for informational callouts. Don't build custom styled `div` containers for info/warning messages.
|
||||
|
||||
```tsx
|
||||
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
|
||||
|
||||
<Alert>
|
||||
<AlertDescription>
|
||||
Automations run with your default sandbox settings.
|
||||
</AlertDescription>
|
||||
</Alert>
|
||||
|
||||
<Alert variant="destructive">
|
||||
<AlertTitle>Error</AlertTitle>
|
||||
<AlertDescription>Something went wrong.</AlertDescription>
|
||||
</Alert>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Overlays
|
||||
|
||||
- Focused task that requires input → `Dialog`
|
||||
- Destructive action confirmation → `AlertDialog`
|
||||
- Side panel with details or filters → `Sheet`
|
||||
- Mobile-first bottom panel → `Drawer`
|
||||
- Quick info on hover → `HoverCard`
|
||||
- Small contextual content on click → `Popover`
|
||||
|
||||
---
|
||||
|
||||
## Empty States
|
||||
|
||||
Use the `Empty` component when there's no data to display.
|
||||
|
||||
```tsx
|
||||
import { Empty, EmptyIcon, EmptyTitle, EmptyDescription, EmptyActions } from "@/components/ui/empty"
|
||||
|
||||
<Empty>
|
||||
<EmptyIcon>{/* icon */}</EmptyIcon>
|
||||
<EmptyTitle>No projects yet</EmptyTitle>
|
||||
<EmptyDescription>Get started by creating a new project.</EmptyDescription>
|
||||
<EmptyActions>
|
||||
<Button>Create Project</Button>
|
||||
</EmptyActions>
|
||||
</Empty>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Toast Notifications
|
||||
|
||||
Use `sonner`. Call `toast()` from anywhere.
|
||||
|
||||
```tsx
|
||||
import { toast } from "sonner"
|
||||
|
||||
toast.success("Changes saved.")
|
||||
toast.error("Something went wrong.")
|
||||
toast("File deleted.", {
|
||||
action: { label: "Undo", onClick: () => undoDelete() },
|
||||
})
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Composition Rules
|
||||
|
||||
1. **Use `asChild` (radix) or `render` (base) for custom triggers.** Don't wrap triggers in extra elements. Check the `base` field from `shadcn info` to determine which prop to use.
|
||||
|
||||
2. **Use `Field` components for forms, not raw divs.** Never use `div` with `space-y-*` or `grid gap-*` for form layout. Use `FieldGroup` for the form container and `Field` for each control. Use `FieldLabel` for labelled inputs, `FieldTitle` for headings, `FieldDescription` for helper text.
|
||||
|
||||
3. **Use existing UI components before custom markup.** Before writing a styled `div`, check if a component already exists: `Alert` for callouts, `ToggleGroup` for option sets, `Empty` for empty states, etc.
|
||||
|
||||
4. **Use `className` for layout, not styling.** Add layout utilities (`w-full`, `grid`, `flex`, `gap-*`) but avoid overriding component colors or typography.
|
||||
|
||||
5. **Prefer built-in variants.** Use `variant="outline"`, `variant="ghost"`, `size="sm"` etc. before adding custom classes.
|
||||
|
||||
6. **Compose, don't customize.** Build complex UIs by composing multiple simple components rather than heavily customizing a single one.
|
||||
|
||||
7. **Add `"use client"` at RSC boundaries.** When `isRSC` is `true` (from `shadcn info`), components that use `useState`, `useEffect`, event handlers (`onClick`, `onChange`, etc.), or browser APIs must start with `"use client"`. Keep client boundaries as low in the tree as possible.
|
||||
|
||||
8. **Keep components small and focused.** A component should render itself and its own interactions (e.g. a card + its dialog). Page-level layout, data arrays, and loops belong in the page, not the component.
|
||||
|
||||
9. **Pass data directly, not keys.** When passing icons or other references through props, pass the actual objects (e.g. `icon={ComputerTerminal01Icon}`), not string keys to a lookup map.
|
||||
|
||||
10. **Always wrap items and labels in a Group.** For menu-like components, items, labels, and subs must be direct children of their group component. Never place them directly inside the content container.
|
||||
- `DropdownMenuItem`, `DropdownMenuLabel`, `DropdownMenuSub` → inside `DropdownMenuGroup`
|
||||
- `MenubarItem`, `MenubarLabel`, `MenubarSub` → inside `MenubarGroup`
|
||||
- `ContextMenuItem`, `ContextMenuLabel`, `ContextMenuSub` → inside `ContextMenuGroup`
|
||||
- `SelectItem`, `SelectLabel` → inside `SelectGroup`
|
||||
- `CommandItem` → inside `CommandGroup`
|
||||
|
||||
11. **Always use `data-icon` on icons inside buttons.** When placing an icon inside a `Button`, add `data-icon="inline-start"` for prefix icons or `data-icon="inline-end"` for suffix icons. This ensures correct spacing. Never add sizing classes to the icon — the button handles sizing automatically.
|
||||
|
||||
12. **Always use `InputGroupInput` and `InputGroupTextarea` inside an `InputGroup`.** Never use the base `Input` or `Textarea` components directly inside an `InputGroup`. The input-group variants reset borders, backgrounds, and focus rings to compose correctly within the group.
|
||||
|
||||
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. **`InputGroupAddon` must use `InputGroupButton`.** Never place a raw `Button` inside `InputGroupAddon`. Always use `InputGroupButton` instead.
|
||||
|
||||
15. **`InputGroupButton` sizing depends on addon alignment.** When `InputGroupAddon` is `align="inline-start"` or `align="inline-end"`, prefer `size="icon-sm"` or `size="icon-xs"` (icon-only buttons). When `align="block-start"` or `align="block-end"`, prefer `size="xs"` or `size="sm"` (buttons with text).
|
||||
387
skills/shadcn/registry-authoring.md
Normal file
387
skills/shadcn/registry-authoring.md
Normal file
@@ -0,0 +1,387 @@
|
||||
# Registry Authoring
|
||||
|
||||
Build and publish your own shadcn/ui-compatible component registry. Registries let you distribute reusable components, blocks, hooks, and utilities that others can install with a single command.
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A registry is a collection of items (components, blocks, hooks, etc.) described in a `registry.json` file. The `shadcn build` command compiles this into individual JSON files that can be hosted on any static file server.
|
||||
|
||||
```
|
||||
my-registry/
|
||||
├── registry.json # registry definition
|
||||
├── registry/
|
||||
│ ├── my-button.tsx # component source files
|
||||
│ ├── my-card.tsx
|
||||
│ └── hooks/
|
||||
│ └── use-something.ts
|
||||
└── public/r/ # built output (created by shadcn build)
|
||||
├── my-button.json
|
||||
├── my-card.json
|
||||
└── use-something.json
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## registry.json Format
|
||||
|
||||
The schema is available at `https://ui.shadcn.com/schema/registry.json`.
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"name": "my-registry",
|
||||
"homepage": "https://my-registry.dev",
|
||||
"items": [
|
||||
{
|
||||
"name": "my-button",
|
||||
"type": "registry:ui",
|
||||
"title": "My Button",
|
||||
"description": "A custom button with extra features.",
|
||||
"dependencies": ["class-variance-authority"],
|
||||
"registryDependencies": ["button"],
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/my-button.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Required Fields
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `name` | Registry name (used in the registry index) |
|
||||
| `homepage` | URL to the registry's homepage |
|
||||
| `items` | Array of registry items |
|
||||
|
||||
### Item Fields
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| `name` | Yes | Unique item name within the registry |
|
||||
| `type` | Yes | Item type (see types below) |
|
||||
| `title` | No | Human-readable display title |
|
||||
| `description` | No | Brief description of the item |
|
||||
| `author` | No | Author info (e.g., `"username <https://github.com/username>"`) |
|
||||
| `dependencies` | No | NPM packages to install |
|
||||
| `devDependencies` | No | NPM dev dependencies to install |
|
||||
| `registryDependencies` | No | Other registry items this depends on |
|
||||
| `files` | No | Array of source files |
|
||||
| `cssVars` | No | CSS variables to inject (light, dark, theme) |
|
||||
| `css` | No | Raw CSS rules to inject |
|
||||
| `tailwind` | No | Tailwind config extensions |
|
||||
| `envVars` | No | Environment variables (added to `.env`) |
|
||||
| `docs` | No | Markdown documentation |
|
||||
| `categories` | No | Array of category strings |
|
||||
| `meta` | No | Arbitrary metadata object |
|
||||
|
||||
---
|
||||
|
||||
## Item Types
|
||||
|
||||
| Type | Purpose | Target Path |
|
||||
|------|---------|-------------|
|
||||
| `registry:ui` | UI primitives (button, card, etc.) | `components/ui/` |
|
||||
| `registry:component` | Reusable composed components | `components/` |
|
||||
| `registry:block` | Multi-file page blocks (login, dashboard) | `components/` |
|
||||
| `registry:hook` | React hooks | `hooks/` |
|
||||
| `registry:lib` | Utility functions | `lib/` |
|
||||
| `registry:page` | Full pages (requires `target`) | Custom path |
|
||||
| `registry:file` | Static files (requires `target`) | Custom path |
|
||||
| `registry:theme` | Theme definitions | — |
|
||||
| `registry:style` | Global style definitions | — |
|
||||
| `registry:item` | Generic item | `components/` |
|
||||
|
||||
**Note:** `registry:page` and `registry:file` require a `target` field on each file to specify the output path.
|
||||
|
||||
---
|
||||
|
||||
## File Objects
|
||||
|
||||
Files can be specified in two ways:
|
||||
|
||||
```json
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/my-component.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| `path` | Yes | Path relative to the registry root |
|
||||
| `type` | Yes | File type (same enum as item types) |
|
||||
| `target` | Conditional | Output path in the project (required for `registry:file` and `registry:page`) |
|
||||
| `content` | No | Inline file content (auto-read from `path` if not provided) |
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
### NPM Dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": ["framer-motion", "class-variance-authority"],
|
||||
"devDependencies": ["@types/some-package"]
|
||||
}
|
||||
```
|
||||
|
||||
These are installed via the user's package manager when they `shadcn add` the item.
|
||||
|
||||
### Registry Dependencies
|
||||
|
||||
```json
|
||||
{
|
||||
"registryDependencies": ["button", "card", "https://other-registry.com/r/item.json"]
|
||||
}
|
||||
```
|
||||
|
||||
- **Plain names** (e.g., `"button"`) reference items from the `@shadcn` registry.
|
||||
- **URLs** reference items from other registries.
|
||||
- Registry dependencies are automatically resolved and installed.
|
||||
|
||||
---
|
||||
|
||||
## CSS Variables
|
||||
|
||||
Inject CSS variables into the user's project:
|
||||
|
||||
```json
|
||||
{
|
||||
"cssVars": {
|
||||
"light": {
|
||||
"chart-custom": "oklch(0.646 0.222 41.116)"
|
||||
},
|
||||
"dark": {
|
||||
"chart-custom": "oklch(0.268 0.08 34.298)"
|
||||
},
|
||||
"theme": {
|
||||
"--color-chart-custom": "var(--chart-custom)"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `light` — Variables added to `:root`.
|
||||
- `dark` — Variables added to `.dark`.
|
||||
- `theme` — Variables added to `@theme inline` (Tailwind v4 only).
|
||||
|
||||
---
|
||||
|
||||
## CSS Rules
|
||||
|
||||
Inject raw CSS into the project:
|
||||
|
||||
```json
|
||||
{
|
||||
"css": {
|
||||
"@keyframes shimmer": {
|
||||
"from": { "background-position": "200% 0" },
|
||||
"to": { "background-position": "-200% 0" }
|
||||
},
|
||||
".animate-shimmer": {
|
||||
"animation": "shimmer 8s ease-in-out infinite",
|
||||
"background-size": "200% 100%"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Supports at-rules, selectors, nested rules, utilities, and layers.
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
```json
|
||||
{
|
||||
"envVars": {
|
||||
"DATABASE_URL": "The connection string for your database.",
|
||||
"API_KEY": "Your API key from the dashboard."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
These are added to the user's `.env` file with placeholder values.
|
||||
|
||||
---
|
||||
|
||||
## Building the Registry
|
||||
|
||||
```bash
|
||||
shadcn build
|
||||
```
|
||||
|
||||
This reads `registry.json` and outputs individual JSON files to `public/r/`:
|
||||
|
||||
```bash
|
||||
# Custom input/output paths.
|
||||
shadcn build ./path/to/registry.json --output ./public/r
|
||||
```
|
||||
|
||||
Each item becomes a standalone JSON file (e.g., `public/r/my-button.json`) containing the resolved item with file contents inlined.
|
||||
|
||||
---
|
||||
|
||||
## Hosting
|
||||
|
||||
Host the built `public/r/` directory on any static file server. The URL pattern must include a `{name}` placeholder:
|
||||
|
||||
```
|
||||
https://my-registry.dev/r/{name}.json
|
||||
```
|
||||
|
||||
**Hosting options:**
|
||||
|
||||
- **Vercel/Netlify** — Deploy the project, files are served from `public/r/`.
|
||||
- **GitHub Pages** — Push `public/r/` to a gh-pages branch.
|
||||
- **Any CDN** — Upload the JSON files.
|
||||
|
||||
---
|
||||
|
||||
## Configuration for Users
|
||||
|
||||
Users add your registry to their `components.json`:
|
||||
|
||||
### Simple format
|
||||
|
||||
```json
|
||||
{
|
||||
"registries": {
|
||||
"@myregistry": "https://my-registry.dev/r/{name}.json"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### With authentication
|
||||
|
||||
```json
|
||||
{
|
||||
"registries": {
|
||||
"@myregistry": {
|
||||
"url": "https://my-registry.dev/r/{name}.json",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${MY_REGISTRY_TOKEN}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Environment variable references (`${VAR}`) are resolved at runtime.
|
||||
|
||||
### Installing items
|
||||
|
||||
```bash
|
||||
shadcn add @myregistry/my-button
|
||||
shadcn search @myregistry -q "button"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Community Registry Index
|
||||
|
||||
To list your registry in the public directory at `https://ui.shadcn.com/r/registries.json`, submit it through the shadcn/ui repository.
|
||||
|
||||
Each entry in the index looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "@myregistry",
|
||||
"homepage": "https://my-registry.dev",
|
||||
"url": "https://my-registry.dev/r/{name}.json",
|
||||
"description": "A collection of custom components."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Minimal Registry
|
||||
|
||||
**registry.json:**
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema/registry.json",
|
||||
"name": "acme-ui",
|
||||
"homepage": "https://acme-ui.dev",
|
||||
"items": [
|
||||
{
|
||||
"name": "status-badge",
|
||||
"type": "registry:ui",
|
||||
"title": "Status Badge",
|
||||
"description": "A badge that shows status with color coding.",
|
||||
"registryDependencies": ["badge"],
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/status-badge.tsx",
|
||||
"type": "registry:ui"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "use-copy-to-clipboard",
|
||||
"type": "registry:hook",
|
||||
"title": "useCopyToClipboard",
|
||||
"description": "A hook to copy text to the clipboard.",
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/hooks/use-copy-to-clipboard.ts",
|
||||
"type": "registry:hook"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Build and host:**
|
||||
|
||||
```bash
|
||||
shadcn build
|
||||
# Outputs: public/r/status-badge.json, public/r/use-copy-to-clipboard.json
|
||||
```
|
||||
|
||||
**Users install with:**
|
||||
|
||||
```bash
|
||||
shadcn add @acme-ui/status-badge
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Block with Multiple Files
|
||||
|
||||
Blocks are multi-file items like dashboards or login forms:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "login-form",
|
||||
"type": "registry:block",
|
||||
"title": "Login Form",
|
||||
"description": "A complete login form with email and password fields.",
|
||||
"registryDependencies": ["button", "input", "label", "card"],
|
||||
"files": [
|
||||
{
|
||||
"path": "registry/login-form/page.tsx",
|
||||
"type": "registry:page",
|
||||
"target": "app/login/page.tsx"
|
||||
},
|
||||
{
|
||||
"path": "registry/login-form/login-form.tsx",
|
||||
"type": "registry:component"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user