create-element

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Create Element

创建元素

Creates new elements for the Elements registry (tryelements.dev).
为Elements注册表(tryelements.dev)创建新元素。

Quick Start

快速开始

Step 1: Scaffold
bun run .claude/skills/create-element/scripts/scaffold-element.ts <category> <name>

Step 2: Implement
Edit component following patterns in references/component-patterns.md

Step 3: Register
bun run build:registry && bun run dev
步骤1:脚手架初始化
bun run .claude/skills/create-element/scripts/scaffold-element.ts <category> <name>

步骤2:实现组件
参考references/component-patterns.md中的设计模式编辑组件

步骤3:注册组件
bun run build:registry && bun run dev

Context7 Integration (CRITICAL)

Context7 集成(至关重要)

Before implementing any component with external dependencies, fetch the latest documentation:
在实现任何带有外部依赖的组件之前,请获取最新文档:

Step 1: Resolve Library ID

步骤1:解析库ID

mcp__context7__resolve-library-id
  libraryName: "radix-ui"
  query: "dialog component accessibility patterns"
mcp__context7__resolve-library-id
  libraryName: "radix-ui"
  query: "dialog component accessibility patterns"

Step 2: Query Specific Docs

步骤2:查询特定文档

mcp__context7__query-docs
  libraryId: "/radix-ui/primitives"
  query: "Dialog API controlled vs uncontrolled portal usage"
mcp__context7__query-docs
  libraryId: "/radix-ui/primitives"
  query: "Dialog API controlled vs uncontrolled portal usage"

Common Libraries

常用库

LibraryQuery For
radix-ui
Primitives (Dialog, Dropdown, Tabs, Select)
next-themes
Theme provider, useTheme hook, hydration
cmdk
Command palette patterns
class-variance-authority
CVA variant patterns
embla-carousel-react
Carousel implementation
lucide-react
Icon usage patterns
库名称查询方向
radix-ui
基础组件(Dialog、Dropdown、Tabs、Select)
next-themes
主题提供者、useTheme钩子、水合处理
cmdk
命令面板设计模式
class-variance-authority
CVA变体设计模式
embla-carousel-react
轮播组件实现
lucide-react
图标使用模式

Element Types

元素类型

TypeExampleWhen to Use
registry:ui
button, card, inputBase UI primitives
registry:block
theme-switcher, polar-checkoutFeature-complete blocks
registry:example
button-demoUsage examples
类型示例使用场景
registry:ui
button、card、input基础UI原语
registry:block
theme-switcher、polar-checkout功能完整的区块组件
registry:example
button-demo使用示例

References

参考文档

Read these based on what you're doing:
  • references/registry-schema.md - When creating/editing registry-item.json
  • references/component-patterns.md - When writing component code (CVA, cn(), data-slot)
  • references/documentation.md - When creating MDX documentation
根据你的操作场景阅读以下文档:
  • references/registry-schema.md - 创建/编辑registry-item.json时参考
  • references/component-patterns.md - 编写组件代码时参考(CVA、cn()、data-slot)
  • references/documentation.md - 创建MDX文档时参考

Directory Structure

目录结构

registry/default/blocks/{category}/{component-name}/
├── registry-item.json          # Metadata
├── components/
│   └── elements/
│       └── {component}.tsx     # Main component
└── routes/                     # Optional demo routes
    ├── layout.tsx
    └── page.tsx
registry/default/blocks/{category}/{component-name}/
├── registry-item.json          # 元数据
├── components/
│   └── elements/
│       └── {component}.tsx     # 主组件
└── routes/                     # 可选的演示路由
    ├── layout.tsx
    └── page.tsx

Workflow Example: Theme Switcher Tabs

工作流示例:主题切换标签页

1. Scaffold

1. 脚手架初始化

bash
bun run .claude/skills/create-element/scripts/scaffold-element.ts theme theme-switcher-tabs
bash
bun run .claude/skills/create-element/scripts/scaffold-element.ts theme theme-switcher-tabs

2. Fetch Docs

