ui-ux-consultant-cli 1.0.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 (30) hide show
  1. package/assets/ui-ux-consultant/SKILL.md +844 -0
  2. package/assets/ui-ux-consultant/references/accessibility.md +175 -0
  3. package/assets/ui-ux-consultant/references/alt-libraries.md +90 -0
  4. package/assets/ui-ux-consultant/references/animations.md +448 -0
  5. package/assets/ui-ux-consultant/references/catalog/colors.md +91 -0
  6. package/assets/ui-ux-consultant/references/catalog/fonts.md +363 -0
  7. package/assets/ui-ux-consultant/references/catalog/products.md +340 -0
  8. package/assets/ui-ux-consultant/references/catalog/styles.md +165 -0
  9. package/assets/ui-ux-consultant/references/components.md +1116 -0
  10. package/assets/ui-ux-consultant/references/patterns.md +600 -0
  11. package/assets/ui-ux-consultant/references/performance.md +198 -0
  12. package/assets/ui-ux-consultant/references/stacks/astro.md +382 -0
  13. package/assets/ui-ux-consultant/references/stacks/flutter.md +308 -0
  14. package/assets/ui-ux-consultant/references/stacks/html-tailwind.md +415 -0
  15. package/assets/ui-ux-consultant/references/stacks/jetpack-compose.md +333 -0
  16. package/assets/ui-ux-consultant/references/stacks/laravel.md +521 -0
  17. package/assets/ui-ux-consultant/references/stacks/nextjs.md +275 -0
  18. package/assets/ui-ux-consultant/references/stacks/nuxt-ui.md +384 -0
  19. package/assets/ui-ux-consultant/references/stacks/nuxtjs.md +264 -0
  20. package/assets/ui-ux-consultant/references/stacks/react-native.md +346 -0
  21. package/assets/ui-ux-consultant/references/stacks/react.md +268 -0
  22. package/assets/ui-ux-consultant/references/stacks/shadcn.md +485 -0
  23. package/assets/ui-ux-consultant/references/stacks/svelte.md +429 -0
  24. package/assets/ui-ux-consultant/references/stacks/swiftui.md +336 -0
  25. package/assets/ui-ux-consultant/references/stacks/threejs.md +366 -0
  26. package/assets/ui-ux-consultant/references/stacks/vue.md +272 -0
  27. package/assets/ui-ux-consultant/references/theming.md +701 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +130 -0
  30. package/package.json +51 -0
