Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计异常

shadcn-uishadcn/ui 组件

Agent Skill

用于辅助界面设计、视觉规范、排版、配色、布局和交互体验优化。它适合让 Agent 根据产品场景整理页面结构、生成 UI 方案、检查视觉一致性或改进组件层级。使用时需要结合现有品牌、设计系统和用户任务,不应只堆装饰元素;涉及真实页面改动时,应通过截图或浏览器预览检查文本溢出、对齐和响应式表现。

总安装

894

周安装

38

GitHub Stars

25

下载量

313
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:shadcn-ui(shadcn/ui 组件)
来源仓库:https://github.com/oimiragieo/agent-studio
仓库路径:skills/shadcn-ui
安装命令:
npx skills add https://github.com/oimiragieo/agent-studio --skill shadcn-ui
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/oimiragieo/agent-studio --skill shadcn-ui

简介

shadcn-ui 用于界面设计与视觉规范优化,支持排版、配色和交互体验改进。

  • 适用于页面结构整理、UI 方案生成和组件层级优化。
  • 通过 npx skills add 命令从 GitHub 仓库安装并使用。
  • 需结合品牌和设计系统使用,避免堆砌装饰元素。
  • 页面改动后应通过截图或预览检查响应式表现。shadcn-ui 属于前端设计类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

shadcn/ui Expert

Comprehensive guide to building UIs with shadcn/ui -- the copy-paste component library built on Radix UI primitives and Tailwind CSS. Components are not installed as a dependency; they are copied into your project for full ownership and customization.

When to Apply

Use this skill when:

  • Adding shadcn/ui components to a React or Next.js project
  • Customizing component styles, variants, or behavior
  • Setting up Tailwind CSS v4 theming with CSS variables
  • Implementing dark mode with shadcn/ui
  • Building accessible forms, dialogs, or data tables
  • Choosing between shadcn/ui components and custom implementations

Core Concepts

shadcn/ui is NOT a Component Library

shadcn/ui is a collection of reusable components that you copy into your project. Key differences from traditional libraries:

  • No npm package dependency -- components live in your codebase
  • Full ownership -- modify any component freely
  • Radix UI primitives -- accessible, unstyled headless components under the hood
  • Tailwind CSS -- all styling via utility classes and CSS variables
  • CLI-driven -- npx shadcn@latest add button copies component code

Architecture

Your Project
  components/
    ui/              <- shadcn/ui components live here
      button.tsx
      dialog.tsx
      input.tsx
      ...
  lib/
    utils.ts         <- cn() utility (clsx + tailwind-merge)

Setup

Next.js App Router (Recommended)

# Initialize shadcn/ui in existing Next.js project
npx shadcn@latest init

# This creates:
# - components.json (configuration)
# - lib/utils.ts (cn utility)
# - Tailwind CSS variable theme in globals.css

components.json Configuration:

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "tailwind.config.ts",
    "css": "app/globals.css",
    "baseColor": "zinc",
    "cssVariables": true
  },
  "aliases": {
    "components": "@/components",
    "utils": "@/lib/utils",
    "ui": "@/components/ui",
    "lib": "@/lib",
    "hooks": "@/hooks"
  }
}

Vite + React

# Initialize
npx shadcn@latest init

# Vite requires path aliases in vite.config.ts:
import path from 'path';

export default defineConfig({
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});

Next.js Pages Router

Same as App Router but set rsc: false in components.json since Pages Router does not support React Server Components.

Adding Components

# Add a single component
npx shadcn@latest add button

# Add multiple components
npx shadcn@latest add button card input label

# Add all components
npx shadcn@latest add --all

# View available components
npx shadcn@latest add --list

The cn() Utility

Every shadcn/ui component uses cn() for conditional class merging:

// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

cn() combines clsx (conditional classes) with tailwind-merge (resolves Tailwind conflicts):

<Button
  className={cn(
    'bg-primary text-white',
    isDisabled && 'opacity-50 cursor-not-allowed',
    size === 'lg' && 'px-8 py-4 text-lg'
  )}
>
  Submit
</Button>

Theming with CSS Variables

Tailwind CSS v4 Theme Setup

shadcn/ui uses CSS custom properties for theming, enabling runtime theme switching:

/* globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 240 10% 3.9%;
    --card: 0 0% 100%;
    --card-foreground: 240 10% 3.9%;
    --popover: 0 0% 100%;
    --popover-foreground: 240 10% 3.9%;
    --primary: 240 5.9% 10%;
    --primary-foreground: 0 0% 98%;
    --secondary: 240 4.8% 95.9%;
    --secondary-foreground: 240 5.9% 10%;
    --muted: 240 4.8% 95.9%;
    --muted-foreground: 240 3.8% 46.1%;
    --accent: 240 4.8% 95.9%;
    --accent-foreground: 240 5.9% 10%;
    --destructive: 0 84.2% 60.2%;
    --destructive-foreground: 0 0% 98%;
    --border: 240 5.9% 90%;
    --input: 240 5.9% 90%;
    --ring: 240 5.9% 10%;
    --radius: 0.5rem;
  }

  .dark {
    --background: 240 10% 3.9%;
    --foreground: 0 0% 98%;
    --card: 240 10% 3.9%;
    --card-foreground: 0 0% 98%;
    --popover: 240 10% 3.9%;
    --popover-foreground: 0 0% 98%;
    --primary: 0 0% 98%;
    --primary-foreground: 240 5.9% 10%;
    --secondary: 240 3.7% 15.9%;
    --secondary-foreground: 0 0% 98%;
    --muted: 240 3.7% 15.9%;
    --muted-foreground: 240 5% 64.9%;
    --accent: 240 3.7% 15.9%;
    --accent-foreground: 0 0% 98%;
    --destructive: 0 62.8% 30.6%;
    --destructive-foreground: 0 0% 98%;
    --border: 240 3.7% 15.9%;
    --input: 240 3.7% 15.9%;
    --ring: 240 4.9% 83.9%;
  }
}

Dark Mode Implementation

Use next-themes for Next.js dark mode:

// app/providers.tsx
'use client';

import { ThemeProvider } from 'next-themes';

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
      {children}
    </ThemeProvider>
  );
}

// app/layout.tsx
import { Providers } from './providers';

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Toggle component:

'use client';

import { useTheme } from 'next-themes';
import { Button } from '@/components/ui/button';
import { Moon, Sun } from 'lucide-react';

export function ThemeToggle() {
  const { setTheme, theme } = useTheme();

  return (
    <Button
      variant="ghost"
      size="icon"
      onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}
    >
      <Sun className="h-5 w-5 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0" />
      <Moon className="absolute h-5 w-5 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100" />
      <span className="sr-only">Toggle theme</span>
    </Button>
  );
}

Common Component Patterns

Forms with React Hook Form + Zod

'use client';

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { Button } from '@/components/ui/button';
import {
  Form,
  FormControl,
  FormField,
  FormItem,
  FormLabel,
  FormMessage,
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';

const formSchema = z.object({
  email: z.string().email('Invalid email address'),
  password: z.string().min(8, 'Password must be at least 8 characters'),
});

export function LoginForm() {
  const form = useForm<z.infer<typeof formSchema>>({
    resolver: zodResolver(formSchema),
    defaultValues: { email: '', password: '' },
  });

  function onSubmit(values: z.infer<typeof formSchema>) {
    console.log(values);
  }

  return (
    <Form {...form}>
      <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
        <FormField
          control={form.control}
          name="email"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Email</FormLabel>
              <FormControl>
                <Input placeholder="name@example.com" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <FormField
          control={form.control}
          name="password"
          render={({ field }) => (
            <FormItem>
              <FormLabel>Password</FormLabel>
              <FormControl>
                <Input type="password" {...field} />
              </FormControl>
              <FormMessage />
            </FormItem>
          )}
        />
        <Button type="submit">Sign In</Button>
      </form>
    </Form>
  );
}

Data Tables with TanStack Table

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from '@/components/ui/table';
import { ColumnDef, flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table';

interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[];
  data: TData[];
}

export function DataTable<TData, TValue>({ columns, data }: DataTableProps<TData, TValue>) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

  return (
    <div className="rounded-md border">
      <Table>
        <TableHeader>
          {table.getHeaderGroups().map(headerGroup => (
            <TableRow key={headerGroup.id}>
              {headerGroup.headers.map(header => (
                <TableHead key={header.id}>
                  {flexRender(header.column.columnDef.header, header.getContext())}
                </TableHead>
              ))}
            </TableRow>
          ))}
        </TableHeader>
        <TableBody>
          {table.getRowModel().rows.map(row => (
            <TableRow key={row.id}>
              {row.getVisibleCells().map(cell => (
                <TableCell key={cell.id}>
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </TableCell>
              ))}
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </div>
  );
}

Responsive Dialog / Drawer Pattern

Use Dialog on desktop and Drawer on mobile:

'use client';

import { useMediaQuery } from '@/hooks/use-media-query';
import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog';
import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer';
import { Button } from '@/components/ui/button';

export function ResponsiveModal({ children }: { children: React.ReactNode }) {
  const isDesktop = useMediaQuery('(min-width: 768px)');

  if (isDesktop) {
    return (
      <Dialog>
        <DialogTrigger asChild>
          <Button>Open</Button>
        </DialogTrigger>
        <DialogContent>{children}</DialogContent>
      </Dialog>
    );
  }

  return (
    <Drawer>
      <DrawerTrigger asChild>
        <Button>Open</Button>
      </DrawerTrigger>
      <DrawerContent>{children}</DrawerContent>
    </Drawer>
  );
}

Accessibility Patterns

shadcn/ui components are built on Radix UI, which provides:

  • Full keyboard navigation (Tab, Arrow keys, Enter, Escape)
  • ARIA attributes (roles, states, properties)
  • Focus management (trapping, restoration)
  • Screen reader announcements

Key Accessibility Features by Component

ComponentKeyboardARIAFocus Trap
ButtonEnter/Space to activaterole="button"No
DialogEscape to closerole="dialog", aria-modalYes
Dropdown MenuArrow keys to navigaterole="menu", role="menuitem"Yes
SelectArrow keys, type-aheadrole="listbox", role="option"Yes
TabsArrow keys between tabsrole="tablist", role="tab"No
ToastAuto-announcerole="status", aria-liveNo
TooltipFocus/hover to showrole="tooltip"No

Custom Accessibility Enhancements

// Always provide labels for interactive elements
<Button aria-label="Close dialog">
  <X className="h-4 w-4" />
</Button>

// Use sr-only for visual-only content
<span className="sr-only">Loading...</span>

// Announce dynamic content
<div aria-live="polite" aria-atomic="true">
  {statusMessage}
</div>

Anti-Patterns

  • Do NOT install shadcn/ui as an npm package -- use the CLI to copy components
  • Do NOT modify Radix primitives directly -- extend via the shadcn wrapper component
  • Do NOT use hardcoded colors -- always use CSS variable theme tokens
  • Do NOT skip the cn() utility -- it prevents Tailwind class conflicts
  • Do NOT forget suppressHydrationWarning on <html> when using next-themes
  • Do NOT nest interactive elements (button inside button, link inside button)

Iron Laws

  1. NEVER install shadcn/ui as a package dependency — components must be copied into the project for full ownership
  2. ALWAYS use the cn() utility for conditional class names to prevent Tailwind class conflicts
  3. NEVER hardcode colors — always use CSS variable theme tokens for theming consistency
  4. ALWAYS use Radix UI primitives through the shadcn/ui abstraction, not directly
  5. NEVER nest interactive elements (button inside button, link inside button) — violates accessibility standards

Anti-Patterns

Anti-PatternWhy It FailsCorrect Approach
Installing as a packageComponent source is locked; no customization possibleUse npx shadcn@latest add to copy components into your project
Hardcoding color valuesTheme switching breaks; dark mode failsUse CSS variable tokens (bg-background, text-foreground, etc.)
Skipping cn() utilityTailwind class conflicts produce unpredictable stylesAlways merge classes with cn() from @/lib/utils
Direct Radix UI primitive useMissing shadcn styling and accessibility wiringUse shadcn components that wrap Radix primitives with correct classes
Missing suppressHydrationWarningHydration mismatch errors with next-themes dark modeAdd suppressHydrationWarning to <html> when using next-themes

Memory Protocol (MANDATORY)

Before starting: Read .claude/context/memory/learnings.md

After completing:

  • New pattern -> .claude/context/memory/learnings.md
  • Issue found -> .claude/context/memory/issues.md
  • Decision made -> .claude/context/memory/decisions.md
ASSUME INTERRUPTION: If it's not in memory, it didn't happen.

References

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.78%
按下载量换算112

Claude

25.98%
按下载量换算81

Cursor

19.12%
按下载量换算60

Gemini CLI

9.55%
按下载量换算30

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

未通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills