文档目录 > 注册表 (Registry)

注册表 (Registry)

介绍

运行你自己的代码注册表。

你可以使用 shadcn CLI 运行自己的代码注册表。运行自己的注册表可以让你将自定义组件、hooks、页面、配置文件、规则和其他文件分发给任何项目。

注意: 注册表适用于任何项目类型和任何框架,不限于 React。

注册表是一个代码分发系统——准备好创建你自己的注册表了吗?下一节将逐步指导你从创建第一个组件到发布供他人使用。

入门 (Getting Started)

学习如何设置和运行你自己的组件注册表。

本指南将引导你完成设置自己的注册表的整个过程。它假定你已经有一个包含组件、hooks、工具函数或其他你想要分发的文件的项目。

如果你有一个现有的公共 GitHub 仓库,你只需在根目录添加一个 registry.json 文件即可将其转变为注册表。 详见 GitHub 注册表

如果你是新建注册表项目,可以使用 registry template 作为起点。

要求

你可以自由地按照自己的意愿设计和发布自定义注册表。唯一的要求是注册表目录(catalog)和注册表项(registry items)必须符合 registry schema 规范registry-item schema 规范

你的注册表可以是 Next.js、Vite、Vue、Svelte、PHP 或任何其他支持通过 HTTP 提供 JSON 的框架。它也可以是在根目录包含 registry.json 文件的公共 GitHub 仓库。

registry.json

registry.json 是注册表的入口点。它包含注册表的名称、主页,并定义了注册表中存在的所有项。

你的注册表必须在注册表端点的根目录存在此文件(或 JSON 负载)。注册表端点是你托管注册表的 URL。

json
{
  "name": "acme",
  "homepage": "https://acme.com",
  "items": []
}

组织注册表结构

你可以通过以下两种方式之一组织源注册表结构:

  • 方案 A:单一 registry.json - 在项目根目录创建一个 registry.json 文件,将所有注册表项添加到 items 数组中。这是定义注册表最简单的方式。
  • 方案 B:使用 include - 对于较大的注册表,你可以使用 include 从多个 registry.json 文件组合你的源注册表。

方案 A:单一 registry.json

json
{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "acme",
  "homepage": "https://acme.com",
  "items": [
    {
      "name": "button",
      "type": "registry:ui",
      "title": "Button",
      "description": "A button component",
      "files": [
        {
          "path": "components/ui/button.tsx",
          "type": "registry:ui"
        }
      ]
    }
  ]
}

方案 B:使用 include

根目录的 registry.json 定义注册表元数据并包含嵌套的注册表文件:

json
{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "acme",
  "homepage": "https://acme.com",
  "include": [
    "components/ui/registry.json",
    "hooks/registry.json"
  ]
}

被包含的 registry.json 文件是有效的组合注册表文件,可以省略 namehomepage。只有根 registry.json 必须定义注册表元数据。

json
// components/ui/registry.json
{
  "items": [
    {
      "name": "button",
      "type": "registry:ui",
      "files": [{ "path": "button.tsx", "type": "registry:ui" }]
    }
  ]
}
json
// hooks/registry.json
{
  "items": [
    {
      "name": "use-debounce",
      "type": "registry:hook",
      "files": [{ "path": "use-debounce.ts", "type": "registry:hook" }]
    }
  ]
}

使用 include 时,文件路径是相对于声明该项的 registry.json 文件。

添加注册表项

创建 UI 组件

添加你的第一个项。以下是一个简单的 <Button /> 组件示例:

tsx
// components/ui/button.tsx
export function Button() {
  return <button>Click me</button>
}

注意: 本示例将组件放在 components/ui 目录中。你可以将其放在项目中的任何位置,只要在 registry.json 文件中设置正确的路径即可。

将项添加到注册表

要将组件添加到注册表,请在 registry.json 中添加项定义。如果你使用 include,请将项添加到拥有该组件的被包含 registry.json 文件中。

json
{
  "items": [
    {
      "name": "button",
      "type": "registry:ui",
      "title": "Button",
      "description": "A button component",
      "files": [
        {
          "path": "components/ui/button.tsx",
          "type": "registry:ui"
        }
      ]
    }
  ]
}

你通过添加 nametypetitledescriptionfiles 来定义注册表项。对于添加的每个文件,必须指定 pathtype。在单一文件注册表中,path 相对于项目根目录。使用 include 时,path 相对于声明该项的 registry.json 文件。type 是文件的类型。

提供注册表服务

你可以以静态 JSON 文件或动态路由处理程序的方式提供注册表服务。

方案 A:静态 JSON 文件

运行构建命令以生成静态注册表 JSON 文件:

bash
npx shadcn@latest build

如果你的源注册表使用了 includeshadcn build 会解析被包含的注册表并将扁平化的注册表写入输出目录。生成的 registry.json 不包含 include

注意: 默认情况下,构建命令会在 public/r 目录下生成注册表 JSON 文件,例如 public/r/button.json。你可以通过 --output 选项更改输出目录。

如果你在 Next.js 上运行注册表,可以通过运行 next 服务器来提供这些文件:

bash
npx next start

你的文件现在将在 http://localhost:3000/r/[NAME].json(例如 http://localhost:3000/r/button.json)提供服务。

