sdd-jc-methodology 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/.claude/commands/sdd-archive.md +122 -0
  2. package/.claude/commands/sdd-constitution.md +240 -0
  3. package/.claude/commands/sdd-execute.md +132 -0
  4. package/.claude/commands/sdd-propose.md +149 -0
  5. package/.claude/commands/sdd-seo.md +251 -0
  6. package/.claude/commands/sdd-specify.md +264 -0
  7. package/.claude/commands/sdd-test.md +128 -0
  8. package/.claude/commands/sdd-validate.md +165 -0
  9. package/.claude/skills/api-design-principles/SKILL.md +528 -0
  10. package/.claude/skills/api-design-principles/assets/api-design-checklist.md +155 -0
  11. package/.claude/skills/api-design-principles/assets/rest-api-template.py +182 -0
  12. package/.claude/skills/api-design-principles/references/graphql-schema-design.md +583 -0
  13. package/.claude/skills/api-design-principles/references/rest-best-practices.md +408 -0
  14. package/.claude/skills/aws-serverless/SKILL.md +323 -0
  15. package/.claude/skills/brainstorming/SKILL.md +96 -0
  16. package/.claude/skills/error-handling-patterns/SKILL.md +641 -0
  17. package/.claude/skills/frontend-design/LICENSE.txt +177 -0
  18. package/.claude/skills/frontend-design/SKILL.md +272 -0
  19. package/.claude/skills/nestjs-expert/SKILL.md +552 -0
  20. package/.claude/skills/product-manager-toolkit/SKILL.md +351 -0
  21. package/.claude/skills/product-manager-toolkit/references/prd_templates.md +317 -0
  22. package/.claude/skills/product-manager-toolkit/scripts/customer_interview_analyzer.py +441 -0
  23. package/.claude/skills/product-manager-toolkit/scripts/rice_prioritizer.py +296 -0
  24. package/.claude/skills/react-doctor/AGENTS.md +15 -0
  25. package/.claude/skills/react-doctor/SKILL.md +19 -0
  26. package/.claude/skills/shadcn-ui/SKILL.md +1677 -0
  27. package/.claude/skills/shadcn-ui/references/learn.md +145 -0
  28. package/.claude/skills/shadcn-ui/references/official-ui-reference.md +1725 -0
  29. package/.claude/skills/shadcn-ui/references/reference.md +586 -0
  30. package/.claude/skills/shadcn-ui/references/ui-reference.md +1578 -0
  31. package/.claude/skills/stitch-design/README.md +50 -0
  32. package/.claude/skills/stitch-design/SKILL.md +84 -0
  33. package/.claude/skills/stitch-design/examples/DESIGN.md +22 -0
  34. package/.claude/skills/stitch-design/examples/enhanced-prompt.md +28 -0
  35. package/.claude/skills/stitch-design/references/design-mappings.md +45 -0
  36. package/.claude/skills/stitch-design/references/prompt-keywords.md +114 -0
  37. package/.claude/skills/stitch-design/references/tool-schemas.md +76 -0
  38. package/.claude/skills/stitch-design/workflows/edit-design.md +44 -0
  39. package/.claude/skills/stitch-design/workflows/generate-design-md.md +63 -0
  40. package/.claude/skills/stitch-design/workflows/text-to-design.md +47 -0
  41. package/.claude/skills/systematic-debugging/CREATION-LOG.md +119 -0
  42. package/.claude/skills/systematic-debugging/SKILL.md +296 -0
  43. package/.claude/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  44. package/.claude/skills/systematic-debugging/condition-based-waiting.md +115 -0
  45. package/.claude/skills/systematic-debugging/defense-in-depth.md +122 -0
  46. package/.claude/skills/systematic-debugging/find-polluter.sh +63 -0
  47. package/.claude/skills/systematic-debugging/root-cause-tracing.md +169 -0
  48. package/.claude/skills/systematic-debugging/test-academic.md +14 -0
  49. package/.claude/skills/systematic-debugging/test-pressure-1.md +58 -0
  50. package/.claude/skills/systematic-debugging/test-pressure-2.md +68 -0
  51. package/.claude/skills/systematic-debugging/test-pressure-3.md +69 -0
  52. package/.claude/skills/tailwind-design-system/SKILL.md +874 -0
  53. package/.claude/skills/ui-ux-pro-max/SKILL.md +377 -0
  54. package/.claude/skills/ui-ux-pro-max/data/charts.csv +26 -0
  55. package/.claude/skills/ui-ux-pro-max/data/colors.csv +97 -0
  56. package/.claude/skills/ui-ux-pro-max/data/icons.csv +101 -0
  57. package/.claude/skills/ui-ux-pro-max/data/landing.csv +31 -0
  58. package/.claude/skills/ui-ux-pro-max/data/products.csv +97 -0
  59. package/.claude/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  60. package/.claude/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  61. package/.claude/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  62. package/.claude/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  63. package/.claude/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  64. package/.claude/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  65. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  66. package/.claude/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  67. package/.claude/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  68. package/.claude/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  69. package/.claude/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  70. package/.claude/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  71. package/.claude/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  72. package/.claude/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  73. package/.claude/skills/ui-ux-pro-max/data/styles.csv +68 -0
  74. package/.claude/skills/ui-ux-pro-max/data/typography.csv +58 -0
  75. package/.claude/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  76. package/.claude/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  77. package/.claude/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  78. package/.claude/skills/ui-ux-pro-max/scripts/core.py +253 -0
  79. package/.claude/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  80. package/.claude/skills/ui-ux-pro-max/scripts/search.py +114 -0
  81. package/.claude/skills/vercel-react-best-practices/AGENTS.md +2934 -0
  82. package/.claude/skills/vercel-react-best-practices/SKILL.md +136 -0
  83. package/.claude/skills/vercel-react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  84. package/.claude/skills/vercel-react-best-practices/rules/advanced-init-once.md +42 -0
  85. package/.claude/skills/vercel-react-best-practices/rules/advanced-use-latest.md +39 -0
  86. package/.claude/skills/vercel-react-best-practices/rules/async-api-routes.md +38 -0
  87. package/.claude/skills/vercel-react-best-practices/rules/async-defer-await.md +80 -0
  88. package/.claude/skills/vercel-react-best-practices/rules/async-dependencies.md +51 -0
  89. package/.claude/skills/vercel-react-best-practices/rules/async-parallel.md +28 -0
  90. package/.claude/skills/vercel-react-best-practices/rules/async-suspense-boundaries.md +99 -0
  91. package/.claude/skills/vercel-react-best-practices/rules/bundle-barrel-imports.md +59 -0
  92. package/.claude/skills/vercel-react-best-practices/rules/bundle-conditional.md +31 -0
  93. package/.claude/skills/vercel-react-best-practices/rules/bundle-defer-third-party.md +49 -0
  94. package/.claude/skills/vercel-react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  95. package/.claude/skills/vercel-react-best-practices/rules/bundle-preload.md +50 -0
  96. package/.claude/skills/vercel-react-best-practices/rules/client-event-listeners.md +74 -0
  97. package/.claude/skills/vercel-react-best-practices/rules/client-localstorage-schema.md +71 -0
  98. package/.claude/skills/vercel-react-best-practices/rules/client-passive-event-listeners.md +48 -0
  99. package/.claude/skills/vercel-react-best-practices/rules/client-swr-dedup.md +56 -0
  100. package/.claude/skills/vercel-react-best-practices/rules/js-batch-dom-css.md +107 -0
  101. package/.claude/skills/vercel-react-best-practices/rules/js-cache-function-results.md +80 -0
  102. package/.claude/skills/vercel-react-best-practices/rules/js-cache-property-access.md +28 -0
  103. package/.claude/skills/vercel-react-best-practices/rules/js-cache-storage.md +70 -0
  104. package/.claude/skills/vercel-react-best-practices/rules/js-combine-iterations.md +32 -0
  105. package/.claude/skills/vercel-react-best-practices/rules/js-early-exit.md +50 -0
  106. package/.claude/skills/vercel-react-best-practices/rules/js-hoist-regexp.md +45 -0
  107. package/.claude/skills/vercel-react-best-practices/rules/js-index-maps.md +37 -0
  108. package/.claude/skills/vercel-react-best-practices/rules/js-length-check-first.md +49 -0
  109. package/.claude/skills/vercel-react-best-practices/rules/js-min-max-loop.md +82 -0
  110. package/.claude/skills/vercel-react-best-practices/rules/js-set-map-lookups.md +24 -0
  111. package/.claude/skills/vercel-react-best-practices/rules/js-tosorted-immutable.md +57 -0
  112. package/.claude/skills/vercel-react-best-practices/rules/rendering-activity.md +26 -0
  113. package/.claude/skills/vercel-react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  114. package/.claude/skills/vercel-react-best-practices/rules/rendering-conditional-render.md +40 -0
  115. package/.claude/skills/vercel-react-best-practices/rules/rendering-content-visibility.md +38 -0
  116. package/.claude/skills/vercel-react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  117. package/.claude/skills/vercel-react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  118. package/.claude/skills/vercel-react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
  119. package/.claude/skills/vercel-react-best-practices/rules/rendering-svg-precision.md +28 -0
  120. package/.claude/skills/vercel-react-best-practices/rules/rendering-usetransition-loading.md +75 -0
  121. package/.claude/skills/vercel-react-best-practices/rules/rerender-defer-reads.md +39 -0
  122. package/.claude/skills/vercel-react-best-practices/rules/rerender-dependencies.md +45 -0
  123. package/.claude/skills/vercel-react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
  124. package/.claude/skills/vercel-react-best-practices/rules/rerender-derived-state.md +29 -0
  125. package/.claude/skills/vercel-react-best-practices/rules/rerender-functional-setstate.md +74 -0
  126. package/.claude/skills/vercel-react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  127. package/.claude/skills/vercel-react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
  128. package/.claude/skills/vercel-react-best-practices/rules/rerender-memo.md +44 -0
  129. package/.claude/skills/vercel-react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
  130. package/.claude/skills/vercel-react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
  131. package/.claude/skills/vercel-react-best-practices/rules/rerender-transitions.md +40 -0
  132. package/.claude/skills/vercel-react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
  133. package/.claude/skills/vercel-react-best-practices/rules/server-after-nonblocking.md +73 -0
  134. package/.claude/skills/vercel-react-best-practices/rules/server-auth-actions.md +96 -0
  135. package/.claude/skills/vercel-react-best-practices/rules/server-cache-lru.md +41 -0
  136. package/.claude/skills/vercel-react-best-practices/rules/server-cache-react.md +76 -0
  137. package/.claude/skills/vercel-react-best-practices/rules/server-dedup-props.md +65 -0
  138. package/.claude/skills/vercel-react-best-practices/rules/server-parallel-fetching.md +83 -0
  139. package/.claude/skills/vercel-react-best-practices/rules/server-serialization.md +38 -0
  140. package/.mcp.json.example +12 -0
  141. package/CHANGELOG.md +61 -0
  142. package/LICENSE +21 -0
  143. package/README.md +571 -0
  144. package/assets/jc-fox-mark.svg +10 -0
  145. package/assets/jc-methodology-badge.png +0 -0
  146. package/bin/sdd-jc.js +379 -0
  147. package/package.json +43 -0
  148. package/scripts/gsc_verify.py +162 -0