2. 获取文档

mcp__context7__resolve-library-id
  libraryName: "next-themes"
  query: "useTheme hook theme switching"

mcp__context7__query-docs
  libraryId: "/pacocoursey/next-themes"
  query: "useTheme setTheme resolvedTheme hydration"
mcp__context7__resolve-library-id
  libraryName: "next-themes"
  query: "useTheme hook theme switching"

mcp__context7__query-docs
  libraryId: "/pacocoursey/next-themes"
  query: "useTheme setTheme resolvedTheme hydration"

3. Implement

3. 实现组件

Edit
registry/default/blocks/theme/theme-switcher-tabs/components/elements/theme-switcher-tabs.tsx
:
tsx
"use client";

import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";

export function ThemeSwitcherTabs({ className }: { className?: string }) {
  const { theme, setTheme } = useTheme();
  const [mounted, setMounted] = useState(false);

  useEffect(() => { setMounted(true); }, []);

  if (!mounted) return <div className="h-8 w-24 animate-pulse bg-muted rounded" />;

  return (
    <div data-slot="theme-switcher-tabs" className={cn("...", className)}>
      {/* Implementation */}
    </div>
  );
}
编辑
registry/default/blocks/theme/theme-switcher-tabs/components/elements/theme-switcher-tabs.tsx
tsx
"use client";

import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";

export function ThemeSwitcherTabs({ className }: { className?: string }) {
  const { theme, setTheme } = useTheme();
  const [mounted, setMounted] = useState(false);

  useEffect(() => { setMounted(true); }, []);

  if (!mounted) return <div className="h-8 w-24 animate-pulse bg-muted rounded" />;

  return (
    <div data-slot="theme-switcher-tabs" className={cn("...", className)}>
      {/* 实现代码 */}
    </div>
  );
}

4. Update registry-item.json

4. 更新registry-item.json

json
{
  "name": "theme-switcher-tabs",
  "type": "registry:ui",
  "title": "Theme Switcher Tabs",
  "description": "Tab-based theme switcher with Light/Dark/System options",
  "registryDependencies": [],
  "dependencies": ["next-themes"],
  "files": [...],
  "docs": "Requires ThemeProvider. Tab-style theme switcher with system support."
}
json
{
  "name": "theme-switcher-tabs",
  "type": "registry:ui",
  "title": "Theme Switcher Tabs",
  "description": "Tab-based theme switcher with Light/Dark/System options",
  "registryDependencies": [],
  "dependencies": ["next-themes"],
  "files": [...],
  "docs": "Requires ThemeProvider. Tab-style theme switcher with system support."
}

5. Build & Test

5. 构建与测试

bash
bun run build:registry
bun run dev
bash
bun run build:registry
bun run dev

Verification Checklist