方案 B:动态路由处理程序

如果你想在请求时从源 registry.json 提供注册表 JSON,请使用 shadcn/registry 的生产端 loader API。

首先安装 shadcn 作为运行时依赖:

bash
npm install shadcn

使用 loadRegistry 提供注册表目录:

ts
// app/r/registry.json/route.ts
import { loadRegistry } from "shadcn/registry"

export async function GET() {
  const registry = await loadRegistry()
  return Response.json(registry)
}

使用 loadRegistryItem 提供单个注册表项:

ts
// app/r/[name].json/route.ts
import { loadRegistryItem } from "shadcn/registry"

export async function GET(
  _request: Request,
  { params }: { params: { name: string } }
) {
  const item = await loadRegistryItem(params.name)
  return Response.json(item)
}

两个 loader 在返回 JSON 之前都会解析 include,因此路由处理程序可以使用相同的源 registry.json 结构,而无需运行 shadcn build

测试注册表

提供注册表服务后,使用其他开发者将使用的相同 CLI 命令进行测试。

使用 URL

bash
# 列出项
npx shadcn@latest list http://localhost:3000/r/registry.json

# 搜索项
npx shadcn@latest search http://localhost:3000/r/registry.json button

# 查看项
npx shadcn@latest view http://localhost:3000/r/button.json

# 添加项(在要安装项的项目中运行)
npx shadcn@latest add http://localhost:3000/r/button.json

使用命名空间

你还可以使用命名空间测试你的注册表。从包含 components.json 文件的项目中,将注册表 URL 模板添加到项目:

bash
npx shadcn@latest add registry http://localhost:3000/r/{name}.json

{name} 占位符必须解析为项 JSON 文件。例如,@acme/button 解析为 http://localhost:3000/r/button.json。目录仍然在 http://localhost:3000/r/registry.json 单独提供服务。

bash
# 列表
npx shadcn@latest list @acme

# 搜索
npx shadcn@latest search @acme button

# 查看
npx shadcn@latest view @acme/button

# 添加
npx shadcn@latest add @acme/button

发布注册表

要使你的注册表对其他开发者可用,请将项目发布到公共 URL。部署后,用户可以直接从项 URL 安装项,或者将你的注册表作为命名空间添加到他们的项目中。

分享命名空间设置说明

如果你希望用户使用像 @acme/button 这样的命名空间安装项,告诉他们将自己的注册表 URL 模板添加到项目。当 CLI 解析注册表项时,{name} 占位符会被替换为项名称。

模板必须解析为项 JSON 文件。例如,@acme/button 解析为 https://acme.com/r/button.json。你的注册表目录仍应在 https://acme.com/r/registry.json 单独提供服务。

他们可以使用 CLI 添加命名空间:

bash
npx shadcn@latest add registry https://acme.com/r/{name}.json

或者手动在 components.json 文件的 registries 字段中添加:

json
{
  "registries": {
    "acme": {
      "url": "https://acme.com/r/{name}.json"
    }
  }
}

用户然后可以通过命名空间消费注册表中的项:

bash
npx shadcn@latest add @acme/button

将命名空间添加到注册表索引

如果你的注册表是开源的且公开可用,你可以将命名空间提交到官方注册表索引。这样用户可以按名称添加你的命名空间,而无需粘贴完整的 URL 模板。

指南

构建注册表组件时需遵循以下指南:

  • 将注册表项放在 registry/[STYLE]/[NAME] 目录中。这里使用 default 作为示例。可以是任何你想要的名称,只要它嵌套在 registry 目录下即可。
  • 对于 blocks,以下属性是必需的:namedescriptiontypefiles
  • 建议为注册表项添加合适的名称和描述。这有助于 LLM 理解组件及其用途。
  • 确保在 registryDependencies 中列出所有注册表依赖。注册表依赖是一个项地址,例如 button@acme/input-formacme/ui/buttonhttp://localhost:3000/r/editor.json
  • 确保在 dependencies 中列出所有依赖。依赖是注册表中包的名称,例如 zodsonner 等。要设置版本,可以使用 name@version 格式,例如 zod@^3.20.0
  • 导入应始终使用 @/registry 路径。 例如 import { HelloWorld } from "@/registry/default/hello-world/hello-world"
  • 理想情况下,将文件放在注册表项内的 componentshookslib 目录中。

GitHub 注册表 (GitHub Registries)

使用公共 GitHub 仓库作为注册表。

你现在可以将任何公共 GitHub 仓库转变为注册表。 在仓库根目录添加一个 registry.json 文件,描述你想要分享的文件,用户就可以使用 shadcn CLI 安装它们。

bash
npx shadcn@latest add github:username/repo/item-name

不需要设置注册表服务器或发布生成的 JSON 文件。GitHub 仓库本身成为源注册表。

分发任何内容

注册表项不限于组件或 React 代码。 它们可以包含仓库中的任何文件:源文件、配置、文档、模板、工作流、规则或项目约定。

