@minhduydev/mdpi 0.4.0 → 0.5.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 (48) hide show
  1. package/dist/index.js +1 -1
  2. package/dist/template/.pi/VERSION +1 -1
  3. package/dist/template/.pi/extensions/templates-injector.ts +34 -6
  4. package/dist/template/.pi/prompts/INDEX.md +3 -9
  5. package/dist/template/.pi/skills/INDEX.md +81 -19
  6. package/dist/template/.pi/skills/accessibility-audit/SKILL.md +8 -2
  7. package/dist/template/.pi/skills/baseline-ui/SKILL.md +211 -0
  8. package/dist/template/.pi/skills/dcp-hygiene/SKILL.md +1 -1
  9. package/dist/template/.pi/skills/design-taste-frontend/SKILL.md +53 -42
  10. package/dist/template/.pi/skills/fixing-accessibility/SKILL.md +509 -0
  11. package/dist/template/.pi/skills/frontend-design/SKILL.md +60 -47
  12. package/dist/template/.pi/skills/frontend-design/references/animation/motion-advanced.md +88 -15
  13. package/dist/template/.pi/skills/frontend-design/references/animation/motion-core.md +148 -13
  14. package/dist/template/.pi/skills/frontend-design/references/shadcn/setup.md +127 -20
  15. package/dist/template/.pi/skills/frontend-ui-engineering/SKILL.md +21 -27
  16. package/dist/template/.pi/skills/nextjs-app-router/SKILL.md +334 -0
  17. package/dist/template/.pi/skills/nextjs-cache/SKILL.md +262 -0
  18. package/dist/template/.pi/skills/oklch-color-workflow/SKILL.md +426 -0
  19. package/dist/template/.pi/skills/production-hardening/SKILL.md +652 -0
  20. package/dist/template/.pi/skills/react-best-practices/SKILL.md +79 -1
  21. package/dist/template/.pi/skills/react-compiler/SKILL.md +237 -0
  22. package/dist/template/.pi/skills/react-hook-form/SKILL.md +374 -0
  23. package/dist/template/.pi/skills/react-server-actions/SKILL.md +299 -0
  24. package/dist/template/.pi/skills/shadcn-ui/SKILL.md +404 -0
  25. package/dist/template/.pi/skills/tanstack-query/SKILL.md +330 -0
  26. package/dist/template/.pi/skills/ui-craft-principles/SKILL.md +564 -0
  27. package/dist/template/.pi/skills/ui-quality-audit/SKILL.md +329 -0
  28. package/dist/template/.pi/skills/v0/SKILL.md +264 -0
  29. package/dist/template/.pi/skills/zustand/SKILL.md +333 -0
  30. package/dist/template/.pi/templates/DESIGN.md +76 -0
  31. package/dist/template/.pi/workflows/INDEX.md +2 -1
  32. package/dist/template/.pi/workflows/frontend-feature-workflow.md +343 -0
  33. package/dist/template/.pi/workflows/quality-loop.md +1 -1
  34. package/package.json +1 -1
  35. package/dist/template/.pi/prompts/loop-check.md +0 -87
  36. package/dist/template/.pi/prompts/loop-init.md +0 -157
  37. package/dist/template/.pi/prompts/loop-review.md +0 -90
  38. package/dist/template/.pi/skills/loop-audit/SKILL.md +0 -141
  39. package/dist/template/.pi/skills/loop-cost/SKILL.md +0 -130
  40. package/dist/template/.pi/skills/loop-engineering/SKILL.md +0 -175
  41. package/dist/template/.pi/templates/loop-github-action.yml +0 -162
  42. package/dist/template/.pi/templates/loop-orchestrator.sh +0 -514
  43. package/dist/template/.pi/templates/loop-orchestrator.test.ts +0 -332
  44. package/dist/template/.pi/templates/loop-orchestrator.ts +0 -936
  45. package/dist/template/.pi/templates/loop-state.json +0 -24
  46. package/dist/template/.pi/templates/loop-state.md +0 -98
  47. package/dist/template/.pi/templates/loop-vision.md +0 -110
  48. /package/dist/template/.pi/templates/{design.md → feature-design.md} +0 -0
@@ -0,0 +1,299 @@
1
+ ---
2
+ name: react-server-actions
3
+ description: Use when building forms, mutations, or data writes in React 19 + Next.js. Covers Server Actions, useActionState, useOptimistic, useFormStatus, progressive enhancement, Zod validation, error handling. MUST load before any form or mutation implementation.
4
+ ---
5
+
6
+ # React Server Actions & Forms (React 19)
7
+
8
+ ## When to Use
9
+
10
+ - Building forms that submit data to the server
11
+ - Handling mutations (create, update, delete) in React 19
12
+ - Adding optimistic updates to improve perceived performance
13
+ - Integrating Zod validation with Server Actions
14
+ - Migrating from API routes or tRPC to Server Actions
15
+ - Implementing progressive enhancement (forms work without JS)
16
+
17
+ ## When NOT to Use
18
+
19
+ - Read-only data fetching (use Server Components, `use()`, or TanStack Query)
20
+ - Client-only state management (use Zustand or context)
21
+ - Non-Next.js React projects without Server Action support
22
+
23
+ ## Core Pattern: Server Action + useActionState
24
+
25
+ ```tsx
26
+ // app/actions.ts
27
+ 'use server'
28
+
29
+ import { z } from 'zod'
30
+ import { revalidatePath } from 'next/cache'
31
+
32
+ const schema = z.object({
33
+ name: z.string().min(2),
34
+ email: z.string().email(),
35
+ })
36
+
37
+ export async function createUser(prevState: unknown, formData: FormData) {
38
+ // 1. Parse and validate
39
+ const raw = Object.fromEntries(formData)
40
+ const parsed = schema.safeParse(raw)
41
+
42
+ if (!parsed.success) {
43
+ return { error: parsed.error.flatten().fieldErrors }
44
+ }
45
+
46
+ // 2. Mutate (database call)
47
+ await db.user.create({ data: parsed.data })
48
+
49
+ // 3. Revalidate and redirect
50
+ revalidatePath('/users')
51
+ return { success: true }
52
+ }
53
+ ```
54
+
55
+ ```tsx
56
+ // app/new/page.tsx
57
+ 'use client'
58
+
59
+ import { useActionState } from 'react'
60
+ import { useFormStatus } from 'react-dom'
61
+ import { createUser } from './actions'
62
+
63
+ function SubmitButton() {
64
+ const { pending } = useFormStatus()
65
+ return (
66
+ <button type="submit" disabled={pending}>
67
+ {pending ? 'Creating...' : 'Create User'}
68
+ </button>
69
+ )
70
+ }
71
+
72
+ export default function NewUserForm() {
73
+ const [state, formAction] = useActionState(createUser, null)
74
+
75
+ return (
76
+ <form action={formAction}>
77
+ <input name="name" required />
78
+ {state?.error?.name && <p>{state.error.name[0]}</p>}
79
+
80
+ <input name="email" type="email" required />
81
+ {state?.error?.email && <p>{state.error.email[0]}</p>}
82
+
83
+ <SubmitButton />
84
+ {state?.success && <p className="text-green-600">User created!</p>}
85
+ </form>
86
+ )
87
+ }
88
+ ```
89
+
90
+ ## Hook Reference
91
+
92
+ ### `useActionState(action, initialState, permalink?)`
93
+
94
+ ```tsx
95
+ const [state, formAction, isPending] = useActionState(action, null)
96
+ ```
97
+
98
+ - Replaces `useFormState` (deprecated in React 19)
99
+ - `state` — return value from your Server Action
100
+ - `formAction` — pass as `<form action={formAction}>`
101
+ - `isPending` — convenient boolean for loading state
102
+ - `permalink` — optional URL for progressive enhancement fallback
103
+
104
+ ### `useFormStatus()`
105
+
106
+ ```tsx
107
+ const { pending, data, method, action } = useFormStatus()
108
+ ```
109
+
110
+ - **Must be used inside a `<form>` child component** — not in the component that renders `<form>`
111
+ - Extract `<SubmitButton>` as a separate component
112
+ - `pending` — true while form is submitting
113
+ - `data` — the FormData being submitted
114
+
115
+ ### `useOptimistic(initialValue, reducer)`
116
+
117
+ ```tsx
118
+ const [optimisticTodos, addOptimistic] = useOptimistic(
119
+ todos,
120
+ (state, newTodo: Todo) => [...state, newTodo]
121
+ )
122
+
123
+ // In event handler:
124
+ addOptimistic({ id: crypto.randomUUID(), text, pending: true })
125
+ await addTodoOnServer(formData)
126
+ ```
127
+
128
+ - Shows UI change immediately, reverts on error
129
+ - `reducer` signature: `(currentState, optimisticValue) => newState`
130
+ - Good for: like counters, comment posting, toggle states
131
+
132
+ ## Zod Integration
133
+
134
+ ```tsx
135
+ 'use server'
136
+
137
+ import { z } from 'zod'
138
+
139
+ const SignupSchema = z.object({
140
+ email: z.string().email('Invalid email'),
141
+ password: z.string().min(8, 'Min 8 characters'),
142
+ age: z.coerce.number().min(18, 'Must be 18+'),
143
+ plan: z.enum(['free', 'pro', 'enterprise']),
144
+ })
145
+
146
+ export async function signup(prev: unknown, formData: FormData) {
147
+ const result = SignupSchema.safeParse(Object.fromEntries(formData))
148
+
149
+ if (!result.success) {
150
+ // Return flattened errors keyed by field
151
+ return {
152
+ errors: result.error.flatten().fieldErrors,
153
+ inputs: Object.fromEntries(formData) // preserve user input
154
+ }
155
+ }
156
+
157
+ await createAccount(result.data)
158
+ return { success: true }
159
+ }
160
+ ```
161
+
162
+ ## Progressive Enhancement
163
+
164
+ Server Actions support HTML form fallback — forms work without JavaScript:
165
+
166
+ ```tsx
167
+ // The form works even if JS fails to load:
168
+ <form action={createUser}>
169
+ <input name="name" required />
170
+ <button type="submit">Submit</button>
171
+ </form>
172
+ ```
173
+
174
+ For the JS-enhanced version, use `useActionState` which wraps the same Server Action.
175
+
176
+ **Requirements for progressive enhancement:**
177
+ - Use native `<form>` and `<button type="submit">`
178
+ - Use `required` attribute for client-side validation
179
+ - All form fields must have `name` attributes
180
+ - Server Action must accept `FormData` as second argument
181
+
182
+ ## Error Handling Pattern
183
+
184
+ ```tsx
185
+ type ActionState = {
186
+ error?: string // General error
187
+ errors?: Record<string, string[]> // Field-level errors
188
+ success?: boolean // Success flag
189
+ data?: unknown // Return data on success
190
+ }
191
+
192
+ // In Server Action:
193
+ try {
194
+ await db.user.create({ data: parsed.data })
195
+ return { success: true }
196
+ } catch (err) {
197
+ if (err instanceof PrismaClientKnownRequestError && err.code === 'P2002') {
198
+ return { errors: { email: ['Email already registered'] } }
199
+ }
200
+ return { error: 'Something went wrong. Please try again.' }
201
+ }
202
+ ```
203
+
204
+ ## Redirect After Success
205
+
206
+ ```tsx
207
+ 'use server'
208
+
209
+ import { redirect } from 'next/navigation'
210
+
211
+ export async function createPost(prev: unknown, formData: FormData) {
212
+ const post = await db.post.create({ data: { title: formData.get('title') } })
213
+ revalidatePath('/posts')
214
+ redirect(`/posts/${post.id}`)
215
+ }
216
+ ```
217
+
218
+ **Important**: `redirect()` throws a `NEXT_REDIRECT` error — call it after all mutations. Cannot be inside try/catch.
219
+
220
+ ## Avoiding Common Pitfalls
221
+
222
+ | Pitfall | Fix |
223
+ |---------|-----|
224
+ | `useFormStatus()` in the form component itself | Extract `<SubmitButton>` to its own component |
225
+ | Not calling `revalidatePath` after mutation | Always revalidate the affected path |
226
+ | Using `redirect()` inside try/catch | Move redirect outside try/catch |
227
+ | Passing sensitive data as hidden inputs | Validate on server — never trust client data |
228
+ | Server Action not at top of file | `'use server'` directive must be first line |
229
+ | Mutating in Server Components | Server Components are read-only; use `'use client'` + action |
230
+ | Zod `safeParse` then ignoring errors | Always return errors to the form |
231
+ | Multiple forms on one page sharing action | Each form gets its own action or use a field to discriminate |
232
+
233
+ ## Multiple Actions Per Form
234
+
235
+ ```tsx
236
+ <form>
237
+ <button formAction={saveDraft}>Save Draft</button>
238
+ <button formAction={publish}>Publish</button>
239
+ </form>
240
+ ```
241
+
242
+ Each button can have its own `formAction` pointing to a different Server Action.
243
+
244
+ ## Non-Form Mutations (Calling Actions Programmatically)
245
+
246
+ ```tsx
247
+ // For button clicks, toggles, etc. — import and call:
248
+ 'use client'
249
+
250
+ import { toggleLike } from './actions'
251
+
252
+ function LikeButton({ postId }: { postId: string }) {
253
+ const [optimistic, addOptimistic] = useOptimistic(
254
+ false,
255
+ (_, liked: boolean) => liked
256
+ )
257
+
258
+ return (
259
+ <button
260
+ onClick={async () => {
261
+ addOptimistic(!optimistic)
262
+ await toggleLike(postId)
263
+ }}
264
+ >
265
+ {optimistic ? '❤️' : '🤍'}
266
+ </button>
267
+ )
268
+ }
269
+ ```
270
+
271
+ ## Integration with Other Skills
272
+
273
+ | Skill | Relationship |
274
+ |-------|-------------|
275
+ | `react-hook-form` | Alternative form approach (client-side state) — use when you need complex field interactions or field arrays |
276
+ | `nextjs-cache` | After mutation, `revalidatePath` / `revalidateTag` to invalidate cache |
277
+ | `nextjs-app-router` | Form pages use App Router conventions (loading.tsx for submit state) |
278
+ | `tanstack-query` | For GET/read operations — Server Actions are for mutations only |
279
+
280
+ ## When to Use Server Actions vs API Routes
281
+
282
+ | Use Server Actions for | Use API Routes for |
283
+ |-----------------------|-------------------|
284
+ | Forms with progressive enhancement | Public APIs consumed by external clients |
285
+ | Mutations tightly coupled to UI | Webhooks / third-party callbacks |
286
+ | When you want co-located data flow | When you need cache headers, CORS, streaming |
287
+ | Optimistic updates | File uploads (use `multipart/form-data`) |
288
+
289
+ ## Verification
290
+
291
+ - [ ] `'use server'` is the first line of the action file
292
+ - [ ] Server Action accepts `(prevState, formData)` matching `useActionState` signature
293
+ - [ ] `useFormStatus` is in a child component (not the form itself)
294
+ - [ ] All form fields have `name` attributes (for FormData extraction)
295
+ - [ ] Zod validation returns field-level errors
296
+ - [ ] `revalidatePath` / `revalidateTag` called after mutations
297
+ - [ ] `redirect()` outside try/catch blocks
298
+ - [ ] Progressive enhancement: form works with JS disabled
299
+ - [ ] Optimistic updates use `useOptimistic` with clean revert on error
@@ -0,0 +1,404 @@
1
+ ---
2
+ name: shadcn-ui
3
+ description: Use when adding, configuring, or managing shadcn/ui components. Covers CLI v4, visual styles (Vega/Nova/Maia/Lyra/Mira), preset system, GitHub Registries, shadcn/skills AI prompt files, MCP registry, and component management. NOT a replacement for component API docs — see frontend-design's shadcn references for that.
4
+ ---
5
+
6
+ # shadcn/ui
7
+
8
+ ## When to Use
9
+
10
+ - Adding shadcn/ui components to a project (`npx shadcn add`)
11
+ - Initializing shadcn/ui in a new project (`npx shadcn init` / `npx shadcn create`)
12
+ - Choosing a visual style (Vega, Nova, Maia, Lyra, Mira)
13
+ - Configuring via the preset system or `components.json`
14
+ - Using shadcn/skills for AI-driven component generation
15
+ - Inspecting installed components (`shadcn info --json`)
16
+ - Previewing component changes before applying (`--dry-run`, `--diff`, `--view`)
17
+ - Setting up custom component registries
18
+
19
+ ## When NOT to Use
20
+
21
+ - When you need component API documentation (use `frontend-design` → `./references/shadcn/*.md`)
22
+ - When theming with CSS variables (use `frontend-design` → `./references/shadcn/theming.md`)
23
+ - When building plain UI without shadcn/ui components
24
+ - When the task is about v0 generation (use the `v0` skill instead)
25
+
26
+ ## Relationship to `frontend-design` References
27
+
28
+ This skill covers **shadcn/ui tooling and workflow** — CLI commands, presets, registries, skills, and configuration management.
29
+
30
+ For **component API documentation** (Button props, Card subcomponents, Dialog patterns, Select usage), see:
31
+ - `frontend-design` → `./references/shadcn/setup.md` — Installation, visual styles, component list
32
+ - `frontend-design` → `./references/shadcn/core-components.md` — Button, Card, Dialog, Select, Tabs, Toast, Command, Sidebar, Table
33
+ - `frontend-design` → `./references/shadcn/form-components.md` — Form, Field, InputGroup
34
+ - `frontend-design` → `./references/shadcn/theming.md` — CSS variables, OKLCH, dark mode
35
+ - `frontend-design` → `./references/shadcn/accessibility.md` — ARIA, keyboard, screen reader
36
+
37
+ ## CLI v4 (current: shadcn@4.11.0)
38
+
39
+ ### Starting Projects
40
+
41
+ ```bash
42
+ # Interactive project creation (recommended)
43
+ npx shadcn create
44
+
45
+ # This walks through:
46
+ # - Framework (Next.js, Vite, Remix, etc.)
47
+ # - Visual style (Vega, Nova, Maia, Lyra, Mira)
48
+ # - Component library backend (Radix UI or Base UI)
49
+ # - Icon library (including Phosphor)
50
+ # - TypeScript, Tailwind CSS, CSS variables setup
51
+ ```
52
+
53
+ ### Adding Components to Existing Projects
54
+
55
+ ```bash
56
+ # Initialize shadcn in existing project
57
+ npx shadcn@latest init
58
+
59
+ # Add specific components
60
+ npx shadcn@latest add button card dialog
61
+
62
+ # Add all components
63
+ npx shadcn@latest add --all
64
+
65
+ # Add from GitHub Registry
66
+ npx shadcn@latest add <username>/<repo>/<item>
67
+ ```
68
+
69
+ ### Safety & Inspection
70
+
71
+ ```bash
72
+ # Preview what will change (no writes)
73
+ npx shadcn@latest add button dialog --dry-run
74
+
75
+ # Show exact diff for a component
76
+ npx shadcn@latest add button --diff
77
+
78
+ # Open component in browser for review
79
+ npx shadcn@latest add button --view
80
+
81
+ # Inspect installed components as JSON
82
+ npx shadcn info --json
83
+
84
+ # Check version
85
+ npx shadcn --version
86
+ ```
87
+
88
+ ### `shadcn info --json`
89
+
90
+ Outputs structured data about installed components, useful for CI and tooling:
91
+
92
+ ```json
93
+ {
94
+ "version": "4.11.0",
95
+ "components": [
96
+ {
97
+ "name": "button",
98
+ "installed": true,
99
+ "version": "4.11.0",
100
+ "path": "components/ui/button.tsx",
101
+ "dependencies": ["@radix-ui/react-slot"],
102
+ "registrySource": "default"
103
+ }
104
+ ],
105
+ "style": "vega",
106
+ "aliases": {
107
+ "components": "@/components",
108
+ "ui": "@/components/ui",
109
+ "lib": "@/lib",
110
+ "utils": "@/lib/utils"
111
+ }
112
+ }
113
+ ```
114
+
115
+ ## Visual Styles
116
+
117
+ | Style | Vibe | Use Case |
118
+ |-------|------|----------|
119
+ | **Vega** | Classic shadcn — balanced, familiar | Default. Good for most projects. |
120
+ | **Nova** | Compact, reduced padding | Data-heavy dashboards, admin panels |
121
+ | **Maia** | Soft, rounded, generous padding | Consumer apps, marketing sites |
122
+ | **Lyra** | Boxy, sharp corners, monospace fonts | Developer tools, technical interfaces |
123
+ | **Mira** | Dense, efficient, minimal chrome | Internal tools, complex workflows |
124
+
125
+ Set during `npx shadcn create` or override per-component with `--style <name>`.
126
+
127
+ ## Preset System
128
+
129
+ Presets pack your entire design system config into a reproducible short code:
130
+
131
+ ```bash
132
+ # Export your design system as a preset code
133
+ npx shadcn preset export
134
+
135
+ # Init a new project with a preset
136
+ npx shadcn init --preset a1Dg5eFl
137
+ ```
138
+
139
+ A preset captures: visual style (Vega/Nova/Maia/Lyra/Mira), component library (Radix/Base UI), colors, theme, icons, fonts, radius, spacing — everything needed to reproduce the exact design system.
140
+
141
+ ## GitHub Registries (June 2026)
142
+
143
+ Any public GitHub repo with a `registry.json` can be a component registry.
144
+
145
+ ```bash
146
+ # Pull from a GitHub registry
147
+ npx shadcn@latest add <username>/<repo>/<item>
148
+
149
+ # Example
150
+ npx shadcn@latest add shadcn-ui/ui/data-table
151
+ ```
152
+
153
+ No build step needed — CLI reads `registry.json` directly. Distribute: components, hooks, utilities, design tokens, feature kits, project conventions, CI workflows, templates.
154
+
155
+ ### Registry Structure
156
+
157
+ ```json
158
+ // registry.json (in any GitHub repo root)
159
+ {
160
+ "name": "my-components",
161
+ "items": [
162
+ {
163
+ "name": "data-table",
164
+ "type": "registry:component",
165
+ "files": [{ "path": "components/data-table.tsx" }],
166
+ "dependencies": ["@tanstack/react-table"]
167
+ }
168
+ ]
169
+ }
170
+ ```
171
+
172
+ ## MCP Registry Server
173
+
174
+ Connect AI editors to your custom shadcn/ui registry:
175
+
176
+ ```json
177
+ {
178
+ "mcpServers": {
179
+ "shadcn": {
180
+ "command": "npx",
181
+ "args": ["-y", "shadcn@canary", "registry:mcp"],
182
+ "env": {
183
+ "REGISTRY_URL": "https://your-registry.vercel.app/r/registry.json"
184
+ }
185
+ }
186
+ }
187
+ }
188
+ ```
189
+
190
+ This allows AI agents (Cursor, Windsurf, Claude Desktop) to query and pull components from your custom design system registry.
191
+
192
+ ## shadcn/skills — AI Agent Prompt File
193
+
194
+ A machine-readable skills file that gives AI coding agents accurate, project-aware context about shadcn/ui.
195
+
196
+ ### Setup
197
+
198
+ ```bash
199
+ npx skills add shadcn/ui
200
+ ```
201
+
202
+ Creates `.shadcn/skills.md` — automatically injected into AI agent context.
203
+
204
+ ### What It Provides
205
+
206
+ - **Project context** — framework, aliases, installed components (via `shadcn info --json`)
207
+ - **CLI commands** — all flags, smart merge, presets, templates
208
+ - **Theming** — CSS vars, OKLCH, dark mode, Tailwind v3/v4
209
+ - **Registry authoring** — `registry.json` format, item types, dependencies
210
+ - **Pattern enforcement** — `FieldGroup` for forms, `ToggleGroup` for options, semantic colors
211
+
212
+ ### Measured Impact
213
+
214
+ | Metric | Before Skills | After Skills |
215
+ |--------|--------------|-------------|
216
+ | API errors | 34% | 3% |
217
+ | Correct variants | 61% | 98% |
218
+ | First-try success | 45% | 89% |
219
+
220
+ ### Critical Workflows
221
+
222
+ ```bash
223
+ # Install
224
+ npx skills add shadcn/ui
225
+
226
+ # Regenerate after adding components (CRITICAL!)
227
+ npx shadcn skills generate
228
+
229
+ # Update monthly to stay current
230
+ npx shadcn skills update
231
+ ```
232
+
233
+ ### Pitfalls
234
+
235
+ | Mistake | Fix |
236
+ |---------|-----|
237
+ | Not regenerating after adding components | Add `shadcn skills generate` to post-install script |
238
+ | Skills getting cut off from context limit | Reference file path; don't paste contents |
239
+ | Using outdated skills (3+ months old) | Run `shadcn skills update` monthly |
240
+ | Ignoring the preset system | Use presets; customize through Tailwind config, not per-component CSS |
241
+
242
+ ## Components (2026)
243
+
244
+ ### New in 2026
245
+
246
+ | Component | Description |
247
+ |-----------|-------------|
248
+ | **Field** | Form field wrapper with label, description, error message |
249
+ | **InputGroup** | Grouped inputs with addons (prefix/suffix) |
250
+ | **Spinner** | Loading spinner with size variants |
251
+ | **Kbd** | Keyboard shortcut display |
252
+ | **ButtonGroup** | Grouped button toolbar |
253
+ | **Item** | Generic list item with icon, text, and actions |
254
+ | **Empty** | Empty state with illustration, text, and action |
255
+
256
+ ### Component Installation
257
+
258
+ ```bash
259
+ npx shadcn@latest add field input-group spinner kbd button-group item empty
260
+ ```
261
+
262
+ ### Quick Reference — New Components
263
+
264
+ #### Field
265
+
266
+ ```tsx
267
+ import { Field, FieldLabel, FieldDescription, FieldError } from "@/components/ui/field"
268
+
269
+ <Field>
270
+ <FieldLabel>Email</FieldLabel>
271
+ <Input placeholder="you@example.com" />
272
+ <FieldDescription>We'll never share your email.</FieldDescription>
273
+ <FieldError>{errors.email}</FieldError>
274
+ </Field>
275
+ ```
276
+
277
+ #### InputGroup
278
+
279
+ ```tsx
280
+ import { InputGroup, InputGroupAddon } from "@/components/ui/input-group"
281
+
282
+ <InputGroup>
283
+ <InputGroupAddon>https://</InputGroupAddon>
284
+ <Input placeholder="example.com" />
285
+ <InputGroupAddon>.com</InputGroupAddon>
286
+ </InputGroup>
287
+ ```
288
+
289
+ #### Spinner
290
+
291
+ ```tsx
292
+ import { Spinner } from "@/components/ui/spinner"
293
+
294
+ <Spinner />
295
+ <Spinner size="sm" />
296
+ <Spinner className="text-primary" />
297
+ ```
298
+
299
+ #### Kbd
300
+
301
+ ```tsx
302
+ import { Kbd } from "@/components/ui/kbd"
303
+
304
+ <Kbd>⌘K</Kbd>
305
+ <Kbd variant="outline">Ctrl + S</Kbd>
306
+ ```
307
+
308
+ #### ButtonGroup
309
+
310
+ ```tsx
311
+ import { ButtonGroup } from "@/components/ui/button-group"
312
+ import { Button } from "@/components/ui/button"
313
+
314
+ <ButtonGroup>
315
+ <Button variant="outline">Day</Button>
316
+ <Button variant="outline">Week</Button>
317
+ <Button variant="outline">Month</Button>
318
+ </ButtonGroup>
319
+ ```
320
+
321
+ #### Item
322
+
323
+ ```tsx
324
+ import { Item, ItemIcon, ItemText, ItemAction } from "@/components/ui/item"
325
+
326
+ <Item>
327
+ <ItemIcon><SettingsIcon /></ItemIcon>
328
+ <ItemText primary="Settings" secondary="Manage preferences" />
329
+ <ItemAction><ChevronRight /></ItemAction>
330
+ </Item>
331
+ ```
332
+
333
+ #### Empty
334
+
335
+ ```tsx
336
+ import { Empty } from "@/components/ui/empty"
337
+
338
+ <Empty
339
+ title="No results"
340
+ description="Try adjusting your filters."
341
+ action={<Button>Clear filters</Button>}
342
+ />
343
+ ```
344
+
345
+ ## Configuration
346
+
347
+ ### `components.json`
348
+
349
+ The central configuration file:
350
+
351
+ ```json
352
+ {
353
+ "$schema": "https://ui.shadcn.com/schema.json",
354
+ "style": "nova",
355
+ "rsc": true,
356
+ "tsx": true,
357
+ "tailwind": {
358
+ "config": "tailwind.config.ts",
359
+ "css": "app/globals.css",
360
+ "cssVariables": true,
361
+ "prefix": ""
362
+ },
363
+ "aliases": {
364
+ "components": "@/components",
365
+ "ui": "@/components/ui",
366
+ "lib": "@/lib",
367
+ "utils": "@/lib/utils",
368
+ "hooks": "@/hooks"
369
+ },
370
+ "iconLibrary": "lucide",
371
+ "registries": [
372
+ {
373
+ "name": "team",
374
+ "url": "gh:my-org/shadcn-registry"
375
+ }
376
+ ]
377
+ }
378
+ ```
379
+
380
+ ## Anti-Patterns
381
+
382
+ | Anti-Pattern | Why | Correct |
383
+ |---|---|---|
384
+ | Manually editing component primitives | Upstream updates become impossible to merge | Extend with wrapper components instead |
385
+ | Importing from shadcn as a package | shadcn/ui is copy-paste, not an npm package | Components live in your `components/ui/` directory |
386
+ | Adding `--all` without reviewing | Installs 50+ components, most unused | Only install what you need |
387
+ | Using hard-coded Tailwind values | Breaks theming and dark mode | Reference CSS variable tokens |
388
+ | Overriding `@theme` without preserving shadcn tokens | Breaks component styling | Extend `@theme`, don't replace it |
389
+ | Editing CSS variables inline | Hard to maintain theme switching | Define variables once, reference by semantic name |
390
+
391
+ ## Verification
392
+
393
+ After working with shadcn/ui:
394
+
395
+ - [ ] `components.json` exists and is configured correctly
396
+ - [ ] Only needed components are installed (no `--all` waste)
397
+ - [ ] CSS variables are used for colors (no hard-coded hex/rgb in components)
398
+ - [ ] Dark mode works via CSS variable overrides
399
+ - [ ] Components compile with TypeScript strict mode
400
+ - [ ] `npx shadcn info --json` shows expected installed components
401
+ - [ ] Preset saved if project has custom styling
402
+ - [ ] `shadcn/skills/` directory exists if project has custom conventions
403
+ - [ ] Aliases match project structure (`@/components/ui/`, `@/lib/utils`)
404
+ - [ ] No manually edited primitives that would conflict with updates