验证清单

  • registry-item.json has all required fields ($schema, name, type, title, description, files)
  • Component exports PascalCase function (e.g.,
    export function ThemeSwitcherTabs
    )
  • Uses
    cn()
    for className merging
  • Has
    data-slot
    attribute on root element
  • Client components have
    "use client"
    directive
  • Hydration-safe if using theme/client state
  • bun run build:registry
    succeeds
  • Component renders correctly in dev
  • If new category: Provider grouping configured (see "Creating New Categories" section)
  • registry-item.json包含所有必填字段($schema、name、type、title、description、files)
  • 组件导出使用大驼峰命名的函数(例如:
    export function ThemeSwitcherTabs
  • 使用
    cn()
    合并className
  • 根元素带有
    data-slot
    属性
  • 客户端组件带有
    "use client"
    指令
  • 依赖主题/客户端状态的组件具备水合安全性
  • bun run build:registry
    执行成功
  • 组件在开发环境中正确渲染
  • 如果是新分类:已配置提供者分组(参考“创建新分类”章节)

Commands

命令

bash
undefined
bash
undefined

Scaffold new element

初始化新元素

bun run .claude/skills/create-element/scripts/scaffold-element.ts <category> <name>
bun run .claude/skills/create-element/scripts/scaffold-element.ts <category> <name>

Build registry

构建注册表

bun run build:registry
bun run build:registry

Development server

开发服务器

bun run dev
bun run dev

Lint/format

代码检查/格式化

bun run lint bun run format
undefined
bun run lint bun run format
undefined

Common Patterns

常见设计模式

Simple Component (No Dependencies)

简单组件(无依赖)

tsx
import { cn } from "@/lib/utils";

interface BadgeProps extends React.ComponentProps<"span"> {}

export function Badge({ className, ...props }: BadgeProps) {
  return (
    <span
      data-slot="badge"
      className={cn("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold", className)}
      {...props}
    />
  );
}
tsx
import { cn } from "@/lib/utils";

interface BadgeProps extends React.ComponentProps<"span"> {}

export function Badge({ className, ...props }: BadgeProps) {
  return (
    <span
      data-slot="badge"
      className={cn("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold", className)}
      {...props}
    />
  );
}

With CVA Variants

带有CVA变体的组件

tsx
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const badgeVariants = cva("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold", {
  variants: {
    variant: {
      default: "bg-primary text-primary-foreground",
      secondary: "bg-secondary text-secondary-foreground",
      destructive: "bg-destructive text-white",
    },
  },
  defaultVariants: {
    variant: "default",
  },
});

interface BadgeProps extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {}

export function Badge({ className, variant, ...props }: BadgeProps) {
  return (
    <span
      data-slot="badge"
      className={cn(badgeVariants({ variant, className }))}
      {...props}
    />
  );
}

export { badgeVariants };
tsx
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const badgeVariants = cva("inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold", {
  variants: {
    variant: {
      default: "bg-primary text-primary-foreground",
      secondary: "bg-secondary text-secondary-foreground",
      destructive: "bg-destructive text-white",
    },
  },
  defaultVariants: {
    variant: "default",
  },
});

interface BadgeProps extends React.ComponentProps<"span">, VariantProps<typeof badgeVariants> {}

export function Badge({ className, variant, ...props }: BadgeProps) {
  return (
    <span
      data-slot="badge"
      className={cn(badgeVariants({ variant, className }))}
      {...props}
    />
  );
}

export { badgeVariants };

With External Dependency (Radix)

带有外部依赖的组件(Radix)

tsx
"use client";

import * as DialogPrimitive from "@radix-ui/react-dialog";
import { cn } from "@/lib/utils";

export function Dialog({ children, ...props }: DialogPrimitive.DialogProps) {
  return <DialogPrimitive.Root {...props}>{children}</DialogPrimitive.Root>;
}

export function DialogTrigger({ className, ...props }: DialogPrimitive.DialogTriggerProps) {
  return <DialogPrimitive.Trigger data-slot="dialog-trigger" className={cn("", className)} {...props} />;
}
tsx
"use client";

import * as DialogPrimitive from "@radix-ui/react-dialog";
import { cn } from "@/lib/utils";

export function Dialog({ children, ...props }: DialogPrimitive.DialogProps) {
  return <DialogPrimitive.Root {...props}>{children}</DialogPrimitive.Root>;
}

export function DialogTrigger({ className, ...props }: DialogPrimitive.DialogTriggerProps) {
  return <DialogPrimitive.Trigger data-slot="dialog-trigger" className={cn("", className)} {...props} />;
}

Pitfalls to Avoid

注意事项

  • Don't forget
    "use client"
    for components using hooks
  • Don't hardcode colors - use CSS variables (
    text-foreground
    ,
    bg-background
    )
  • Don't skip hydration handling for theme-dependent components
  • Don't use
    any
    types - properly type props
  • Don't forget to run
    build:registry
    after changes
  • 不要忘记为使用钩子的组件添加
    "use client"
    指令
  • 不要硬编码颜色 - 使用CSS变量(
    text-foreground
    bg-background
  • 不要跳过依赖主题的组件的水合处理
  • 不要使用
    any
    类型 - 正确定义props类型
  • 不要忘记在修改后运行
    build:registry

Creating New Categories (Provider Grouping)

创建新分类(提供者分组)

When creating a new category of components (not just a new component in an existing category), you must configure the provider system for proper landing page display. Otherwise, each component will appear as a separate "Coming Soon" card.
当创建新的组件分类(而不是现有分类中的新组件)时,必须配置提供者系统以确保落地页正确显示。否则,每个组件都会显示为单独的“即将推出”卡片。

When This Applies

适用场景

  • Creating a new integration (e.g.,
    charts/
    ,
    payments/
    ,
    analytics/
    )
  • Adding multiple related components that should be grouped together
  • The category doesn't exist in the current provider list
  • 创建新的集成(例如:
    charts/
    payments/
    analytics/
  • 添加多个相关组件并希望将它们分组展示
  • 当前提供者列表中不存在该分类

Two-File Setup Required

需配置两个文件

1.
src/lib/registry-loader.ts

1.
src/lib/registry-loader.ts

Add grouping logic in
getProviderFromName()
(~line 53):
typescript
// Special case: chart components go to "charts" provider
if (
  name === "area-chart" ||
  name === "bar-chart-vertical" ||
  name === "heatmap-grid" ||
  name === "growth-stats"
) {
  return "charts";
}
Add provider metadata in
getProviderMetadata()
(~line 156):
typescript
charts: {
  displayName: "Charts",
  description: "Data visualization primitives - area charts, heatmaps, bar charts",
  category: "DATA VIZ",
  brandColor: "#14B8A6",
},
getProviderFromName()
中添加分组逻辑
(约第53行):
typescript
// 特殊情况:图表组件归到"charts"提供者
if (
  name === "area-chart" ||
  name === "bar-chart-vertical" ||
  name === "heatmap-grid" ||
  name === "growth-stats"
) {
  return "charts";
}
getProviderMetadata()
中添加提供者元数据
(约第156行):
typescript
charts: {
  displayName: "Charts",
  description: "Data visualization primitives - area charts, heatmaps, bar charts",
  category: "DATA VIZ",
  brandColor: "#14B8A6",
},

2.
src/lib/providers.tsx

2.
src/lib/providers.tsx

Add provider config in
providerConfig
(~line 46):
typescript
charts: {
  isEnabled: true,
  displayName: "Charts",
  description: "Data visualization primitives - area charts, heatmaps, bar charts",
  category: "Data Viz",
},
Add provider icon in
ProviderIcon()
(~line 196):
typescript
charts: <ChartIcon className="w-10 h-10" />,
Create the icon at
src/components/icons/{provider}.tsx
if needed.
providerConfig
中添加提供者配置
(约第46行):
typescript
charts: {
  isEnabled: true,
  displayName: "Charts",
  description: "Data visualization primitives - area charts, heatmaps, bar charts",
  category: "Data Viz",
},
ProviderIcon()
中添加提供者图标
(约第196行):
typescript
charts: <ChartIcon className="w-10 h-10" />,
如果需要,在
src/components/icons/{provider}.tsx
中创建图标。

Provider Metadata Fields

提供者元数据字段

FieldExamplePurpose
displayName
"Charts"Landing page card title
description
"Data visualization..."Card description
category
"DATA VIZ"Badge shown on card
brandColor
"#14B8A6"Diagonal hatch pattern color
字段示例用途
displayName
"Charts"落地页卡片标题
description
"Data visualization..."卡片描述
category
"DATA VIZ"卡片上显示的标签
brandColor
"#14B8A6"对角填充图案颜色

Existing Providers (Reference)

现有提供者(参考)

Provider KeyDisplay NameCategory
clerk
ClerkUSER MGMT
polar
PolarMONETIZATION
theme
Theme SwitcherUI
logos
Brand LogosBRAND
uploadthing
UploadThingFILES
tinte
TinteTHEMING
charts
ChartsDATA VIZ
提供者Key显示名称分类
clerk
ClerkUSER MGMT
polar
PolarMONETIZATION
theme
Theme SwitcherUI
logos
Brand LogosBRAND
uploadthing
UploadThingFILES
tinte
TinteTHEMING
charts
ChartsDATA VIZ

Naming Convention

命名约定

The default extraction uses the first part before hyphen:
  • clerk-sign-in
    clerk
  • polar-checkout
    polar
Add special cases when:
  • Components share a category but have different prefixes (e.g.,
    area-chart
    ,
    heatmap-grid
    )
  • You want a custom provider name (e.g.,
    theme-switcher-*
    theme
    )
默认提取连字符前的第一部分作为分组依据:
  • clerk-sign-in
    clerk
  • polar-checkout
    polar
在以下情况添加特殊规则:
  • 组件属于同一分类但前缀不同(例如:
    area-chart
    heatmap-grid
  • 你需要自定义提供者名称(例如:
    theme-switcher-*
    theme

MDX Documentation Setup

MDX文档设置

New categories also need MDX documentation files for the docs pages to render properly:
新分类还需要配置MDX文档文件,以便文档页正确渲染:

1. Create Demo Components

1. 创建演示组件

For each component, create a demo in
/registry/default/examples/{component}-demo.tsx
:
tsx
"use client";

import { MyComponent } from "@/registry/default/blocks/{category}/{component}/components/elements/{component}";

export default function MyComponentDemo() {
  return (
    <div className="flex items-center justify-center p-4">
      <MyComponent />
    </div>
  );
}
为每个组件在
/registry/default/examples/{component}-demo.tsx
中创建演示:
tsx
"use client";

import { MyComponent } from "@/registry/default/blocks/{category}/{component}/components/elements/{component}";

export default function MyComponentDemo() {
  return (
    <div className="flex items-center justify-center p-4">
      <MyComponent />
    </div>
  );
}

2. Register in MDX Components

2. 在MDX组件中注册

Add imports and mappings in
/src/mdx-components.tsx
:
tsx
// Add import
import MyComponentDemo from "@/registry/default/examples/my-component-demo";

// Add to getMDXComponents return object
MyComponent: MyComponentDemo,
/src/mdx-components.tsx
中添加导入和映射:
tsx
// 添加导入
import MyComponentDemo from "@/registry/default/examples/my-component-demo";

// 添加到getMDXComponents返回对象
MyComponent: MyComponentDemo,

3. Create Provider MDX

3. 创建提供者MDX文件

Create
/src/content/providers/{provider}.mdx
:
mdx
---
title: My Provider
description: Description of the category
category: CATEGORY TAG
brandColor: "#hexcolor"
---
创建
/src/content/providers/{provider}.mdx
mdx
---
title: My Provider
description: Description of the category
category: CATEGORY TAG
brandColor: "#hexcolor"
---

Overview

概述

Brief description.
简要描述。

Components

组件

Component Name

组件名称

<ComponentPreviewItem componentKey="component-name" installUrl="@elements/component-name" category="Category" name="Component Name"
<ComponentName /> </ComponentPreviewItem> ```
<ComponentPreviewItem componentKey="component-name" installUrl="@elements/component-name" category="Category" name="Component Name"
<ComponentName /> </ComponentPreviewItem> ```

4. Create Component MDX Files

4. 创建组件MDX文件

Create
/src/content/components/{provider}/{component}.mdx
for each component:
mdx
---
title: Component Name
description: Brief description
---

<ComponentPreviewItem
  componentKey="component-name"
  installUrl="@elements/component-name"
  category="Category"
  name="Component Name"
>
  <ComponentName />
</ComponentPreviewItem>
为每个组件创建
/src/content/components/{provider}/{component}.mdx
mdx
---
title: Component Name
description: Brief description
---

<ComponentPreviewItem
  componentKey="component-name"
  installUrl="@elements/component-name"
  category="Category"
  name="Component Name"
>
  <ComponentName />
</ComponentPreviewItem>

Overview

概述

Installation

安装

Usage

使用

Props

Props

Features

特性

undefined
undefined