用途示例文件
组件components/date-picker.tsxcomponents/data-table.tsx
辅助函数和工具lib/format-date.tslib/cn.tshooks/use-copy.ts
设计系统包tokens/colors.jsonstyles/theme.csscomponents/*
功能套件app/(auth)/*lib/auth.tscomponents/login-form.tsx
Agent 工作流AGENTS.md.cursor/rules/*.claude/commands/*
项目约定.editorconfigbiome.jsondocs/conventions.md
Codemods 和迁移工具codemods/*scripts/migrate.tsdocs/migration.md
测试配置vitest.config.tstest/setup.tsdocs/testing.md
CI 和发布工作流.github/workflows/ci.yml.github/workflows/release.yml
项目和自动化scripts/release.tsscripts/checks.tsdocs/automation.md
Issue 和 PR 模板.github/ISSUE_TEMPLATE/*.github/pull_request_template.md
MCP 配置.mcp.json.cursor/mcp.json

何时使用 GitHub

在以下情况下使用 GitHub 注册表:

  • 你已经在公共 GitHub 仓库中有可重用代码。
  • 你希望用户直接从 owner/repo/item 安装。
  • 你想分发配置文件、规则、文档、模板、工具或同一仓库中的任何其他文件。
  • 你不需要私有仓库访问或自定义请求认证。

要求

GitHub 注册表必须:

  • github.com 上的公共仓库。
  • 在仓库根目录有一个 registry.json 文件。
  • 使用有效的 registry.jsonregistry-item.json schema。
  • 引用的源文件必须存在于仓库中。

私有仓库和 GitHub Enterprise 主机目前不被 GitHub 地址支持。对于私有或经过认证的注册表,请使用命名空间配合认证

第一步:添加 registry.json

给定一个现有的公共仓库:

text
my-toolkit/
├── components/
│   └── button.tsx
└── lib/
    └── utils.ts

在仓库根目录添加 registry.json

json
{
  "name": "my-toolkit",
  "homepage": "https://github.com/username/my-toolkit",
  "items": [
    {
      "name": "button",
      "type": "registry:ui",
      "files": [
        { "path": "components/button.tsx", "type": "registry:ui" }
      ]
    }
  ]
}

提交并推送文件:

bash
git add registry.json
git commit -m "add registry.json"
git push

用户现在可以从 GitHub 安装该项:

bash
npx shadcn@latest add github:username/my-toolkit/button

第二步:分发任何文件

注册表项可以安装一个文件或多个文件。使用 files 数组声明属于同一组的文件。

例如,一个测试设置可以安装 Vitest 配置、一个设置文件和一个简短的团队指南:

json
{
  "items": [
    {
      "name": "testing-setup",
      "type": "registry:file",
      "title": "Testing Setup",
      "description": "Vitest config, setup file, and team guide",
      "files": [
        { "path": "vitest.config.ts", "type": "registry:file", "target": "~/vitest.config.ts" },
        { "path": "test/setup.ts", "type": "registry:file", "target": "~/test/setup.ts" },
        { "path": "docs/testing.md", "type": "registry:file", "target": "~/docs/testing.md" }
      ]
    }
  ]
}

用户以相同方式安装:

bash
npx shadcn@latest add github:username/my-toolkit/testing-setup

使用 target 指定文件应写入用户项目中的特定目标位置。

第三步:验证注册表

在分享注册表之前,从 CLI 验证它:

bash
npx shadcn@latest validate github:username/my-toolkit

该命令读取根 registry.json,解析 include,验证注册表项,并检查引用的文件是否存在。

你也可以验证分支、标签或提交 SHA:

bash
npx shadcn@latest validate github:username/my-toolkit#v1.0.0

第四步:列表和搜索项

bash
# 列出所有项
npx shadcn@latest list github:username/my-toolkit

# 搜索
npx shadcn@latest search github:username/my-toolkit button

# 查看项
npx shadcn@latest view github:username/my-toolkit/button

使用 include 组织

对于较大的仓库,将项定义保持在其描述的源文件附近:

text
my-toolkit/
├── registry.json          # root with include
├── rules/
│   ├── registry.json      # declares items for rules/
│   ├── project-conventions.md
│   └── code-review.md
└── components/
    ├── registry.json      # declares items for components/
    └── button.tsx

registry.json 可以包含嵌套的注册表文件:

json
{
  "name": "my-toolkit",
  "include": ["rules/registry.json", "components/registry.json"]
}

被包含的注册表文件为该目录声明项:

json
// rules/registry.json
{
  "items": [
    {
      "name": "project-conventions",
      "type": "registry:file",
      "files": [{ "path": "project-conventions.md", "type": "registry:file", "target": "~/docs/project-conventions.md" }]
    }
  ]
}

使用 include 时,文件路径是相对于声明该项的 registry.json 文件。

注册表依赖

使用 registryDependencies 表示一个注册表项依赖于另一个注册表项。

同一仓库依赖:

json
{
  "items": [
    {
      "name": "login-form",
      "type": "registry:block",
      "registryDependencies": ["github:username/my-toolkit/button", "github:username/my-toolkit/input"]
    }
  ]
}

外部注册表依赖:

json
{
  "items": [
    {
      "name": "dashboard",
      "type": "registry:block",
      "registryDependencies": ["shadcn/button", "@acme/chart", "github:other-org/toolkit/card"]
    }
  ]
}

Refs

使用 #ref 从分支、标签或提交 SHA 安装:

bash
npx shadcn@latest add github:username/my-toolkit/button#v1.0.0
npx shadcn@latest add github:username/my-toolkit/button#main
npx shadcn@latest add github:username/my-toolkit/button#abc123def456abc123def456abc123def456abc123

Refs 可以包含斜杠。如果未提供 ref,CLI 使用仓库的默认分支。CLI 使用 Git 将分支、标签和短 ref 解析为提交 SHA,然后读取文件。完整的 40 字符提交 SHA 直接使用,不需要 Git。

安装前审查

GitHub 注册表项从公共仓库安装代码和项目文件。将 GitHub 项地址视为任何其他第三方代码依赖。

在从你不控制的源安装之前:

  • 审查仓库和根 registry.json
  • 审查项定义,特别是 filestargetdependenciesdevDependenciesregistryDependenciesenvVars
  • 检查任何外部注册表依赖。它们可以从其他注册表安装文件。
  • 对于发布的安装命令,优先使用固定 ref。完整的 40 字符提交 SHA 是最可重现的选项。
  • 使用 shadcn view acme/toolkit/project-conventions 在安装前检查解析后的项负载。
  • 使用 shadcn add acme/toolkit/project-conventions --dry-run 预览安装而不写入文件。
  • 使用 --diff--viewshadcn add 一起在应用前检查文件更改或文件内容。

命名空间注册表 (Namespaces)

配置和使用多个资源注册表,支持命名空间。

命名空间注册表让你在一个项目中配置多个资源来源。这意味着你可以从各种注册表安装组件、库、工具、AI 提示、配置文件和其他资源,无论它们是公共的、第三方的,还是你自己自定义的私有库。

概述

注册表命名空间以 @ 为前缀,提供了一种组织和引用不同来源资源的方式。资源可以是任何类型的内容:组件、库、工具、hooks、AI 提示、配置文件、主题等。例如:

  • @shadcn/button - 来自 shadcn 注册表的 UI 组件
  • @v0/dashboard - 来自 v0 注册表的仪表板组件
  • @acme/auth-utils - 来自公司私有注册表的认证工具

去中心化命名空间系统

命名空间系统被有意设计为去中心化的。存在一个中央开源注册表索引用于开源命名空间,但你可以自由创建和使用任何你想要的命名空间。

这种去中心化方法让你可以完全灵活地以适合你的组织的方式组织资源。

你可以为不同目的创建多个注册表:

json
{
  "registries": {
    "ui": { "url": "https://ui.acme.com/{name}.json" },
    "docs": { "url": "https://docs.acme.com/{name}.json" },
    "ai": { "url": "https://ai.acme.com/{name}.json" }
  }
}

这允许你:按类型组织、按团队组织、按可见性组织、按版本组织,并且不会产生命名冲突。

快速配置

将注册表添加到你的 components.json

json
{
  "registries": {
    "acme": {
      "url": "https://registry.acme.com/r/{name}.json"
    }
  }
}

然后开始安装:

bash
npx shadcn@latest add @acme/button
npx shadcn@latest add @acme/input @acme/select

注册表命名约定

注册表名称必须遵循以下规则:

  • @ 符号开头
  • 仅包含字母数字字符、连字符和下划线
  • 有效名称示例:@v0@acme-ui@my_company
  • 引用资源的模式:@namespace/resource-name

GitHub 和命名空间

GitHub 注册表地址和命名空间解决不同的问题。

当注册表是公共 GitHub 仓库并且你希望用户无需配置 components.json 即可安装时,使用 GitHub 地址:

bash
npx shadcn@latest add github:acme/ui/button

当你想要稳定的别名、自定义托管、认证、请求头、查询参数或私有注册表支持时,使用命名空间:

bash
npx shadcn@latest add @acme/button

配置

命名空间注册表在你的 components.json 文件的 registries 字段中配置。

基本配置:

json
{
  "registries": {
    "acme": "https://registry.acme.com/r/{name}.json"
  }
}

注意: URL 中的 {name} 占位符在运行 npx shadcn@latest add @namespace/resource-name 时会被自动解析并替换为资源名称。例如,@acme/button 变为 https://registry.acme.com/r/button.json

高级配置:

对于需要认证或其他参数的注册表,使用对象格式:

json
{
  "registries": {
    "acme": {
      "url": "https://registry.acme.com/r/{name}.json",
      "headers": {
        "Authorization": "Bearer ${ACME_TOKEN}"
      }
    }
  }
}

注意: ${VAR_NAME} 格式的环境变量会自动从你的环境(process.env)中展开。这适用于 URL、headers 和 params。

URL 模式系统

注册表 URL 支持以下占位符:

{name} 占位符(必需) - 被替换为资源名称:

json
{
  "registries": {
    "acme": "https://registry.acme.com/{name}.json"
  }
}

安装 @acme/button 时,URL 变为:https://registry.acme.com/button.json

{style} 占位符(可选) - 被替换为当前样式配置:

json
{
  "registries": {
    "themes": "https://registry.example.com/{style}/{name}.json"
  }
}

样式设置为 new-york 时,安装 @themes/card 解析为:https://registry.example.com/new-york/card.json

认证与安全

环境变量: 使用环境变量安全地存储凭据:

json
{
  "registries": {
    "@internal": {
      "url": "https://internal.company.com/r/{name}.json",
      "headers": {
        "Authorization": "Bearer ${INTERNAL_TOKEN}"
      }
    }
  }
}

然后在 .env.local 中设置环境变量:

text
INTERNAL_TOKEN=your-secret-token

Bearer Token (OAuth 2.0):

json
{
  "headers": {
    "Authorization": "Bearer ${TOKEN}"
  }
}

API Key 在请求头中:

json
{
  "headers": {
    "X-API-Key": "${API_KEY}"
  }
}

基本认证:

json
{
  "headers": {
    "Authorization": "Basic ${BASIC_AUTH}"
  }
}

查询参数认证:

json
{
  "params": {
    "token": "${REGISTRY_TOKEN}"
  }
}

安全性: 环境变量从不会被记录,仅在运行时展开,每个注册表维护自己的认证上下文。切勿将实际令牌提交到版本控制。强烈建议对所有注册表 URL 使用 HTTPS。

资源验证: 所有从注册表获取的资源在安装前都会根据注册表项 schema 进行验证。

版本控制

你可以使用查询参数为注册表资源实现版本控制:

json
{
  "registries": {
    "versioned": {
      "url": "https://registry.example.com/{name}.json",
      "params": {
        "version": "v2"
      }
    }
  }
}

使用环境变量跨项目控制版本:

json
{
  "params": {
    "version": "${REGISTRY_VERSION}"
  }
}

依赖解析

资源可以跨不同注册表具有依赖关系:

json
{
  "registryDependencies": ["@shadcn/button", "@acme/input-form", "github:org/repo/helper"]
}

CLI 自动解析和安装所有来自各自注册表的依赖。解析过程:

  1. 清除注册表上下文以重新开始
  2. 从指定注册表获取主要资源
  3. 递归解析来自各自注册表的依赖
  4. 应用拓扑排序以确保正确的安装顺序
  5. 基于目标路径去重文件(后解析的覆盖先解析的)
  6. 深度合并配置(tailwind、cssVars、css、envVars)

当你安装 @custom/dashboard 依赖多个资源时:

json
{
  "registryDependencies": ["@shadcn/card", "@vendor/chart", "@custom/card"]
}

解析顺序:先安装 @shadcn/card,然后 @vendor/chart,最后 @custom/card(如果目标相同会覆盖)。

错误处理

  • 注册表未配置: Error: Registry "@unknown" is not configured.
  • 环境变量缺失: Error: Missing environment variable: ACME_TOKEN
  • 资源未找到: Error: Registry item "@acme/unknown" not found.
  • 认证失败: Error: 401 Unauthorized / Error: 403 Forbidden

认证 (Authentication)

使用认证保护你的注册表,用于私有的和个性化的组件。

认证让你运行私有注册表,控制谁能访问你的组件,并向不同的团队或用户提供不同的内容。

常见认证模式

基于令牌的认证(最常见):

json
{
  "registries": {
    "@internal": {
      "url": "https://registry.company.com/r/{name}.json",
      "headers": {
        "Authorization": "Bearer ${REGISTRY_TOKEN}"
      }
    }
  }
}

.env.local 中设置令牌:

text
REGISTRY_TOKEN=your-secret-token

API Key 认证:

json
{
  "headers": {
    "X-API-Key": "${API_KEY}"
  }
}

查询参数认证:

json
{
  "params": {
    "token": "${REGISTRY_TOKEN}"
  }
}

这将创建:https://registry.company.com/button.json?token=your_token

服务端实现

Next.js API 路由:

ts
// app/api/registry/[name]/route.ts
export async function GET(request: Request) {
  const token = request.headers.get("Authorization")?.replace("Bearer ", "")
  if (!token || token !== process.env.REGISTRY_TOKEN) {
    return Response.json({ error: "Unauthorized" }, { status: 401 })
  }
  // 返回注册表项
}

多注册表认证

使用命名空间注册表,你可以设置具有不同认证的多个注册表:

json
{
  "registries": {
    "public": "https://public.example.com/r/{name}.json",
    "@internal": {
      "url": "https://internal.company.com/r/{name}.json",
      "headers": { "Authorization": "Bearer ${INTERNAL_TOKEN}" }
    },
    "partner": {
      "url": "https://partner.example.com/r/{name}.json",
      "headers": { "X-API-Key": "${PARTNER_KEY}" }
    }
  }
}

安全最佳实践

  • 使用环境变量: 切勿将令牌提交到版本控制
  • 使用 HTTPS: 始终使用 HTTPS URL 以在传输过程中保护令牌
  • 添加速率限制: 保护你的注册表免受滥用
  • 轮换令牌: 定期更改访问令牌
  • 记录访问: 跟踪注册表访问以进行安全和审计

错误处理

shadcn CLI 优雅地处理认证错误:

  • 401 Unauthorized: 令牌无效或缺失
  • 403 Forbidden: 令牌对此资源没有权限
  • 429 Too Many Requests: 超过速率限制

你可以从注册表服务器返回带有自定义错误消息的响应体,CLI 将向用户显示这些消息:

json
{
  "error": "Your subscription has expired. Please renew at https://billing.example.com"
}

MCP 服务器 (Registry MCP)

注册表开发者的 MCP 支持。

shadcn MCP 服务器 可以与任何 shadcn 兼容的注册表一起开箱即用。你不需要做任何特殊操作来为你的注册表启用 MCP 支持。

先决条件

MCP 服务器通过请求你的注册表索引来工作。确保在注册表根目录有一个名为 registry 的注册表项文件。

例如,如果你的注册表托管在 https://acme.com/r/[name].json,你应该在 https://acme.com/r/registry.json 有一个文件。此文件必须是符合注册表 schema 的有效 JSON 文件。

配置 MCP

要求你的注册表消费者在他们的 components.json 文件中配置你的注册表并安装 shadcn MCP 服务器:

json
{
  "registries": {
    "acme": {
      "url": "https://acme.com/r/{name}.json"
    }
  }
}

然后在项目中运行:

bash
npx shadcn@latest mcp

重启 Claude Code 并尝试以下提示:

  • "Show me the components in the acme registry"
  • "Create a landing page using items from the acme registry"

你可以使用 Claude Code 中的 /mcp 命令调试 MCP 服务器。

最佳实践

MCP 兼容注册表的最佳实践:

  1. 清晰的描述: 添加简洁、信息丰富的描述,帮助 AI 助手理解注册表项的用途和用法。
  2. 正确的依赖: 准确列出所有 dependencies,以便 MCP 可以自动安装它们。
  3. 注册表依赖: 使用 registryDependencies 表示项之间的关系。
  4. 一致的命名: 使用 kebab-case 命名组件,并在整个注册表中保持一致。

Open in v0

将你的注册表与 "Open in v0" 集成。

如果你的注册表已托管并通过 URL 公开访问,你可以使用 https://v0.dev/chat/api/open?url=[URL] 端点在 v0 中打开注册表项。

例如:https://v0.dev/chat/api/open?url=https://ui.shadcn.com/r/styles/new-york/login-01.json

重要: "Open in v0" 不支持 cssVarscssenvVars、命名空间注册表或高级认证方法。

按钮

以下是如何在站点上添加 "Open in v0" 按钮的简单示例:

html
<a href="https://v0.dev/chat/api/open?url=https://acme.com/r/button.json" target="_blank">
  Open in v0
</a>

认证

"Open in v0" 仅支持查询参数认证。不支持命名空间注册表或像 Bearer 令牌或 API key 在请求头中的高级认证方法。

要使用 Open in v0 的认证,使用 token 查询参数:

text
https://v0.dev/chat/api/open?url=https://acme.com/r/button.json?token=YOUR_TOKEN

在你的注册表服务器上实现时:

  1. 检查 token 查询参数
  2. 验证令牌是否对认证系统有效
  3. 如果令牌无效或缺失,返回 401 Unauthorized 响应
  4. shadcn CLI 和 Open in v0 都会处理 401 响应并向用户显示适当消息

API 参考 (API Reference)

用于处理注册表、schema 和预设的程序化 API。

除了 CLI 之外,shadcn 包还公开了一组程序化 API。你可以使用它们获取和解析注册表项、验证注册表 JSON 以及构建自定义工具。

每个 API 都可以通过专用的子路径导入使用:

ts
import { getRegistry, getRegistryItems, resolveRegistryItems } from "shadcn/registry"
import { registrySchema, registryItemSchema } from "shadcn/schema"
import { encodePreset, decodePreset } from "shadcn/preset"

CLI 命令本身不是公共 API 的一部分。只有下面记录的导入被认为是稳定的。

shadcn/registry

获取和解析来自已配置注册表的项。

config: 可选,类型为 Partial<Config>,默认使用内置注册表。即你的 components.json 文件的解析内容。其 registries 字段将命名空间(例如 @acme)映射到 URL 以及访问所需的任何认证头或环境变量。

useCache: 类型为 boolean,默认 true。注册表响应在进程生命周期内缓存在内存中。保持启用用于一次性脚本和 CLI 运行。在长时间运行的进程(服务器、watcher、MCP 服务器)中设置为 false

getRegistry(name, config?, useCache?): 按名称获取单个注册表。

ts
const registry = await getRegistry("@shadcn")

getRegistryItems(names, config?, useCache?): 通过合格名称获取一个或多个注册表项。

ts
const items = await getRegistryItems(["@shadcn/button", "@shadcn/card"])

返回注册表项数组:

ts
[{ name: "button", type: "registry:ui", ... }, { name: "card", type: "registry:ui", ... }]

resolveRegistryItems(names, config?, useCache?): 解析多个项及其注册表依赖,合并为单个树。与 getRegistryItems 不同,它会遍历每个项的 registryDependencies 并将所有内容(文件、依赖、CSS 变量)扁平化为一个可安装的对象。

ts
const resolved = await resolveRegistryItems(["@acme/dashboard"])

getRegistries(config?, useCache?): 获取注册表目录。返回注册表条目数组。

searchRegistries(query, config?, useCache?): 使用模糊匹配跨一个或多个注册表搜索。

ts
const results = await searchRegistries("button")

loadRegistry(path?): 从磁盘读取并解析本地 registry.json 文件,跟踪所有 include 引用,返回注册表目录。返回的目录列出每个项但省略文件内容。

getRegistryloadRegistry 的区别:getRegistry 通过网络获取远程注册表,期望提供的目录已扁平化——它拒绝仍使用 include 的目录。loadRegistry 从磁盘读取本地 registry.json 并自行解析 include 引用。

loadRegistryItem(name, path?): 通过名称从本地 registry.json 读取单个项,文件内容从磁盘读取并内联。返回完全解析的注册表项及其文件内容。

getRegistryItemsloadRegistryItem 的区别:getRegistryItems 通过网络从远程注册表解析项。loadRegistryItem 从你的本地源文件按需构建单个项。

错误处理: 所有注册表函数都会抛出扩展 RegistryError 的类型化错误。可用的错误类包括:

  • RegistryErrorRegistryNotFoundErrorRegistryUnauthorizedError
  • RegistryForbiddenErrorRegistryFetchErrorRegistryNotConfiguredError
  • RegistryLocalFileErrorRegistryParseErrorRegistryValidationError
  • RegistryItemNotFoundErrorRegistriesIndexParseError
  • RegistryMissingEnvironmentVariablesErrorRegistryInvalidNamespaceError

shadcn/schema

用于验证 registry.jsonregistry-item.jsoncomponents.json 的 Zod schema。

ts
import { registrySchema, registryItemSchema } from "shadcn/schema"

主要 schema:

  • registrySchemaregistryItemSchemaregistryItemFileSchema
  • registryItemTypeSchemaregistryItemCssVarsSchema
  • registryItemTailwindSchemaregistryBaseColorSchema
  • configSchemapresetSchema

导出的推断类型:

  • RegistryRegistryItemRegistryBaseItem
  • RegistryFontItemPresetConfigJson

shadcn/preset

编码、解码和验证主题预设,以及主题编辑器使用的预设选项常量。

encodePreset(config):Partial<PresetConfig> 编码为简短的 URL 安全预设代码。省略的任何字段回退到 DEFAULT_PRESET_CONFIG

decodePreset(code): 将预设代码解码回完整的 PresetConfig。如果代码缺失或无效,返回 null

其他导出:isPresetCodeisValidPresetgenerateRandomConfiggenerateRandomPresettoBase62fromBase62

常量:PRESET_BASESPRESET_STYLESPRESET_BASE_COLORSPRESET_THEMESPRESET_ICON_LIBRARIESPRESET_FONTSPRESET_FONT_HEADINGSPRESET_RADIIPRESET_MENU_ACCENTSPRESET_MENU_COLORSPRESET_CHART_COLORSDEFAULT_PRESET_CONFIG

registry.json 规范

用于定义自定义组件注册表的 schema。

json
{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "acme",
  "homepage": "https://acme.com",
  "items": [
    {
      "name": "button",
      "type": "registry:ui",
      "files": [{ "path": "components/ui/button.tsx", "type": "registry:ui" }]
    }
  ]
}

公共 GitHub 仓库使用相同的源注册表格式。CLI 读取根 registry.json,解析 include,并从仓库安装文件。

字段定义

  • $schema(可选):用于指定 registry.json 文件的 schema URL。
  • name(必需):注册表的名称。用于数据属性和其他元数据。
  • homepage(可选):注册表的主页 URL。用于数据属性和其他元数据。
  • include(可选):用于从其他 registry.json 文件组合注册表。每个包含路径必须是相对于显式 registry.json 文件的路径。不支持文件夹简写。
json
{
  "include": ["components/ui/registry.json", "hooks/registry.json"]
}

被包含的 registry.json 文件可以省略 namehomepage——这些字段仅在根 registry.json 上必需。当 shadcn build 解析 include 时,项文件路径相对于声明该项的 registry.json 文件读取。生成的注册表输出是扁平化的且不包含 include。注册表项名称在已解析的注册表中(包括所有被包含的文件)必须唯一。

  • items(可选):注册表中的项。每个项必须实现 registry-item schema 规范。根 registry.json 必须至少定义 itemsinclude 中的一个。如果省略 items,则默认为空数组。

registry-item.json 规范

用于定义自定义注册表项的 schema。

json
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "button",
  "type": "registry:ui",
  "title": "Button",
  "description": "A native button component",
  "dependencies": ["@radix-ui/react-slot"],
  "registryDependencies": [],
  "files": [{ "path": "button.tsx", "type": "registry:ui" }]
}

字段定义

  • $schema(可选):指定 registry-item.json 文件的 schema URL。
  • name(必需):项的名称。用于在注册表中标识该项,在你的注册表中应唯一。
  • title(可选):人类可读的注册表项标题。保持简短和描述性。
  • description(可选):注册表项的描述。可以比 title 更长更详细。
  • type(必需):注册表项的类型。用于确定项在解析到项目时的类型和目标路径。

支持的类型:

类型描述
registry:base用于完整的设计系统
registry:block用于包含多个文件的复杂组件
registry:component用于简单组件
registry:font用于字体
registry:lib用于库和工具函数
registry:hook用于 hooks
registry:ui用于 UI 组件和单文件原语
registry:page用于页面或基于文件的路由
registry:file用于杂项文件
registry:style用于注册表样式,例如 new-york
registry:theme用于主题
registry:item用于通用注册表项
  • author(可选):注册表项的作者。
  • dependencies(可选):注册表项的 npm 包依赖。使用 @version 指定版本,例如 zod@^3.20.0
  • devDependencies(可选):注册表项的开发依赖。仅在开发期间需要的 npm 包。
  • registryDependencies(可选):注册表依赖。每个条目是一个项地址。

地址格式:

格式示例
shadcn/ui 内置项"button""input""select"
命名空间注册表项"@acme/input-form"
GitHub 注册表项"acme/ui/button""acme/ui/button#v1.2.0"
自定义 URL"https://example.com/r/hello-world.json"
本地文件路径"./hello-world.json"

注意: 裸名称保持现有行为。button 表示内置的 shadcn button 项,而不是来自同一 GitHub 仓库的项。对于同一仓库的 GitHub 依赖,使用完整的 GitHub 项地址。Refs 不会跨依赖继承。如果 GitHub 依赖需要可重现,将其固定到自己的标签或完整提交 SHA。

  • files(必需):注册表项的文件。每个文件具有 pathtype 和可选的 target 属性。

path 注册表中文件的路径。构建脚本使用此路径解析、转换和构建注册表 JSON 负载。

type 文件的类型。

target(可选): 文件在项目中应放置的位置。仅对 registry:pageregistry:file 类型必需。默认情况下,shadcn CLI 读取项目的 components.json 文件以确定目标路径。对于某些文件,如路由或配置,你可以手动指定目标路径。

使用 ~ 表示项目根目录,例如 ~/foo.config.js

你还可以使用注册表目标占位符将文件放在用户 components.json 配置的目录下:

占位符解析为
@components/aliases.components
@ui/aliases.ui
@lib/aliases.lib
@hooks/aliases.hooks

使用这些占位符时,注册表项会安装到项目配置的 shadcn 目录中,而无需硬编码 componentssrc 或工作区包路径。占位符后的任何内容都会被保留,因此 @ui/ai/prompt-input.tsx 安装在用户配置的 ui 目录下的 ai/prompt-input.tsx

target 决定文件写入的位置。它可以将文件指向与文件 type 不同的 shadcn 目录。

  • tailwind(已废弃,可选):用于 tailwind 配置,如 themepluginscontent。在 Tailwind v4 项目中改用 cssVars.theme
  • cssVars(可选):为注册表项定义 CSS 变量。
  • css(可选):使用 css 将新规则添加到项目的 CSS 文件中,例如 @layer base@layer components@utility@keyframes@plugin 等。
  • envVars(可选):为注册表项添加环境变量。变量会被添加到 .env.local.env 文件中。现有变量不会被覆盖。

重要: 使用 envVars 添加开发或示例变量。不要用于生产变量。

  • font(可选):对 registry:font 类型必需。配置字体系列、提供者、导入名称、CSS 变量和用于非 Next.js 项目的 npm 包。
属性类型必需描述
familystringCSS font-family 值
providerstring字体提供者。目前仅支持 google
importstringnext/font/google 的字体导入名称
variablestring字体的 CSS 变量名称(如 --font-sans
weightstring[]包含的字体粗细数组
subsetsstring[]包含的字体子集数组
selectorstring应用字体的 CSS 选择器。默认为 html
dependencystring非 Next.js 项目安装的 npm 包
  • docs(可选):在通过 CLI 安装注册表项时显示自定义文档或消息。
  • categories(可选):组织注册表项。
  • meta(可选):为注册表项添加额外的元数据。可以添加任何你希望注册表项可用的键/值对。

示例 (Examples)

注册表项的示例:样式、组件、CSS 变量等。

registry:style

自定义样式(扩展 shadcn/ui):npx shadcn init 时,它将安装 @tabler/icons-react 作为依赖,添加 login-01 block 和 calendar 组件,从远程注册表添加 editor,将 font-sans 变量设置为 Inter, sans-serif,并安装浅色和深色模式的 brand 颜色。

自定义样式(从头开始): 使用 extends: none 创建不扩展 shadcn/ui 的自定义样式。可以用于创建全新的样式,即自定义组件、CSS 变量、依赖等。

registry:theme

自定义主题和自定义颜色。支持添加自定义 CSS 变量和覆盖 Tailwind CSS 变量。

registry:block

自定义 block。可以安装一个 block 并覆盖其原语。

registry:ui

可重用的 UI 组件,可以具有依赖、注册表依赖和 CSS 变量。

registry:lib

工具库。用于共享辅助函数、常量或其他非组件代码。

registry:hook

自定义 React hook。

registry:font

安装 Google 字体。支持常规字体、等宽字体、衬线字体以及使用 selector 字段将字体应用于特定 CSS 选择器。

registry:base

完整的设计系统基础。定义项目的完整依赖、CSS 变量和配置。config 字段是 registry:base 类型独有的,接受 styleiconLibraryrsctsxrtlmenuColormenuAccenttailwindaliasesregistries 属性。

通用项(自 v2.9.0)

可以创建无需框架检测或 components.json 即可安装的通用项。要使项成为通用项(即框架无关),项中的所有文件必须具有明确的 target。适用于安装自定义 Cursor 规则、ESLint 配置等。

更多详细示例和完整的 JSON 代码示例,请参见 官方示例页面