@@ -0,0 +1,1677 @@
1
+ ---
2
+ name: shadcn-ui
3
+ description: Provides complete shadcn/ui component library patterns including installation, configuration, and implementation of accessible React components. Use when setting up shadcn/ui, installing components, building forms with React Hook Form and Zod, customizing themes with Tailwind CSS, or implementing UI patterns like buttons, dialogs, dropdowns, tables, and complex form layouts.
4
+ allowed-tools: Read, Write, Bash, Edit, Glob
5
+ ---
6
+
7
+ # shadcn/ui Component Patterns
8
+
9
+ ## Overview
10
+
11
+ Expert guide for building accessible, customizable UI components with shadcn/ui, Radix UI, and Tailwind CSS. This skill provides comprehensive patterns for implementing production-ready components with full accessibility support.
12
+
13
+ ## Table of Contents
14
+
15
+ - [When to Use](#when-to-use)
16
+ - [Quick Start](#quick-start)
17
+ - [Installation & Setup](#installation--setup)
18
+ - [Project Configuration](#project-configuration)
19
+ - [Core Components](#core-components)
20
+ - [Button](#button-component)
21
+ - [Input & Form Fields](#input--form-fields)
22
+ - [Forms with Validation](#forms-with-validation)
23
+ - [Card](#card-component)
24
+ - [Dialog (Modal)](#dialog-modal-component)
25
+ - [Select (Dropdown)](#select-dropdown-component)
26
+ - [Sheet (Slide-over)](#sheet-slide-over-component)
27
+ - [Menubar & Navigation](#menubar--navigation)
28
+ - [Table](#table-component)
29
+ - [Toast Notifications](#toast-notifications)
30
+ - [Advanced Patterns](#advanced-patterns)
31
+ - [Customization](#customization)
32
+ - [Next.js Integration](#nextjs-integration)
33
+ - [Best Practices](#best-practices)
34
+ - [Common Component Combinations](#common-component-combinations)
35
+
36
+ ## When to Use
37
+
38
+ - Setting up a new project with shadcn/ui
39
+ - Installing or configuring individual components
40
+ - Building forms with React Hook Form and Zod validation
41
+ - Creating accessible UI components (buttons, dialogs, dropdowns, sheets)
42
+ - Customizing component styling with Tailwind CSS
43
+ - Implementing design systems with shadcn/ui
44
+ - Building Next.js applications with TypeScript
45
+ - Creating complex layouts and data displays
46
+
47
+ ## Instructions
48
+
49
+ 1. **Initialize Project**: Run `npx shadcn@latest init` to configure shadcn/ui
50
+ 2. **Install Components**: Add components with `npx shadcn@latest add <component>`
51
+ 3. **Configure Theme**: Customize CSS variables in globals.css for theming
52
+ 4. **Import Components**: Use components from `@/components/ui/` directory
53
+ 5. **Customize as Needed**: Modify component code directly in your project
54
+ 6. **Add Form Validation**: Integrate React Hook Form with Zod schemas
55
+ 7. **Test Accessibility**: Verify ARIA attributes and keyboard navigation
56
+
57
+ ## Examples
58
+
59
+ ### Complete Form with Validation
60
+
61
+ ```tsx
62
+ "use client"
63
+
64
+ import { zodResolver } from "@hookform/resolvers/zod"
65
+ import { useForm } from "react-hook-form"
66
+ import { z } from "zod"
67
+ import { Button } from "@/components/ui/button"
68
+ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
69
+ import { Input } from "@/components/ui/input"
70
+
71
+ const formSchema = z.object({
72
+ email: z.string().email("Invalid email"),
73
+ password: z.string().min(8, "Password must be at least 8 characters"),
74
+ })
75
+
76
+ export function LoginForm() {
77
+ const form = useForm<z.infer<typeof formSchema>>({
78
+ resolver: zodResolver(formSchema),
79
+ defaultValues: { email: "", password: "" },
80
+ })
81
+
82
+ return (
83
+ <Form {...form}>
84
+ <form onSubmit={form.handleSubmit(console.log)} className="space-y-4">
85
+ <FormField name="email" render={({ field }) => (
86
+ <FormItem>
87
+ <FormLabel>Email</FormLabel>
88
+ <FormControl><Input type="email" {...field} /></FormControl>
89
+ <FormMessage />
90
+ </FormItem>
91
+ )} />
92
+ <Button type="submit">Login</Button>
93
+ </form>
94
+ </Form>
95
+ )
96
+ }
97
+ ```
98
+
99
+ ## Constraints and Warnings
100
+
101
+ - **Not an NPM Package**: Components are copied to your project; you own the code
102
+ - **Client Components**: Most components require "use client" directive
103
+ - **Radix Dependencies**: Ensure all @radix-ui packages are installed
104
+ - **Tailwind Required**: Components rely on Tailwind CSS utilities
105
+ - **TypeScript**: Designed for TypeScript projects; type definitions included
106
+ - **Path Aliases**: Configure @ alias in tsconfig.json for imports
107
+ - **Dark Mode**: Set up dark mode with CSS variables or class strategy
108
+
109
+ ## Quick Start
110
+
111
+ For new projects, use the automated setup:
112
+
113
+ ```bash
114
+ # Create Next.js project with shadcn/ui
115
+ npx create-next-app@latest my-app --typescript --tailwind --eslint --app
116
+ cd my-app
117
+ npx shadcn@latest init
118
+
119
+ # Install essential components
120
+ npx shadcn@latest add button input form card dialog select
121
+ ```
122
+
123
+ For existing projects:
124
+
125
+ ```bash
126
+ # Install dependencies
127
+ npm install tailwindcss-animate class-variance-authority clsx tailwind-merge lucide-react
128
+
129
+ # Initialize shadcn/ui
130
+ npx shadcn@latest init
131
+ ```
132
+
133
+ ## What is shadcn/ui?
134
+
135
+ shadcn/ui is **not** a traditional component library or npm package. Instead:
136
+
137
+ - It's a **collection of reusable components** that you can copy into your project
138
+ - Components are **yours to customize** - you own the code
139
+ - Built with **Radix UI** primitives for accessibility
140
+ - Styled with **Tailwind CSS** utilities
141
+ - Includes CLI tool for easy component installation
142
+
143
+ ## Installation & Setup
144
+
145
+ ### Initial Setup
146
+
147
+ ```bash
148
+ # Initialize shadcn/ui in your project
149
+ npx shadcn@latest init
150
+ ```
151
+
152
+ During setup, you'll configure:
153
+ - TypeScript or JavaScript
154
+ - Style (Default, New York, etc.)
155
+ - Base color theme
156
+ - CSS variables or Tailwind CSS classes
157
+ - Component installation path
158
+
159
+ ### Installing Individual Components
160
+
161
+ ```bash
162
+ # Install a single component
163
+ npx shadcn@latest add button
164
+
165
+ # Install multiple components
166
+ npx shadcn@latest add button input form
167
+
168
+ # Install all components
169
+ npx shadcn@latest add --all
170
+ ```
171
+
172
+ ### Manual Installation
173
+
174
+ If you prefer manual setup:
175
+
176
+ ```bash
177
+ # Install dependencies for a specific component
178
+ npm install @radix-ui/react-slot
179
+
180
+ # Copy component code from ui.shadcn.com
181
+ # Place in src/components/ui/
182
+ ```
183
+
184
+ ## Project Configuration
185
+
186
+ ### Required Dependencies
187
+
188
+ ```json
189
+ {
190
+ "dependencies": {
191
+ "@radix-ui/react-accordion": "^1.1.2",
192
+ "@radix-ui/react-alert-dialog": "^1.0.5",
193
+ "@radix-ui/react-dialog": "^1.0.5",
194
+ "@radix-ui/react-dropdown-menu": "^2.0.6",
195
+ "@radix-ui/react-label": "^2.0.2",
196
+ "@radix-ui/react-select": "^2.0.0",
197
+ "@radix-ui/react-separator": "^1.0.3",
198
+ "@radix-ui/react-slot": "^1.0.2",
199
+ "@radix-ui/react-toast": "^1.1.5",
200
+ "class-variance-authority": "^0.7.0",
201
+ "clsx": "^2.0.0",
202
+ "lucide-react": "^0.294.0",
203
+ "tailwind-merge": "^2.0.0",
204
+ "tailwindcss-animate": "^1.0.7"
205
+ }
206
+ }
207
+ ```
208
+
209
+ ### TSConfig Configuration
210
+
211
+ ```json
212
+ {
213
+ "compilerOptions": {
214
+ "target": "es5",
215
+ "lib": ["dom", "dom.iterable", "es6"],
216
+ "allowJs": true,
217
+ "skipLibCheck": true,
218
+ "strict": true,
219
+ "forceConsistentCasingInFileNames": true,
220
+ "noEmit": true,
221
+ "esModuleInterop": true,
222
+ "module": "esnext",
223
+ "moduleResolution": "node",
224
+ "resolveJsonModule": true,
225
+ "isolatedModules": true,
226
+ "jsx": "preserve",
227
+ "incremental": true,
228
+ "plugins": [
229
+ {
230
+ "name": "next"
231
+ }
232
+ ],
233
+ "baseUrl": ".",
234
+ "paths": {
235
+ "@/components/*": ["./src/components/*"],
236
+ "@/lib/*": ["./src/lib/*"]
237
+ }
238
+ },
239
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
240
+ "exclude": ["node_modules"]
241
+ }
242
+ ```
243
+
244
+ ### Tailwind Configuration
245
+
246
+ ```js
247
+ // tailwind.config.js
248
+ /** @type {import('tailwindcss').Config} */
249
+ module.exports = {
250
+ darkMode: ["class"],
251
+ content: [
252
+ './pages/**/*.{ts,tsx}',
253
+ './components/**/*.{ts,tsx}',
254
+ './app/**/*.{ts,tsx}',
255
+ './src/**/*.{ts,tsx}',
256
+ ],
257
+ prefix: "",
258
+ theme: {
259
+ container: {
260
+ center: true,
261
+ padding: "2rem",
262
+ screens: {
263
+ "2xl": "1400px",
264
+ },
265
+ },
266
+ extend: {
267
+ colors: {
268
+ border: "hsl(var(--border))",
269
+ input: "hsl(var(--input))",
270
+ ring: "hsl(var(--ring))",
271
+ background: "hsl(var(--background))",
272
+ foreground: "hsl(var(--foreground))",
273
+ primary: {
274
+ DEFAULT: "hsl(var(--primary))",
275
+ foreground: "hsl(var(--primary-foreground))",
276
+ },
277
+ secondary: {
278
+ DEFAULT: "hsl(var(--secondary))",
279
+ foreground: "hsl(var(--secondary-foreground))",
280
+ },
281
+ destructive: {
282
+ DEFAULT: "hsl(var(--destructive))",
283
+ foreground: "hsl(var(--destructive-foreground))",
284
+ },
285
+ muted: {
286
+ DEFAULT: "hsl(var(--muted))",
287
+ foreground: "hsl(var(--muted-foreground))",
288
+ },
289
+ accent: {
290
+ DEFAULT: "hsl(var(--accent))",
291
+ foreground: "hsl(var(--accent-foreground))",
292
+ },
293
+ popover: {
294
+ DEFAULT: "hsl(var(--popover))",
295
+ foreground: "hsl(var(--popover-foreground))",
296
+ },
297
+ card: {
298
+ DEFAULT: "hsl(var(--card))",
299
+ foreground: "hsl(var(--card-foreground))",
300
+ },
301
+ },
302
+ borderRadius: {
303
+ lg: "var(--radius)",
304
+ md: "calc(var(--radius) - 2px)",
305
+ sm: "calc(var(--radius) - 4px)",
306
+ },
307
+ keyframes: {
308
+ "accordion-down": {
309
+ from: { height: "0" },
310
+ to: { height: "var(--radix-accordion-content-height)" },
311
+ },
312
+ "accordion-up": {
313
+ from: { height: "var(--radix-accordion-content-height)" },
314
+ to: { height: "0" },
315
+ },
316
+ },
317
+ animation: {
318
+ "accordion-down": "accordion-down 0.2s ease-out",
319
+ "accordion-up": "accordion-up 0.2s ease-out",
320
+ },
321
+ },
322
+ },
323
+ plugins: [require("tailwindcss-animate")],
324
+ }
325
+ ```
326
+
327
+ ### CSS Variables (globals.css)
328
+
329
+ ```css
330
+ @tailwind base;
331
+ @tailwind components;
332
+ @tailwind utilities;
333
+
334
+ @layer base {
335
+ :root {
336
+ --background: 0 0% 100%;
337
+ --foreground: 222.2 84% 4.9%;
338
+ --card: 0 0% 100%;
339
+ --card-foreground: 222.2 84% 4.9%;
340
+ --popover: 0 0% 100%;
341
+ --popover-foreground: 222.2 84% 4.9%;
342
+ --primary: 222.2 47.4% 11.2%;
343
+ --primary-foreground: 210 40% 98%;
344
+ --secondary: 210 40% 96.1%;
345
+ --secondary-foreground: 222.2 47.4% 11.2%;
346
+ --muted: 210 40% 96.1%;
347
+ --muted-foreground: 215.4 16.3% 46.9%;
348
+ --accent: 210 40% 96.1%;
349
+ --accent-foreground: 222.2 47.4% 11.2%;
350
+ --destructive: 0 84.2% 60.2%;
351
+ --destructive-foreground: 210 40% 98%;
352
+ --border: 214.3 31.8% 91.4%;
353
+ --input: 214.3 31.8% 91.4%;
354
+ --ring: 222.2 84% 4.9%;
355
+ --radius: 0.5rem;
356
+ }
357
+
358
+ .dark {
359
+ --background: 222.2 84% 4.9%;
360
+ --foreground: 210 40% 98%;
361
+ --card: 222.2 84% 4.9%;
362
+ --card-foreground: 210 40% 98%;
363
+ --popover: 222.2 84% 4.9%;
364
+ --popover-foreground: 210 40% 98%;
365
+ --primary: 210 40% 98%;
366
+ --primary-foreground: 222.2 47.4% 11.2%;
367
+ --secondary: 217.2 32.6% 17.5%;
368
+ --secondary-foreground: 210 40% 98%;
369
+ --muted: 217.2 32.6% 17.5%;
370
+ --muted-foreground: 215 20.2% 65.1%;
371
+ --accent: 217.2 32.6% 17.5%;
372
+ --accent-foreground: 210 40% 98%;
373
+ --destructive: 0 62.8% 30.6%;
374
+ --destructive-foreground: 210 40% 98%;
375
+ --border: 217.2 32.6% 17.5%;
376
+ --input: 217.2 32.6% 17.5%;
377
+ --ring: 212.7 26.8% 83.9%;
378
+ }
379
+ }
380
+
381
+ @layer base {
382
+ * {
383
+ @apply border-border;
384
+ }
385
+ body {
386
+ @apply bg-background text-foreground;
387
+ }
388
+ }
389
+ ```
390
+
391
+ ## Core Components
392
+
393
+ ### Button Component
394
+
395
+ Installation:
396
+
397
+ ```bash
398
+ npx shadcn@latest add button
399
+ ```
400
+
401
+ Basic usage:
402
+
403
+ ```tsx
404
+ import { Button } from "@/components/ui/button";
405
+
406
+ export function ButtonDemo() {
407
+ return <Button>Click me</Button>;
408
+ }
409
+ ```
410
+
411
+ Button variants:
412
+
413
+ ```tsx
414
+ import { Button } from "@/components/ui/button";
415
+
416
+ export function ButtonVariants() {
417
+ return (
418
+ <div className="flex gap-4">
419
+ <Button variant="default">Default</Button>
420
+ <Button variant="destructive">Destructive</Button>
421
+ <Button variant="outline">Outline</Button>
422
+ <Button variant="secondary">Secondary</Button>
423
+ <Button variant="ghost">Ghost</Button>
424
+ <Button variant="link">Link</Button>
425
+ </div>
426
+ );
427
+ }
428
+ ```
429
+
430
+ Button sizes:
431
+
432
+ ```tsx
433
+ <div className="flex gap-4 items-center">
434
+ <Button size="default">Default</Button>
435
+ <Button size="sm">Small</Button>
436
+ <Button size="lg">Large</Button>
437
+ <Button size="icon">
438
+ <Icon className="h-4 w-4" />
439
+ </Button>
440
+ </div>
441
+ ```
442
+
443
+ With loading state:
444
+
445
+ ```tsx
446
+ import { Button } from "@/components/ui/button";
447
+ import { Loader2 } from "lucide-react";
448
+
449
+ export function ButtonLoading() {
450
+ return (
451
+ <Button disabled>
452
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
453
+ Please wait
454
+ </Button>
455
+ );
456
+ }
457
+ ```
458
+
459
+ ### Input & Form Fields
460
+
461
+ #### Input Component
462
+
463
+ Installation:
464
+
465
+ ```bash
466
+ npx shadcn@latest add input
467
+ ```
468
+
469
+ Basic input:
470
+
471
+ ```tsx
472
+ import { Input } from "@/components/ui/input";
473
+
474
+ export function InputDemo() {
475
+ return <Input type="email" placeholder="Email" />;
476
+ }
477
+ ```
478
+
479
+ Input with label:
480
+
481
+ ```tsx
482
+ import { Input } from "@/components/ui/input";
483
+ import { Label } from "@/components/ui/label";
484
+
485
+ export function InputWithLabel() {
486
+ return (
487
+ <div className="grid w-full max-w-sm items-center gap-1.5">
488
+ <Label htmlFor="email">Email</Label>
489
+ <Input type="email" id="email" placeholder="Email" />
490
+ </div>
491
+ );
492
+ }
493
+ ```
494
+
495
+ Input with button:
496
+
497
+ ```tsx
498
+ import { Button } from "@/components/ui/button";
499
+ import { Input } from "@/components/ui/input";
500
+
501
+ export function InputWithButton() {
502
+ return (
503
+ <div className="flex w-full max-w-sm items-center gap-2">
504
+ <Input type="email" placeholder="Email" />
505
+ <Button type="submit" variant="outline">Subscribe</Button>
506
+ </div>
507
+ );
508
+ }
509
+ ```
510
+
511
+ ### Forms with Validation
512
+
513
+ Installation:
514
+
515
+ ```bash
516
+ npx shadcn@latest add form
517
+ ```
518
+
519
+ This installs React Hook Form, Zod, and form components.
520
+
521
+ Complete form example:
522
+
523
+ ```tsx
524
+ "use client"
525
+
526
+ import { zodResolver } from "@hookform/resolvers/zod"
527
+ import { useForm } from "react-hook-form"
528
+ import * as z from "zod"
529
+
530
+ import { Button } from "@/components/ui/button"
531
+ import {
532
+ Form,
533
+ FormControl,
534
+ FormDescription,
535
+ FormField,
536
+ FormItem,
537
+ FormLabel,
538
+ FormMessage,
539
+ } from "@/components/ui/form"
540
+ import { Input } from "@/components/ui/input"
541
+ import { toast } from "@/components/ui/use-toast"
542
+
543
+ const formSchema = z.object({
544
+ username: z.string().min(2, {
545
+ message: "Username must be at least 2 characters.",
546
+ }),
547
+ email: z.string().email({
548
+ message: "Please enter a valid email address.",
549
+ }),
550
+ })
551
+
552
+ export function ProfileForm() {
553
+ const form = useForm<z.infer<typeof formSchema>>({
554
+ resolver: zodResolver(formSchema),
555
+ defaultValues: {
556
+ username: "",
557
+ email: "",
558
+ },
559
+ })
560
+
561
+ function onSubmit(values: z.infer<typeof formSchema>) {
562
+ toast({
563
+ title: "You submitted the following values:",
564
+ description: (
565
+ <pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
566
+ <code className="text-white">{JSON.stringify(values, null, 2)}</code>
567
+ </pre>
568
+ ),
569
+ })
570
+ }
571
+
572
+ return (
573
+ <Form {...form}>
574
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
575
+ <FormField
576
+ control={form.control}
577
+ name="username"
578
+ render={({ field }) => (
579
+ <FormItem>
580
+ <FormLabel>Username</FormLabel>
581
+ <FormControl>
582
+ <Input placeholder="shadcn" {...field} />
583
+ </FormControl>
584
+ <FormDescription>
585
+ This is your public display name.
586
+ </FormDescription>
587
+ <FormMessage />
588
+ </FormItem>
589
+ )}
590
+ />
591
+
592
+ <FormField
593
+ control={form.control}
594
+ name="email"
595
+ render={({ field }) => (
596
+ <FormItem>
597
+ <FormLabel>Email</FormLabel>
598
+ <FormControl>
599
+ <Input type="email" placeholder="you@example.com" {...field} />
600
+ </FormControl>
601
+ <FormMessage />
602
+ </FormItem>
603
+ )}
604
+ />
605
+
606
+ <Button type="submit">Submit</Button>
607
+ </form>
608
+ </Form>
609
+ )
610
+ }
611
+ ```
612
+
613
+ ### Card Component
614
+
615
+ Installation:
616
+
617
+ ```bash
618
+ npx shadcn@latest add card
619
+ ```
620
+
621
+ Basic card:
622
+
623
+ ```tsx
624
+ import {
625
+ Card,
626
+ CardContent,
627
+ CardDescription,
628
+ CardFooter,
629
+ CardHeader,
630
+ CardTitle,
631
+ } from "@/components/ui/card"
632
+
633
+ export function CardDemo() {
634
+ return (
635
+ <Card>
636
+ <CardHeader>
637
+ <CardTitle>Card Title</CardTitle>
638
+ <CardDescription>Card Description</CardDescription>
639
+ </CardHeader>
640
+ <CardContent>
641
+ <p>Card Content</p>
642
+ </CardContent>
643
+ <CardFooter>
644
+ <p>Card Footer</p>
645
+ </CardFooter>
646
+ </Card>
647
+ )
648
+ }
649
+ ```
650
+
651
+ Card with form:
652
+
653
+ ```tsx
654
+ import { Button } from "@/components/ui/button"
655
+ import {
656
+ Card,
657
+ CardContent,
658
+ CardDescription,
659
+ CardFooter,
660
+ CardHeader,
661
+ CardTitle,
662
+ } from "@/components/ui/card"
663
+ import { Input } from "@/components/ui/input"
664
+ import { Label } from "@/components/ui/label"
665
+
666
+ export function CardWithForm() {
667
+ return (
668
+ <Card className="w-[350px]">
669
+ <CardHeader>
670
+ <CardTitle>Create project</CardTitle>
671
+ <CardDescription>Deploy your new project in one-click.</CardDescription>
672
+ </CardHeader>
673
+ <CardContent>
674
+ <form>
675
+ <div className="grid w-full items-center gap-4">
676
+ <div className="flex flex-col space-y-1.5">
677
+ <Label htmlFor="name">Name</Label>
678
+ <Input id="name" placeholder="Name of your project" />
679
+ </div>
680
+ </div>
681
+ </form>
682
+ </CardContent>
683
+ <CardFooter className="flex justify-between">
684
+ <Button variant="outline">Cancel</Button>
685
+ <Button>Deploy</Button>
686
+ </CardFooter>
687
+ </Card>
688
+ )
689
+ }
690
+ ```
691
+
692
+ ### Dialog (Modal) Component
693
+
694
+ Installation:
695
+
696
+ ```bash
697
+ npx shadcn@latest add dialog
698
+ ```
699
+
700
+ Basic dialog:
701
+
702
+ ```tsx
703
+ import { Button } from "@/components/ui/button"
704
+ import {
705
+ Dialog,
706
+ DialogContent,
707
+ DialogDescription,
708
+ DialogFooter,
709
+ DialogHeader,
710
+ DialogTitle,
711
+ DialogTrigger,
712
+ } from "@/components/ui/dialog"
713
+
714
+ export function DialogDemo() {
715
+ return (
716
+ <Dialog>
717
+ <DialogTrigger asChild>
718
+ <Button variant="outline">Open Dialog</Button>
719
+ </DialogTrigger>
720
+ <DialogContent className="sm:max-w-[425px]">
721
+ <DialogHeader>
722
+ <DialogTitle>Edit profile</DialogTitle>
723
+ <DialogDescription>
724
+ Make changes to your profile here. Click save when you're done.
725
+ </DialogDescription>
726
+ </DialogHeader>
727
+ <div className="grid gap-4 py-4">
728
+ <div className="grid grid-cols-4 items-center gap-4">
729
+ <Label htmlFor="name" className="text-right">
730
+ Name
731
+ </Label>
732
+ <Input id="name" value="Pedro Duarte" className="col-span-3" />
733
+ </div>
734
+ </div>
735
+ <DialogFooter>
736
+ <Button type="submit">Save changes</Button>
737
+ </DialogFooter>
738
+ </DialogContent>
739
+ </Dialog>
740
+ )
741
+ }
742
+ ```
743
+
744
+ ### Sheet (Slide-over) Component
745
+
746
+ Installation:
747
+
748
+ ```bash
749
+ npx shadcn@latest add sheet
750
+ ```
751
+
752
+ Basic sheet:
753
+
754
+ ```tsx
755
+ import { Button } from "@/components/ui/button"
756
+ import {
757
+ Sheet,
758
+ SheetContent,
759
+ SheetDescription,
760
+ SheetHeader,
761
+ SheetTitle,
762
+ SheetTrigger,
763
+ } from "@/components/ui/sheet"
764
+
765
+ export function SheetDemo() {
766
+ return (
767
+ <Sheet>
768
+ <SheetTrigger asChild>
769
+ <Button variant="outline">Open Sheet</Button>
770
+ </SheetTrigger>
771
+ <SheetContent>
772
+ <SheetHeader>
773
+ <SheetTitle>Edit profile</SheetTitle>
774
+ <SheetDescription>
775
+ Make changes to your profile here. Click save when you're done.
776
+ </SheetDescription>
777
+ </SheetHeader>
778
+ <div className="grid gap-4 py-4">
779
+ <div className="grid grid-cols-4 items-center gap-4">
780
+ <Label htmlFor="name" className="text-right">
781
+ Name
782
+ </Label>
783
+ <Input id="name" value="Pedro Duarte" className="col-span-3" />
784
+ </div>
785
+ <div className="grid grid-cols-4 items-center gap-4">
786
+ <Label htmlFor="username" className="text-right">
787
+ Username
788
+ </Label>
789
+ <Input id="username" value="@peduarte" className="col-span-3" />
790
+ </div>
791
+ </div>
792
+ </SheetContent>
793
+ </Sheet>
794
+ )
795
+ }
796
+ ```
797
+
798
+ Sheet with side placement:
799
+
800
+ ```tsx
801
+ <Sheet>
802
+ <SheetTrigger asChild>
803
+ <Button variant="outline">Open Right Sheet</Button>
804
+ </SheetTrigger>
805
+ <SheetContent side="right">
806
+ <SheetHeader>
807
+ <SheetTitle>Settings</SheetTitle>
808
+ <SheetDescription>
809
+ Configure your application settings here.
810
+ </SheetDescription>
811
+ </SheetHeader>
812
+ {/* Settings content */}
813
+ </SheetContent>
814
+ </Sheet>
815
+ ```
816
+
817
+ ### Menubar & Navigation
818
+
819
+ #### Menubar Component
820
+
821
+ Installation:
822
+
823
+ ```bash
824
+ npx shadcn@latest add menubar
825
+ ```
826
+
827
+ Basic menubar:
828
+
829
+ ```tsx
830
+ import {
831
+ Menubar,
832
+ MenubarContent,
833
+ MenubarItem,
834
+ MenubarMenu,
835
+ MenubarSeparator,
836
+ MenubarShortcut,
837
+ MenubarSub,
838
+ MenubarSubContent,
839
+ MenubarSubTrigger,
840
+ MenubarTrigger,
841
+ } from "@/components/ui/menubar"
842
+
843
+ export function MenubarDemo() {
844
+ return (
845
+ <Menubar>
846
+ <MenubarMenu>
847
+ <MenubarTrigger>File</MenubarTrigger>
848
+ <MenubarContent>
849
+ <MenubarItem>
850
+ New Tab <MenubarShortcut>⌘T</MenubarShortcut>
851
+ </MenubarItem>
852
+ <MenubarItem>
853
+ New Window <MenubarShortcut>⌘N</MenubarShortcut>
854
+ </MenubarItem>
855
+ <MenubarSeparator />
856
+ <MenubarItem>Share</MenubarItem>
857
+ <MenubarSeparator />
858
+ <MenubarItem>Print</MenubarItem>
859
+ </MenubarContent>
860
+ </MenubarMenu>
861
+ <MenubarMenu>
862
+ <MenubarTrigger>Edit</MenubarTrigger>
863
+ <MenubarContent>
864
+ <MenubarItem>
865
+ Undo <MenubarShortcut>⌘Z</MenubarShortcut>
866
+ </MenubarItem>
867
+ <MenubarItem>
868
+ Redo <MenubarShortcut>⌘Y</MenubarShortcut>
869
+ </MenubarItem>
870
+ <MenubarSeparator />
871
+ <MenubarSub>
872
+ <MenubarSubTrigger>Find</MenubarSubTrigger>
873
+ <MenubarSubContent>
874
+ <MenubarItem>Search the web</MenubarItem>
875
+ <MenubarItem>Find...</MenubarItem>
876
+ <MenubarItem>Find Next</MenubarItem>
877
+ <MenubarItem>Find Previous</MenubarItem>
878
+ </MenubarSubContent>
879
+ </MenubarSub>
880
+ </MenubarContent>
881
+ </MenubarMenu>
882
+ </Menubar>
883
+ )
884
+ }
885
+ ```
886
+
887
+ ### Select (Dropdown) Component
888
+
889
+ Installation:
890
+
891
+ ```bash
892
+ npx shadcn@latest add select
893
+ ```
894
+
895
+ Basic select:
896
+
897
+ ```tsx
898
+ import {
899
+ Select,
900
+ SelectContent,
901
+ SelectItem,
902
+ SelectTrigger,
903
+ SelectValue,
904
+ } from "@/components/ui/select"
905
+
906
+ export function SelectDemo() {
907
+ return (
908
+ <Select>
909
+ <SelectTrigger className="w-[180px]">
910
+ <SelectValue placeholder="Select a fruit" />
911
+ </SelectTrigger>
912
+ <SelectContent>
913
+ <SelectItem value="apple">Apple</SelectItem>
914
+ <SelectItem value="banana">Banana</SelectItem>
915
+ <SelectItem value="orange">Orange</SelectItem>
916
+ </SelectContent>
917
+ </Select>
918
+ )
919
+ }
920
+ ```
921
+
922
+ Select in form:
923
+
924
+ ```tsx
925
+ <FormField
926
+ control={form.control}
927
+ name="role"
928
+ render={({ field }) => (
929
+ <FormItem>
930
+ <FormLabel>Role</FormLabel>
931
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
932
+ <FormControl>
933
+ <SelectTrigger>
934
+ <SelectValue placeholder="Select a role" />
935
+ </SelectTrigger>
936
+ </FormControl>
937
+ <SelectContent>
938
+ <SelectItem value="admin">Admin</SelectItem>
939
+ <SelectItem value="user">User</SelectItem>
940
+ <SelectItem value="guest">Guest</SelectItem>
941
+ </SelectContent>
942
+ </Select>
943
+ <FormMessage />
944
+ </FormItem>
945
+ )}
946
+ />
947
+ ```
948
+
949
+ ### Toast Notifications
950
+
951
+ Installation:
952
+
953
+ ```bash
954
+ npx shadcn@latest add toast
955
+ ```
956
+
957
+ Setup toast provider in root layout:
958
+
959
+ ```tsx
960
+ import { Toaster } from "@/components/ui/toaster"
961
+
962
+ export default function RootLayout({ children }) {
963
+ return (
964
+ <html lang="en">
965
+ <body>
966
+ {children}
967
+ <Toaster />
968
+ </body>
969
+ </html>
970
+ )
971
+ }
972
+ ```
973
+
974
+ Using toast:
975
+
976
+ ```tsx
977
+ import { useToast } from "@/components/ui/use-toast"
978
+ import { Button } from "@/components/ui/button"
979
+
980
+ export function ToastDemo() {
981
+ const { toast } = useToast()
982
+
983
+ return (
984
+ <Button
985
+ onClick={() => {
986
+ toast({
987
+ title: "Scheduled: Catch up",
988
+ description: "Friday, February 10, 2023 at 5:57 PM",
989
+ })
990
+ }}
991
+ >
992
+ Show Toast
993
+ </Button>
994
+ )
995
+ }
996
+ ```
997
+
998
+ Toast variants:
999
+
1000
+ ```tsx
1001
+ // Success
1002
+ toast({
1003
+ title: "Success",
1004
+ description: "Your changes have been saved.",
1005
+ })
1006
+
1007
+ // Error
1008
+ toast({
1009
+ variant: "destructive",
1010
+ title: "Error",
1011
+ description: "Something went wrong.",
1012
+ })
1013
+
1014
+ // With action
1015
+ toast({
1016
+ title: "Uh oh! Something went wrong.",
1017
+ description: "There was a problem with your request.",
1018
+ action: <ToastAction altText="Try again">Try again</ToastAction>,
1019
+ })
1020
+ ```
1021
+
1022
+ ### Table Component
1023
+
1024
+ Installation:
1025
+
1026
+ ```bash
1027
+ npx shadcn@latest add table
1028
+ ```
1029
+
1030
+ Basic table:
1031
+
1032
+ ```tsx
1033
+ import {
1034
+ Table,
1035
+ TableBody,
1036
+ TableCaption,
1037
+ TableCell,
1038
+ TableHead,
1039
+ TableHeader,
1040
+ TableRow,
1041
+ } from "@/components/ui/table"
1042
+
1043
+ const invoices = [
1044
+ { invoice: "INV001", status: "Paid", method: "Credit Card", amount: "$250.00" },
1045
+ { invoice: "INV002", status: "Pending", method: "PayPal", amount: "$150.00" },
1046
+ ]
1047
+
1048
+ export function TableDemo() {
1049
+ return (
1050
+ <Table>
1051
+ <TableCaption>A list of your recent invoices.</TableCaption>
1052
+ <TableHeader>
1053
+ <TableRow>
1054
+ <TableHead>Invoice</TableHead>
1055
+ <TableHead>Status</TableHead>
1056
+ <TableHead>Method</TableHead>
1057
+ <TableHead className="text-right">Amount</TableHead>
1058
+ </TableRow>
1059
+ </TableHeader>
1060
+ <TableBody>
1061
+ {invoices.map((invoice) => (
1062
+ <TableRow key={invoice.invoice}>
1063
+ <TableCell className="font-medium">{invoice.invoice}</TableCell>
1064
+ <TableCell>{invoice.status}</TableCell>
1065
+ <TableCell>{invoice.method}</TableCell>
1066
+ <TableCell className="text-right">{invoice.amount}</TableCell>
1067
+ </TableRow>
1068
+ ))}
1069
+ </TableBody>
1070
+ </Table>
1071
+ )
1072
+ }
1073
+ ```
1074
+
1075
+ ## Customization
1076
+
1077
+ ### Theming with CSS Variables
1078
+
1079
+ shadcn/ui uses CSS variables for theming. Configure in `globals.css`:
1080
+
1081
+ ```css
1082
+ @layer base {
1083
+ :root {
1084
+ --background: 0 0% 100%;
1085
+ --foreground: 222.2 84% 4.9%;
1086
+ --primary: 222.2 47.4% 11.2%;
1087
+ --primary-foreground: 210 40% 98%;
1088
+ --secondary: 210 40% 96.1%;
1089
+ --secondary-foreground: 222.2 47.4% 11.2%;
1090
+ --muted: 210 40% 96.1%;
1091
+ --muted-foreground: 215.4 16.3% 46.9%;
1092
+ --accent: 210 40% 96.1%;
1093
+ --accent-foreground: 222.2 47.4% 11.2%;
1094
+ --destructive: 0 84.2% 60.2%;
1095
+ --destructive-foreground: 210 40% 98%;
1096
+ --border: 214.3 31.8% 91.4%;
1097
+ --input: 214.3 31.8% 91.4%;
1098
+ --ring: 222.2 84% 4.9%;
1099
+ --radius: 0.5rem;
1100
+ }
1101
+
1102
+ .dark {
1103
+ --background: 222.2 84% 4.9%;
1104
+ --foreground: 210 40% 98%;
1105
+ --primary: 210 40% 98%;
1106
+ --primary-foreground: 222.2 47.4% 11.2%;
1107
+ /* ... other dark mode variables */
1108
+ }
1109
+ }
1110
+ ```
1111
+
1112
+ ### Customizing Components
1113
+
1114
+ Since you own the code, customize directly:
1115
+
1116
+ ```tsx
1117
+ // components/ui/button.tsx
1118
+ import * as React from "react"
1119
+ import { Slot } from "@radix-ui/react-slot"
1120
+ import { cva, type VariantProps } from "class-variance-authority"
1121
+ import { cn } from "@/lib/utils"
1122
+
1123
+ const buttonVariants = cva(
1124
+ "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors",
1125
+ {
1126
+ variants: {
1127
+ variant: {
1128
+ default: "bg-primary text-primary-foreground hover:bg-primary/90",
1129
+ destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
1130
+ outline: "border border-input bg-background hover:bg-accent",
1131
+ // Add custom variant
1132
+ custom: "bg-gradient-to-r from-purple-500 to-pink-500 text-white",
1133
+ },
1134
+ size: {
1135
+ default: "h-10 px-4 py-2",
1136
+ sm: "h-9 rounded-md px-3",
1137
+ lg: "h-11 rounded-md px-8",
1138
+ // Add custom size
1139
+ xl: "h-14 rounded-md px-10 text-lg",
1140
+ },
1141
+ },
1142
+ defaultVariants: {
1143
+ variant: "default",
1144
+ size: "default",
1145
+ },
1146
+ }
1147
+ )
1148
+
1149
+ export interface ButtonProps
1150
+ extends React.ButtonHTMLAttributes<HTMLButtonElement>,
1151
+ VariantProps<typeof buttonVariants> {
1152
+ asChild?: boolean
1153
+ }
1154
+
1155
+ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
1156
+ ({ className, variant, size, asChild = false, ...props }, ref) => {
1157
+ const Comp = asChild ? Slot : "button"
1158
+ return (
1159
+ <Comp
1160
+ className={cn(buttonVariants({ variant, size, className }))}
1161
+ ref={ref}
1162
+ {...props}
1163
+ />
1164
+ )
1165
+ }
1166
+ )
1167
+ Button.displayName = "Button"
1168
+
1169
+ export { Button, buttonVariants }
1170
+ ```
1171
+
1172
+ ## Next.js Integration
1173
+
1174
+ ### App Router Setup
1175
+
1176
+ For Next.js 13+ with App Router, ensure components use `"use client"` directive:
1177
+
1178
+ ```tsx
1179
+ // src/components/ui/button.tsx
1180
+ "use client"
1181
+
1182
+ import * as React from "react"
1183
+ import { Slot } from "@radix-ui/react-slot"
1184
+ import { cva, type VariantProps } from "class-variance-authority"
1185
+ import { cn } from "@/lib/utils"
1186
+
1187
+ // ... rest of component
1188
+ ```
1189
+
1190
+ ### Layout Integration
1191
+
1192
+ Add the Toaster to your root layout:
1193
+
1194
+ ```tsx
1195
+ // app/layout.tsx
1196
+ import { Toaster } from "@/components/ui/toaster"
1197
+ import "./globals.css"
1198
+
1199
+ export default function RootLayout({
1200
+ children,
1201
+ }: {
1202
+ children: React.ReactNode
1203
+ }) {
1204
+ return (
1205
+ <html lang="en" suppressHydrationWarning>
1206
+ <body className="min-h-screen bg-background font-sans antialiased">
1207
+ {children}
1208
+ <Toaster />
1209
+ </body>
1210
+ </html>
1211
+ )
1212
+ }
1213
+ ```
1214
+
1215
+ ### Server Components
1216
+
1217
+ When using shadcn/ui components in Server Components, wrap them in a Client Component:
1218
+
1219
+ ```tsx
1220
+ // app/dashboard/page.tsx
1221
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
1222
+ import { ButtonClient } from "@/components/ui/button-client"
1223
+
1224
+ export default function DashboardPage() {
1225
+ return (
1226
+ <div className="container mx-auto p-6">
1227
+ <Card>
1228
+ <CardHeader>
1229
+ <CardTitle>Dashboard</CardTitle>
1230
+ </CardHeader>
1231
+ <CardContent>
1232
+ <ButtonClient>Interactive Button</ButtonClient>
1233
+ </CardContent>
1234
+ </Card>
1235
+ </div>
1236
+ )
1237
+ }
1238
+ ```
1239
+
1240
+ ```tsx
1241
+ // src/components/ui/button-client.tsx
1242
+ "use client"
1243
+
1244
+ import { Button } from "./button"
1245
+
1246
+ export function ButtonClient(props: React.ComponentProps<typeof Button>) {
1247
+ return <Button {...props} />
1248
+ }
1249
+ ```
1250
+
1251
+ ### Route Handlers with Forms
1252
+
1253
+ Create API routes for form submissions:
1254
+
1255
+ ```tsx
1256
+ // app/api/contact/route.ts
1257
+ import { NextRequest, NextResponse } from "next/server"
1258
+ import { z } from "zod"
1259
+
1260
+ const contactSchema = z.object({
1261
+ name: z.string().min(2),
1262
+ email: z.string().email(),
1263
+ message: z.string().min(10),
1264
+ })
1265
+
1266
+ export async function POST(request: NextRequest) {
1267
+ try {
1268
+ const body = await request.json()
1269
+ const validated = contactSchema.parse(body)
1270
+
1271
+ // Process form data
1272
+ console.log("Form submission:", validated)
1273
+
1274
+ return NextResponse.json({ success: true })
1275
+ } catch (error) {
1276
+ if (error instanceof z.ZodError) {
1277
+ return NextResponse.json(
1278
+ { errors: error.errors },
1279
+ { status: 400 }
1280
+ )
1281
+ }
1282
+
1283
+ return NextResponse.json(
1284
+ { error: "Internal server error" },
1285
+ { status: 500 }
1286
+ )
1287
+ }
1288
+ }
1289
+ ```
1290
+
1291
+ ### Form with Server Action
1292
+
1293
+ Using Next.js 14+ Server Actions:
1294
+
1295
+ ```tsx
1296
+ // app/contact/page.tsx
1297
+ "use client"
1298
+
1299
+ import { zodResolver } from "@hookform/resolvers/zod"
1300
+ import { useForm } from "react-hook-form"
1301
+ import * as z from "zod"
1302
+ import { Button } from "@/components/ui/button"
1303
+ import {
1304
+ Form,
1305
+ FormControl,
1306
+ FormField,
1307
+ FormItem,
1308
+ FormLabel,
1309
+ FormMessage,
1310
+ } from "@/components/ui/form"
1311
+ import { Input } from "@/components/ui/input"
1312
+ import { Textarea } from "@/components/ui/textarea"
1313
+ import { toast } from "@/components/ui/use-toast"
1314
+
1315
+ const formSchema = z.object({
1316
+ name: z.string().min(2),
1317
+ email: z.string().email(),
1318
+ message: z.string().min(10),
1319
+ })
1320
+
1321
+ async function onSubmit(values: z.infer<typeof formSchema>) {
1322
+ try {
1323
+ const response = await fetch("/api/contact", {
1324
+ method: "POST",
1325
+ headers: { "Content-Type": "application/json" },
1326
+ body: JSON.stringify(values),
1327
+ })
1328
+
1329
+ if (!response.ok) throw new Error("Failed to submit")
1330
+
1331
+ toast({
1332
+ title: "Success!",
1333
+ description: "Your message has been sent.",
1334
+ })
1335
+ } catch (error) {
1336
+ toast({
1337
+ variant: "destructive",
1338
+ title: "Error",
1339
+ description: "Failed to send message. Please try again.",
1340
+ })
1341
+ }
1342
+ }
1343
+
1344
+ export default function ContactPage() {
1345
+ const form = useForm<z.infer<typeof formSchema>>({
1346
+ resolver: zodResolver(formSchema),
1347
+ })
1348
+
1349
+ return (
1350
+ <div className="container mx-auto max-w-2xl py-8">
1351
+ <Form {...form}>
1352
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
1353
+ <FormField
1354
+ control={form.control}
1355
+ name="name"
1356
+ render={({ field }) => (
1357
+ <FormItem>
1358
+ <FormLabel>Name</FormLabel>
1359
+ <FormControl>
1360
+ <Input placeholder="Your name" {...field} />
1361
+ </FormControl>
1362
+ <FormMessage />
1363
+ </FormItem>
1364
+ )}
1365
+ />
1366
+
1367
+ <FormField
1368
+ control={form.control}
1369
+ name="email"
1370
+ render={({ field }) => (
1371
+ <FormItem>
1372
+ <FormLabel>Email</FormLabel>
1373
+ <FormControl>
1374
+ <Input type="email" placeholder="your@email.com" {...field} />
1375
+ </FormControl>
1376
+ <FormMessage />
1377
+ </FormItem>
1378
+ )}
1379
+ />
1380
+
1381
+ <FormField
1382
+ control={form.control}
1383
+ name="message"
1384
+ render={({ field }) => (
1385
+ <FormItem>
1386
+ <FormLabel>Message</FormLabel>
1387
+ <FormControl>
1388
+ <Textarea
1389
+ placeholder="Your message..."
1390
+ className="resize-none"
1391
+ {...field}
1392
+ />
1393
+ </FormControl>
1394
+ <FormMessage />
1395
+ </FormItem>
1396
+ )}
1397
+ />
1398
+
1399
+ <Button type="submit" className="w-full">
1400
+ Send Message
1401
+ </Button>
1402
+ </form>
1403
+ </Form>
1404
+ </div>
1405
+ )
1406
+ }
1407
+ ```
1408
+
1409
+ ### Metadata with shadcn/ui
1410
+
1411
+ Using shadcn/ui components in metadata:
1412
+
1413
+ ```tsx
1414
+ // app/layout.tsx
1415
+ import { Metadata } from "next"
1416
+
1417
+ export const metadata: Metadata = {
1418
+ title: {
1419
+ default: "My App",
1420
+ template: "%s | My App",
1421
+ },
1422
+ description: "Built with shadcn/ui and Next.js",
1423
+ }
1424
+
1425
+ // app/about/page.tsx
1426
+ import { Metadata } from "next"
1427
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
1428
+
1429
+ export const metadata: Metadata = {
1430
+ title: "About Us",
1431
+ description: "Learn more about our company",
1432
+ }
1433
+
1434
+ export default function AboutPage() {
1435
+ return (
1436
+ <div className="container mx-auto py-8">
1437
+ <Card>
1438
+ <CardHeader>
1439
+ <CardTitle>About Our Company</CardTitle>
1440
+ </CardHeader>
1441
+ <CardContent>
1442
+ <p>We build amazing products with modern web technologies.</p>
1443
+ </CardContent>
1444
+ </Card>
1445
+ </div>
1446
+ )
1447
+ }
1448
+ ```
1449
+
1450
+ ### Font Optimization
1451
+
1452
+ Optimize fonts with next/font:
1453
+
1454
+ ```tsx
1455
+ // app/layout.tsx
1456
+ import { Inter } from "next/font/google"
1457
+ import { Toaster } from "@/components/ui/toaster"
1458
+ import { cn } from "@/lib/utils"
1459
+ import "./globals.css"
1460
+
1461
+ const inter = Inter({ subsets: ["latin"] })
1462
+
1463
+ export default function RootLayout({
1464
+ children,
1465
+ }: {
1466
+ children: React.ReactNode
1467
+ }) {
1468
+ return (
1469
+ <html lang="en" suppressHydrationWarning>
1470
+ <body className={cn("min-h-screen bg-background font-sans antialiased", inter.className)}>
1471
+ {children}
1472
+ <Toaster />
1473
+ </body>
1474
+ </html>
1475
+ )
1476
+ }
1477
+ ```
1478
+
1479
+ ## Advanced Patterns
1480
+
1481
+ ### Form with Multiple Fields
1482
+
1483
+ ```tsx
1484
+ const formSchema = z.object({
1485
+ username: z.string().min(2).max(50),
1486
+ email: z.string().email(),
1487
+ bio: z.string().max(160).min(4),
1488
+ role: z.enum(["admin", "user", "guest"]),
1489
+ notifications: z.boolean().default(false),
1490
+ })
1491
+
1492
+ export function AdvancedForm() {
1493
+ const form = useForm<z.infer<typeof formSchema>>({
1494
+ resolver: zodResolver(formSchema),
1495
+ defaultValues: {
1496
+ username: "",
1497
+ email: "",
1498
+ bio: "",
1499
+ role: "user",
1500
+ notifications: false,
1501
+ },
1502
+ })
1503
+
1504
+ function onSubmit(values: z.infer<typeof formSchema>) {
1505
+ console.log(values)
1506
+ }
1507
+
1508
+ return (
1509
+ <Form {...form}>
1510
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
1511
+ {/* Username field */}
1512
+ <FormField
1513
+ control={form.control}
1514
+ name="username"
1515
+ render={({ field }) => (
1516
+ <FormItem>
1517
+ <FormLabel>Username</FormLabel>
1518
+ <FormControl>
1519
+ <Input placeholder="johndoe" {...field} />
1520
+ </FormControl>
1521
+ <FormMessage />
1522
+ </FormItem>
1523
+ )}
1524
+ />
1525
+
1526
+ {/* Email field */}
1527
+ <FormField
1528
+ control={form.control}
1529
+ name="email"
1530
+ render={({ field }) => (
1531
+ <FormItem>
1532
+ <FormLabel>Email</FormLabel>
1533
+ <FormControl>
1534
+ <Input type="email" placeholder="john@example.com" {...field} />
1535
+ </FormControl>
1536
+ <FormMessage />
1537
+ </FormItem>
1538
+ )}
1539
+ />
1540
+
1541
+ {/* Textarea field */}
1542
+ <FormField
1543
+ control={form.control}
1544
+ name="bio"
1545
+ render={({ field }) => (
1546
+ <FormItem>
1547
+ <FormLabel>Bio</FormLabel>
1548
+ <FormControl>
1549
+ <Textarea
1550
+ placeholder="Tell us about yourself"
1551
+ className="resize-none"
1552
+ {...field}
1553
+ />
1554
+ </FormControl>
1555
+ <FormMessage />
1556
+ </FormItem>
1557
+ )}
1558
+ />
1559
+
1560
+ {/* Select field */}
1561
+ <FormField
1562
+ control={form.control}
1563
+ name="role"
1564
+ render={({ field }) => (
1565
+ <FormItem>
1566
+ <FormLabel>Role</FormLabel>
1567
+ <Select onValueChange={field.onChange} defaultValue={field.value}>
1568
+ <FormControl>
1569
+ <SelectTrigger>
1570
+ <SelectValue placeholder="Select a role" />
1571
+ </SelectTrigger>
1572
+ </FormControl>
1573
+ <SelectContent>
1574
+ <SelectItem value="admin">Admin</SelectItem>
1575
+ <SelectItem value="user">User</SelectItem>
1576
+ <SelectItem value="guest">Guest</SelectItem>
1577
+ </SelectContent>
1578
+ </Select>
1579
+ <FormMessage />
1580
+ </FormItem>
1581
+ )}
1582
+ />
1583
+
1584
+ {/* Checkbox field */}
1585
+ <FormField
1586
+ control={form.control}
1587
+ name="notifications"
1588
+ render={({ field }) => (
1589
+ <FormItem className="flex flex-row items-start space-x-3 space-y-0">
1590
+ <FormControl>
1591
+ <Checkbox
1592
+ checked={field.value}
1593
+ onCheckedChange={field.onChange}
1594
+ />
1595
+ </FormControl>
1596
+ <div className="space-y-1 leading-none">
1597
+ <FormLabel>Email notifications</FormLabel>
1598
+ <FormDescription>
1599
+ Receive emails about your account activity.
1600
+ </FormDescription>
1601
+ </div>
1602
+ </FormItem>
1603
+ )}
1604
+ />
1605
+
1606
+ <Button type="submit">Submit</Button>
1607
+ </form>
1608
+ </Form>
1609
+ )
1610
+ }
1611
+ ```
1612
+
1613
+ ## Best Practices
1614
+
1615
+ 1. **Accessibility**: Components use Radix UI primitives for ARIA compliance
1616
+ 2. **Customization**: Modify components directly in your codebase
1617
+ 3. **Type Safety**: Use TypeScript for type-safe props and state
1618
+ 4. **Validation**: Use Zod schemas for form validation
1619
+ 5. **Styling**: Leverage Tailwind utilities and CSS variables
1620
+ 6. **Consistency**: Use the same component patterns across your app
1621
+ 7. **Testing**: Components are testable with React Testing Library
1622
+ 8. **Performance**: Components are optimized and tree-shakeable
1623
+
1624
+ ## Common Component Combinations
1625
+
1626
+ ### Login Form
1627
+
1628
+ ```tsx
1629
+ <Card className="w-[350px]">
1630
+ <CardHeader>
1631
+ <CardTitle>Login</CardTitle>
1632
+ <CardDescription>Enter your credentials to continue</CardDescription>
1633
+ </CardHeader>
1634
+ <CardContent>
1635
+ <Form {...form}>
1636
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
1637
+ <FormField
1638
+ control={form.control}
1639
+ name="email"
1640
+ render={({ field }) => (
1641
+ <FormItem>
1642
+ <FormLabel>Email</FormLabel>
1643
+ <FormControl>
1644
+ <Input type="email" placeholder="you@example.com" {...field} />
1645
+ </FormControl>
1646
+ <FormMessage />
1647
+ </FormItem>
1648
+ )}
1649
+ />
1650
+ <FormField
1651
+ control={form.control}
1652
+ name="password"
1653
+ render={({ field }) => (
1654
+ <FormItem>
1655
+ <FormLabel>Password</FormLabel>
1656
+ <FormControl>
1657
+ <Input type="password" {...field} />
1658
+ </FormControl>
1659
+ <FormMessage />
1660
+ </FormItem>
1661
+ )}
1662
+ />
1663
+ <Button type="submit" className="w-full">Login</Button>
1664
+ </form>
1665
+ </Form>
1666
+ </CardContent>
1667
+ </Card>
1668
+ ```
1669
+
1670
+ ## References
1671
+
1672
+ - Official Docs: https://ui.shadcn.com
1673
+ - Radix UI: https://www.radix-ui.com
1674
+ - React Hook Form: https://react-hook-form.com
1675
+ - Zod: https://zod.dev
1676
+ - Tailwind CSS: https://tailwindcss.com
1677
+ - Examples: https://ui.shadcn.com/examples