@@ -0,0 +1,275 @@
1
+ # Next.js UI/UX Guidelines
2
+
3
+ ## When to read this
4
+ Read this file when building with Next.js 14+ App Router. Covers server vs client components, data fetching patterns, routing, images, metadata, and performance for production Next.js apps.
5
+
6
+ ## Recommended UI Libraries
7
+
8
+ | Library | Best for | Install |
9
+ |---|---|---|
10
+ | shadcn/ui | UI components | `npx shadcn@latest init` |
11
+ | next-auth v5 | Authentication | `npm install next-auth@beta` |
12
+ | TanStack Query | Client-side caching | `npm install @tanstack/react-query` |
13
+ | Prisma | Database ORM | `npm install prisma` |
14
+ | Zod | Schema validation | `npm install zod` |
15
+ | nuqs | URL search params state | `npm install nuqs` |
16
+
17
+ ## Style Recommendations by App Type
18
+
19
+ - **SaaS product:** shadcn/ui + custom color tokens in `globals.css`
20
+ - **Marketing site:** shadcn/ui + Tailwind animations + dark mode
21
+ - **Dashboard/admin:** shadcn/ui data table + sidebar layout
22
+ - **E-commerce:** Custom product cards, cart drawer, optimistic updates
23
+
24
+ ## Top UX Patterns
25
+
26
+ ### 1. Streaming Loading UI with loading.tsx
27
+ ```tsx
28
+ // app/dashboard/loading.tsx
29
+ export default function Loading() {
30
+ return <DashboardSkeleton />;
31
+ }
32
+ // Automatically shown while page.tsx's async data resolves
33
+ // No extra code needed in page.tsx
34
+ ```
35
+
36
+ ### 2. Server Action with Error Handling
37
+ ```tsx
38
+ 'use server';
39
+ import { revalidatePath } from 'next/cache';
40
+
41
+ export async function createItem(formData: FormData) {
42
+ const title = formData.get('title') as string;
43
+ try {
44
+ await db.item.create({ data: { title } });
45
+ revalidatePath('/items');
46
+ return { success: true };
47
+ } catch {
48
+ return { error: 'Failed to create item' };
49
+ }
50
+ }
51
+
52
+ // Client component usage
53
+ function ItemForm() {
54
+ const [state, formAction] = useFormState(createItem, null);
55
+ return (
56
+ <form action={formAction}>
57
+ <input name="title" required />
58
+ {state?.error && <p className="text-red-500">{state.error}</p>}
59
+ <button type="submit">Create</button>
60
+ </form>
61
+ );
62
+ }
63
+ ```
64
+
65
+ ### 3. Route-Level Data Fetching (Server Component)
66
+ ```tsx
67
+ // app/users/[id]/page.tsx
68
+ import { notFound } from 'next/navigation';
69
+
70
+ export default async function UserPage({ params }: { params: { id: string } }) {
71
+ const user = await db.user.findUnique({ where: { id: params.id } });
72
+ if (!user) notFound();
73
+ return <UserProfile user={user} />;
74
+ }
75
+ ```
76
+
77
+ ### 4. Parallel Data Fetching
78
+ ```tsx
79
+ // BAD: sequential — each awaits the previous (slow)
80
+ const user = await getUser(id);
81
+ const posts = await getPosts(id);
82
+
83
+ // GOOD: parallel — both fire simultaneously
84
+ const [user, posts] = await Promise.all([getUser(id), getPosts(id)]);
85
+ ```
86
+
87
+ ### 5. Intercepting Route Modal Pattern
88
+ ```
89
+ app/
90
+ photos/
91
+ page.tsx ← gallery page
92
+ [id]/
93
+ page.tsx ← full photo page (direct navigation)
94
+ @modal/
95
+ (.)photos/[id]/
96
+ page.tsx ← modal (shown when navigating from gallery)
97
+ layout.tsx ← renders both {children} and {modal}
98
+ ```
99
+
100
+ ### 6. Dynamic Metadata for SEO
101
+ ```tsx
102
+ // app/blog/[slug]/page.tsx
103
+ export async function generateMetadata({ params }: { params: { slug: string } }) {
104
+ const post = await getPost(params.slug);
105
+ return {
106
+ title: post.title,
107
+ description: post.excerpt,
108
+ openGraph: {
109
+ title: post.title,
110
+ images: [{ url: post.coverImage }],
111
+ },
112
+ };
113
+ }
114
+ ```
115
+
116
+ ### 7. Suspense Boundary for Slow Component
117
+ ```tsx
118
+ // app/dashboard/page.tsx
119
+ import { Suspense } from 'react';
120
+
121
+ export default function DashboardPage() {
122
+ return (
123
+ <div>
124
+ <StaticHeader />
125
+ <Suspense fallback={<ChartSkeleton />}>
126
+ <SlowAnalyticsChart /> {/* streams in separately */}
127
+ </Suspense>
128
+ </div>
129
+ );
130
+ }
131
+ ```
132
+
133
+ ### 8. Optimistic UI with useOptimistic (React 19 / Next.js 14+)
134
+ ```tsx
135
+ 'use client';
136
+ import { useOptimistic } from 'react';
137
+
138
+ function LikeButton({ post }) {
139
+ const [optimisticPost, addOptimisticLike] = useOptimistic(
140
+ post,
141
+ (state) => ({ ...state, likes: state.likes + 1 })
142
+ );
143
+ return (
144
+ <form action={async () => {
145
+ addOptimisticLike(null);
146
+ await likePost(post.id);
147
+ }}>
148
+ <button type="submit">Like ({optimisticPost.likes})</button>
149
+ </form>
150
+ );
151
+ }
152
+ ```
153
+
154
+ ### 9. next/image with Priority and Sizes
155
+ ```tsx
156
+ import Image from 'next/image';
157
+
158
+ // Hero image (LCP) — always use priority
159
+ <Image
160
+ src="/hero.jpg"
161
+ alt="Hero"
162
+ width={1200}
163
+ height={600}
164
+ priority
165
+ />
166
+
167
+ // Responsive fill image
168
+ <div className="relative h-64 w-full">
169
+ <Image
170
+ src={product.image}
171
+ alt={product.name}
172
+ fill
173
+ sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
174
+ className="object-cover"
175
+ />
176
+ </div>
177
+ ```
178
+
179
+ ### 10. URL State with nuqs
180
+ ```tsx
181
+ 'use client';
182
+ import { useQueryState } from 'nuqs';
183
+
184
+ function ProductFilter() {
185
+ const [category, setCategory] = useQueryState('category');
186
+ const [sort, setSort] = useQueryState('sort', { defaultValue: 'popular' });
187
+
188
+ return (
189
+ <div>
190
+ <select value={category ?? ''} onChange={e => setCategory(e.target.value)}>
191
+ <option value="">All</option>
192
+ <option value="shoes">Shoes</option>
193
+ </select>
194
+ </div>
195
+ );
196
+ }
197
+ // URL: /products?category=shoes&sort=popular — shareable, bookmarkable
198
+ ```
199
+
200
+ ## Best Practices by Category
201
+
202
+ ### Rendering
203
+ - Server Components by default — no `'use client'` unless you need browser APIs, event handlers, or hooks
204
+ - Push `'use client'` to leaf nodes — not layouts or high-level wrappers
205
+ - Use Suspense for progressive streaming of slow data sections
206
+ - Static generation (`cache: 'force-cache'`) where data does not change per request
207
+
208
+ ### Data Fetching
209
+ - Fetch in Server Components — no `useEffect` for initial data load
210
+ - `cache: 'force-cache'` for static data, `cache: 'no-store'` for always-fresh data
211
+ - Server Actions for all mutations (create, update, delete)
212
+ - `revalidatePath` or `revalidateTag` for ISR cache invalidation after mutations
213
+ - `Promise.all` for all parallel fetches — never sequential `await` for independent calls
214
+
215
+ ### Routing
216
+ - App Router as default for all new Next.js projects
217
+ - File-based routing: `page.tsx`, `layout.tsx`, `loading.tsx`, `error.tsx` per segment
218
+ - Parallel routes (`@slot`) for split views and modal overlays
219
+ - Intercepting routes for modal patterns without losing deep-link capability
220
+
221
+ ### Images
222
+ - `next/image` on every `<img>` — automatic format optimization and lazy loading
223
+ - `priority` prop on the LCP (largest contentful paint) image
224
+ - Explicit `width`/`height` or `fill` + `sizes` — prevents layout shift
225
+ - `next/font` for all custom fonts — zero layout shift, self-hosted automatically
226
+
227
+ ### Performance
228
+ - `next/dynamic` for client-heavy third-party components (maps, editors, charts)
229
+ - Bundle analyzer: `ANALYZE=true npm run build` with `@next/bundle-analyzer`
230
+ - Avoid large `'use client'` subtrees — keep server boundary as low as possible
231
+ - Cache expensive DB queries with `unstable_cache` or React `cache()`
232
+
233
+ ### Forms
234
+ - Server Actions as form `action` prop — no API route needed
235
+ - `useFormState` for server action response feedback
236
+ - `useFormStatus` for pending state on submit button
237
+ - Zod for schema validation in Server Actions before DB writes
238
+
239
+ ### Accessibility
240
+ - Semantic HTML in all Server Components
241
+ - `loading.tsx` skeleton should mirror the layout of real content — reduces layout shift
242
+ - Focus management after navigation — Next.js handles this automatically
243
+ - Error pages (`error.tsx`) must have a recovery action (retry button)
244
+
245
+ ### State
246
+ - URL state (`nuqs`) for filters, pagination, search — shareable and bookmarkable
247
+ - `useState`/`useReducer` for ephemeral UI state (modals, toggles)
248
+ - TanStack Query for client-side caching of server data after initial load
249
+ - Avoid `localStorage` for critical state — use cookies or DB for SSR compatibility
250
+
251
+ ## Common Anti-Patterns
252
+
253
+ 1. `'use client'` on a layout or high-level wrapper — makes the entire subtree client-side, losing all Server Component benefits
254
+ 2. `useEffect` for data that could be fetched in a Server Component — unnecessary client waterfall
255
+ 3. Fetching in client components without caching — re-fetches on every mount
256
+ 4. Missing `loading.tsx` — no streaming feedback during server data loading
257
+ 5. `<img>` instead of `next/image` — no optimization, causes layout shift
258
+ 6. Sequential `await` for independent data fetches — use `Promise.all`
259
+ 7. No `generateMetadata` on dynamic pages — poor SEO, missing OG tags
260
+ 8. Putting secrets in client components — environment variables without `NEXT_PUBLIC_` are server-only
261
+ 9. Mutating data without `revalidatePath` — stale cache shown to users after update
262
+ 10. Not using `notFound()` — returning null causes blank pages instead of proper 404
263
+
264
+ ## Performance Checklist
265
+
266
+ - [ ] Server Components used for all non-interactive UI
267
+ - [ ] `next/image` on every image, with `priority` on LCP image
268
+ - [ ] `next/font` for all custom fonts — no `@font-face` in CSS
269
+ - [ ] `loading.tsx` on every dynamic route segment
270
+ - [ ] `Promise.all` for all parallel data fetches in Server Components
271
+ - [ ] Bundle analyzer run: `ANALYZE=true npm run build`
272
+ - [ ] Suspense boundaries around individually-slow components
273
+ - [ ] `generateStaticParams` for known dynamic routes (static generation)
274
+ - [ ] No large third-party libraries in Server Components (they ship to client via `'use client'` boundary)
275
+ - [ ] `revalidateTag` strategy defined for all cached data
@@ -0,0 +1,384 @@
1
+ # Nuxt UI (nuxt/ui) UI/UX Guidelines
2
+
3
+ ## When to read this
4
+ Read this file when building UI with the `@nuxt/ui` component library in a Nuxt 3 project. Covers component usage, theming, form patterns, toast notifications, modals, and accessibility built into the library.
5
+
6
+ ## Setup
7
+ ```bash
8
+ npx nuxi module add ui
9
+ # Automatically installs and configures:
10
+ # - Tailwind CSS
11
+ # - Headless UI (accessibility primitives)
12
+ # - Heroicons (default icon set)
13
+ # - Color mode support
14
+ # - All components are auto-imported
15
+ ```
16
+
17
+ ## Core Components Reference
18
+
19
+ | Component | Selector | Best for |
20
+ |---|---|---|
21
+ | UButton | `<UButton>` | Actions — color, variant, icon, size, loading props |
22
+ | UInput | `<UInput>` | Text fields — placeholder, icon, trailing, disabled |
23
+ | UTextarea | `<UTextarea>` | Multi-line text input |
24
+ | USelect | `<USelect>` | Dropdown select with options array |
25
+ | UCard | `<UCard>` | Content containers with header/footer slots |
26
+ | UModal | `<UModal>` | Dialogs — v-model for open/close, accessible by default |
27
+ | USlideover | `<USlideover>` | Side panels / drawers |
28
+ | UDropdown | `<UDropdown>` | Menus — :items array prop |
29
+ | UTable | `<UTable>` | Data tables — :rows, :columns, sorting, pagination |
30
+ | UBadge | `<UBadge>` | Status indicators — color, variant, size |
31
+ | UAlert | `<UAlert>` | Feedback messages — icon, color, description |
32
+ | UCommandPalette | `<UCommandPalette>` | Search / command palette with built-in filtering |
33
+ | UNotifications | `<UNotifications>` | Toast notification stack — pair with useToast() |
34
+ | UFormGroup | `<UFormGroup>` | Form field wrapper with label, hint, and error |
35
+ | UForm | `<UForm>` | Form with schema validation (Zod or Yup) |
36
+ | UTabs | `<UTabs>` | Tab navigation — :items array |
37
+ | UAccordion | `<UAccordion>` | Collapsible sections |
38
+ | UAvatar | `<UAvatar>` | User avatars with fallback initials |
39
+ | UProgress | `<UProgress>` | Progress bar with value and animation |
40
+ | UTooltip | `<UTooltip>` | Hover tooltips with text prop |
41
+ | UPopover | `<UPopover>` | Click-triggered overlay panels |
42
+ | UPagination | `<UPagination>` | Page navigation — v-model, :total, :page-count |
43
+ | URange | `<URange>` | Slider input |
44
+ | UToggle | `<UToggle>` | Boolean on/off switch |
45
+ | UCheckbox | `<UCheckbox>` | Checkbox with label |
46
+ | URadio | `<URadio>` | Radio button |
47
+
48
+ ## Top UX Patterns
49
+
50
+ ### 1. Button Variants and States
51
+ ```vue
52
+ <!-- Primary action -->
53
+ <UButton color="primary" variant="solid" size="md" @click="save">
54
+ Save changes
55
+ </UButton>
56
+
57
+ <!-- With icon and loading state -->
58
+ <UButton
59
+ color="primary"
60
+ variant="solid"
61
+ icon="i-heroicons-check"
62
+ :loading="saving"
63
+ :disabled="saving"
64
+ @click="save"
65
+ >
66
+ Save changes
67
+ </UButton>
68
+
69
+ <!-- Destructive action -->
70
+ <UButton color="red" variant="soft" icon="i-heroicons-trash" @click="remove">
71
+ Delete
72
+ </UButton>
73
+
74
+ <!-- Ghost / subtle -->
75
+ <UButton color="gray" variant="ghost" icon="i-heroicons-x-mark" @click="cancel">
76
+ Cancel
77
+ </UButton>
78
+ ```
79
+
80
+ ### 2. Form with Schema Validation
81
+ ```vue
82
+ <script setup lang="ts">
83
+ import { z } from 'zod';
84
+ import type { FormSubmitEvent } from '#ui/types';
85
+
86
+ const schema = z.object({
87
+ email: z.string().email('Invalid email'),
88
+ password: z.string().min(8, 'At least 8 characters'),
89
+ });
90
+
91
+ type Schema = z.output<typeof schema>;
92
+
93
+ const state = reactive({ email: '', password: '' });
94
+
95
+ async function onSubmit(event: FormSubmitEvent<Schema>) {
96
+ await login(event.data);
97
+ }
98
+ </script>
99
+
100
+ <template>
101
+ <UForm :schema="schema" :state="state" @submit="onSubmit" class="space-y-4">
102
+ <UFormGroup label="Email" name="email" required>
103
+ <UInput v-model="state.email" type="email" placeholder="you@example.com" />
104
+ </UFormGroup>
105
+
106
+ <UFormGroup label="Password" name="password" required>
107
+ <UInput v-model="state.password" type="password" />
108
+ </UFormGroup>
109
+
110
+ <UButton type="submit" color="primary" block>Sign in</UButton>
111
+ </UForm>
112
+ </template>
113
+ ```
114
+
115
+ ### 3. Toast Notifications
116
+ ```typescript
117
+ const toast = useToast();
118
+
119
+ // Success
120
+ toast.add({
121
+ title: 'Saved!',
122
+ description: 'Your changes have been saved.',
123
+ icon: 'i-heroicons-check-circle',
124
+ color: 'green',
125
+ });
126
+
127
+ // Error
128
+ toast.add({
129
+ title: 'Error',
130
+ description: 'Failed to save. Please try again.',
131
+ icon: 'i-heroicons-x-circle',
132
+ color: 'red',
133
+ timeout: 5000,
134
+ });
135
+
136
+ // Info with action
137
+ toast.add({
138
+ title: 'New version available',
139
+ actions: [{ label: 'Refresh', click: () => window.location.reload() }],
140
+ });
141
+ ```
142
+
143
+ ```vue
144
+ <!-- Place once in app.vue -->
145
+ <template>
146
+ <div>
147
+ <NuxtPage />
148
+ <UNotifications />
149
+ </div>
150
+ </template>
151
+ ```
152
+
153
+ ### 4. Modal Dialog
154
+ ```vue
155
+ <script setup lang="ts">
156
+ const isOpen = ref(false);
157
+ </script>
158
+
159
+ <template>
160
+ <UButton @click="isOpen = true">Open dialog</UButton>
161
+
162
+ <UModal v-model="isOpen">
163
+ <UCard :ui="{ ring: '', divide: 'divide-y divide-gray-100 dark:divide-gray-800' }">
164
+ <template #header>
165
+ <div class="flex items-center justify-between">
166
+ <h3 class="text-base font-semibold">Edit item</h3>
167
+ <UButton color="gray" variant="ghost" icon="i-heroicons-x-mark" @click="isOpen = false" />
168
+ </div>
169
+ </template>
170
+
171
+ <p>Modal content goes here.</p>
172
+
173
+ <template #footer>
174
+ <div class="flex justify-end gap-3">
175
+ <UButton color="gray" variant="ghost" @click="isOpen = false">Cancel</UButton>
176
+ <UButton color="primary" @click="save">Save</UButton>
177
+ </div>
178
+ </template>
179
+ </UCard>
180
+ </UModal>
181
+ </template>
182
+ ```
183
+
184
+ ### 5. Data Table with Columns
185
+ ```vue
186
+ <script setup lang="ts">
187
+ const columns = [
188
+ { key: 'name', label: 'Name', sortable: true },
189
+ { key: 'email', label: 'Email' },
190
+ { key: 'role', label: 'Role' },
191
+ { key: 'actions', label: '' },
192
+ ];
193
+
194
+ const { data: users } = await useFetch('/api/users');
195
+ </script>
196
+
197
+ <template>
198
+ <UTable
199
+ :rows="users"
200
+ :columns="columns"
201
+ :loading="pending"
202
+ :empty-state="{ icon: 'i-heroicons-users', label: 'No users found.' }"
203
+ >
204
+ <template #actions-data="{ row }">
205
+ <UDropdown :items="[[{ label: 'Edit', click: () => edit(row) }, { label: 'Delete', click: () => remove(row) }]]">
206
+ <UButton icon="i-heroicons-ellipsis-horizontal" color="gray" variant="ghost" />
207
+ </UDropdown>
208
+ </template>
209
+ </UTable>
210
+ </template>
211
+ ```
212
+
213
+ ### 6. Command Palette
214
+ ```vue
215
+ <script setup lang="ts">
216
+ const isOpen = ref(false);
217
+ const { metaSymbol } = useShortcuts();
218
+
219
+ defineShortcuts({
220
+ meta_k: { usingInput: false, handler: () => { isOpen.value = !isOpen.value; } },
221
+ });
222
+
223
+ const groups = [
224
+ {
225
+ key: 'pages',
226
+ label: 'Pages',
227
+ commands: [
228
+ { id: 'home', label: 'Home', icon: 'i-heroicons-home', to: '/' },
229
+ { id: 'dashboard', label: 'Dashboard', icon: 'i-heroicons-squares-2x2', to: '/dashboard' },
230
+ ],
231
+ },
232
+ ];
233
+ </script>
234
+
235
+ <template>
236
+ <UModal v-model="isOpen">
237
+ <UCommandPalette :groups="groups" @update:model-value="isOpen = false" />
238
+ </UModal>
239
+ </template>
240
+ ```
241
+
242
+ ### 7. Slideover Side Panel
243
+ ```vue
244
+ <template>
245
+ <USlideover v-model="isOpen" side="right">
246
+ <UCard class="h-full rounded-none">
247
+ <template #header>
248
+ <div class="flex items-center justify-between">
249
+ <h3>Filter options</h3>
250
+ <UButton icon="i-heroicons-x-mark" color="gray" variant="ghost" @click="isOpen = false" />
251
+ </div>
252
+ </template>
253
+ <FilterForm />
254
+ </UCard>
255
+ </USlideover>
256
+ </template>
257
+ ```
258
+
259
+ ### 8. Dropdown Menu
260
+ ```vue
261
+ <script setup lang="ts">
262
+ const items = [
263
+ [
264
+ { label: 'Profile', icon: 'i-heroicons-user', to: '/profile' },
265
+ { label: 'Settings', icon: 'i-heroicons-cog-6-tooth', to: '/settings' },
266
+ ],
267
+ [
268
+ { label: 'Sign out', icon: 'i-heroicons-arrow-right-on-rectangle', click: signOut },
269
+ ],
270
+ ];
271
+ </script>
272
+
273
+ <template>
274
+ <UDropdown :items="items">
275
+ <UAvatar :src="user.avatar" :alt="user.name" />
276
+ </UDropdown>
277
+ </template>
278
+ ```
279
+
280
+ ## Theming (app.config.ts)
281
+
282
+ ```typescript
283
+ // app.config.ts
284
+ export default defineAppConfig({
285
+ ui: {
286
+ primary: 'indigo', // Primary color — any Tailwind color
287
+ gray: 'slate', // Gray scale — slate, cool, zinc, neutral, stone
288
+
289
+ // Component-level defaults
290
+ button: {
291
+ default: {
292
+ size: 'md',
293
+ color: 'primary',
294
+ variant: 'solid',
295
+ },
296
+ },
297
+
298
+ input: {
299
+ default: {
300
+ size: 'md',
301
+ },
302
+ },
303
+
304
+ // Custom variant example
305
+ badge: {
306
+ variant: {
307
+ custom: 'bg-{color}-100 text-{color}-700 ring-1 ring-{color}-300',
308
+ },
309
+ },
310
+ },
311
+ });
312
+ ```
313
+
314
+ ## Icons
315
+
316
+ Nuxt UI uses Heroicons by default. Icons are accessed via CSS class names:
317
+
318
+ ```vue
319
+ <!-- Outline (default) -->
320
+ <UIcon name="i-heroicons-home" class="w-5 h-5" />
321
+
322
+ <!-- Solid variant -->
323
+ <UIcon name="i-heroicons-home-solid" />
324
+
325
+ <!-- In components -->
326
+ <UButton icon="i-heroicons-plus" />
327
+ <UInput icon="i-heroicons-magnifying-glass" />
328
+ ```
329
+
330
+ Install additional icon sets:
331
+ ```bash
332
+ npm install @iconify-json/lucide # Lucide icons — i-lucide-*
333
+ npm install @iconify-json/ph # Phosphor icons — i-ph-*
334
+ npm install @iconify-json/tabler # Tabler icons — i-tabler-*
335
+ ```
336
+
337
+ ## Best Practices by Category
338
+
339
+ ### Components
340
+ - Always use `<UFormGroup>` around form inputs — it wires up the label/input association, hint text, and error display automatically
341
+ - Use `<UModal>` and `<USlideover>` instead of building custom overlays — they handle focus trap, Escape key, scroll lock, and ARIA out of the box
342
+ - Use the `color` prop with theme values (`primary`, `gray`, `red`, `green`) — never hardcode hex colors
343
+ - Use `variant` prop to convey hierarchy: `solid` for primary, `soft` or `outline` for secondary, `ghost` for tertiary
344
+
345
+ ### Forms
346
+ - `<UForm>` with `:schema` (Zod) handles validation automatically on submit and on change
347
+ - `<UFormGroup name="fieldName">` matches the Zod schema key — errors display automatically
348
+ - Use `:loading` on submit button — never disable the button without visual feedback
349
+
350
+ ### Notifications
351
+ - `useToast()` is the only notification system — do not build a custom one
352
+ - Place `<UNotifications />` once in `app.vue`
353
+ - Use `color` prop to convey meaning: `green` for success, `red` for error, `yellow` for warning
354
+
355
+ ### Accessibility
356
+ - All Nuxt UI components are built on Headless UI — ARIA roles, keyboard navigation, and focus management are handled automatically
357
+ - Do not suppress the built-in focus ring — it is essential for keyboard users
358
+ - Use `aria-label` on icon-only buttons: `<UButton icon="i-heroicons-x-mark" aria-label="Close" />`
359
+
360
+ ### State
361
+ - `v-model` on `<UModal>` and `<USlideover>` for open/close state
362
+ - `useToast()` composable — auto-imported, no import needed
363
+ - `useShortcuts()` for keyboard shortcuts that interact with UI
364
+
365
+ ## Common Anti-Patterns
366
+
367
+ 1. Not using `<UFormGroup>` — input loses label association, hint text, and auto error display
368
+ 2. Building a custom modal — `<UModal>` and `<USlideover>` handle all accessibility automatically (focus trap, Escape key, scroll lock)
369
+ 3. Hardcoded colors in `class` or `style` — use `color` prop so theming works correctly
370
+ 4. Building a custom toast/notification system — `useToast()` + `<UNotifications />` is already provided
371
+ 5. Importing components manually — all Nuxt UI components are auto-imported
372
+ 6. Not passing `aria-label` on icon-only buttons — screen readers cannot identify the action
373
+ 7. Using `disabled` on form submit without `:loading` — users see no feedback that something is happening
374
+ 8. Nested `<UCard>` inside `<UModal>` without removing the ring — creates double border; use `:ui="{ ring: '' }"`
375
+
376
+ ## Performance Checklist
377
+
378
+ - [ ] `<UTable>` with `:rows` for all data tables — has built-in empty state and loading state
379
+ - [ ] `<UCommandPalette>` for app-wide search — built-in filtering and keyboard navigation
380
+ - [ ] `<UModal>` content only renders when open — no hidden DOM overhead when closed
381
+ - [ ] `<UNotifications />` placed once at app root — not duplicated per page
382
+ - [ ] Icon sets installed only as needed — each `@iconify-json/*` adds to bundle
383
+ - [ ] Theme configured in `app.config.ts` — avoids runtime style computation
384
+ - [ ] `<UButton :loading="true">` used during async operations — prevents double-submit