# Registry

Scaffold and author installable registry items under registry/items.

Registry items live under `registry/items/**` and can be installed by shadcn-compatible CLIs. Start new items with the scaffold command so the folder, `_registry.mdx`, source file, metadata, and generated registry JSON paths follow the template conventions.

```sh
bun --bun ./scripts/new.ts --type registry:ui --name example-card --description "A compact card component."
```

Or, run the command without flags if you want an interactive prompt (recommended).

```sh
bun --bun ./scripts/new.ts
```

<Callout title="Requires Bun">
  [Make sure Bun is installed before running these scripts.](https://bun.com/)
</Callout>

## Item Types

Choose the registry type from what the item installs:

| Type                 | Use For                                   | Folder                         |
| -------------------- | ----------------------------------------- | ------------------------------ |
| `registry:ui`        | Shadcn-style UI components                | `registry/items/components/**` |
| `registry:component` | Components outside `components/ui`        | `registry/items/components/**` |
| `registry:block`     | Larger composed UI patterns               | `registry/items/blocks/**`     |
| `registry:hook`      | React hooks                               | `registry/items/hooks/**`      |
| `registry:lib`       | Utility or helper modules                 | `registry/items/lib/**`        |
| `registry:page`      | App page files with explicit targets      | `registry/items/pages/**`      |
| `registry:file`      | Other files with explicit install targets | `registry/items/files/**`      |
| `registry:style`     | Style-level CSS and dependency metadata   | `registry/items/styles/**`     |
| `registry:theme`     | Theme CSS variables                       | `registry/items/themes/**`     |
| `registry:font`      | Font metadata                             | `registry/items/fonts/**`      |
| `registry:base`      | Design system base configuration          | `registry/items/bases/**`      |
| `registry:item`      | Universal or metadata-only items          | `registry/items/items/**`      |

The scaffold creates each item in its own folder:

```text
registry/items/components/example-card/
  _registry.mdx
  _preview.tsx
  example-card.tsx
```

## CLI Flags

Use flags for agent-friendly and CI-friendly scaffolding:

```sh
bun --bun ./scripts/new.ts --type registry:block --name stats-panel --description "A metrics panel with reusable sample data."
bun --bun ./scripts/new.ts --type registry:ui --name prompt-input --description "An AI prompt input." --target @ui/ai/prompt-input.tsx
bun --bun ./scripts/new.ts --type registry:page --name dashboard-page --description "A starter dashboard page." --target app/dashboard/page.tsx
bun --bun ./scripts/new.ts --type registry:file --name chart-theme --description "Shared chart theme tokens." --target styles/chart-theme.css --file-extension css
bun --bun ./scripts/new.ts --type registry:font --name font-inter --description "Inter font metadata." --font-family "'Inter Variable', sans-serif" --font-import Inter --font-variable=--font-sans
```

Supported flags:

- `--type`: registry item type. Defaults to `registry:ui`.
- `--name`: required kebab-case item name.
- `--title`: optional public title. Defaults from the name.
- `--description`: required public description.
- `--target`: required for `registry:page` and `registry:file`; optional for source-backed items that need a custom install path, including shadcn target placeholders like `@ui/ai/prompt-input.tsx`.
- `--file-extension`: for `registry:file` and targeted `registry:item`; defaults to `ts`.
- `--font-family`, `--font-import`, `--font-variable`: required for noninteractive `registry:font` scaffolds.

Use `bun --bun ./scripts/new.ts --help` to print the full usage.

## Authoring

Use `_registry.mdx` for public metadata and usage docs. Put the optional named `Preview` export in `_preview.tsx`. Keep both files private to authoring; never list them in `files`.

For one-file `registry:ui` items, the catalog infers `<item-name>.tsx`. Hooks, libs, blocks, pages, target paths, and multi-file items should list `files` explicitly. Metadata-only styles, themes, fonts, bases, and universal items can omit `files`.

List authored source files with paths relative to the item `_registry.mdx` file. The catalog automatically emits `files[].target` placeholders such as `@ui/<name>.tsx`, `@components/<name>.tsx`, `@hooks/<name>.ts`, and `@lib/<name>.ts` for file types that should install through the user's `components.json` aliases. Use explicit `target` values for `registry:page`, `registry:file`, and nested alias installs like `@ui/ai/prompt-input.tsx`; do not add `registry/items/**` prefixes or a separate `sourcePath` field.

Use `localRegistryDependencies` for dependencies on other local registry items.

## Component Variants

If a component uses `cva` from `class-variance-authority`, keep that definition in a colocated `<name>.variants.ts` file. Do not call `cva` in the component `.tsx`. Use `.ts`, not `.tsx`.

Treat [`button`](/components/button) as the reference:

```text
registry/items/components/button/
  _registry.mdx
  _preview.tsx
  button.tsx
  button.types.ts
  button.variants.ts
```

`button.tsx` imports the CVA helper and renders. `button.variants.ts` owns every `cva()` call for that item. If one folder has several CVA helpers, keep them in the same `.variants.ts` file. Put `VariantProps` in a colocated `<name>.types.ts` file when the item has named variant types, as Button does.

Each variants file should follow this shape:

```ts
import { cva } from "class-variance-authority";

import { cn } from "cn";

const exampleBase = cn("inline-flex items-center rounded-md");

const exampleConfig = {
  variants: {
    variant: {
      primary: "bg-primary text-primary-foreground",
      outline: "border border-border bg-background",
    },
    size: {
      sm: "h-8 px-3",
      md: "h-9 px-4",
    },
  },
  compoundVariants: [],
  defaultVariants: {
    variant: "primary",
    size: "md",
  },
} as const;

export const exampleCva = cva(exampleBase, {
  ...exampleConfig,
  compoundVariants: [...exampleConfig.compoundVariants],
});

export const EXAMPLE_VARIANTS = Object.keys(
  exampleConfig.variants.variant,
) as (keyof typeof exampleConfig.variants.variant)[];

export const EXAMPLE_SIZES = Object.keys(
  exampleConfig.variants.size,
) as (keyof typeof exampleConfig.variants.size)[];

export const exampleVariants = exampleCva;
```

Always include `compoundVariants` on the config, even when it is empty, and spread it into `cva()` so the `as const` config stays compatible. Export a key array for each variant axis that stories or other items need to iterate. Re-export the CVA helper from the component file only when another item already consumes that public name.

List the variants file in `_registry.mdx` `files`, and add `class-variance-authority` to `dependencies`. Include `.types.ts` when the item has one:

```yaml
dependencies:
  - class-variance-authority
files:
  - path: example.tsx
    type: registry:ui
    target: components/ui/example/example.tsx
  - path: example.types.ts
    type: registry:ui
    target: components/ui/example/example.types.ts
  - path: example.variants.ts
    type: registry:ui
    target: components/ui/example/example.variants.ts
```

After editing an item, run `vp check --fix` on touched files and `bun --bun ./scripts/doctor.ts`. Run `vp build` when registry docs, routes, JSON output, catalog loading, or source loading changed.
