Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Guidance for building UIs with Nuxt UI, the official Tailwind-based component library for Nuxt.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/guidelines/design-system.md
1# Design System23## Semantic colors45Nuxt UI uses 7 semantic colors. Never use raw Tailwind palette colors in components — always use these semantic names.67| Color | Default | When to use |8|---|---|---|9| `primary` | green | CTAs, active states, brand accent, links |10| `secondary` | blue | Secondary actions, complementary highlights |11| `success` | green | Success messages, confirmations, positive states |12| `info` | blue | Informational alerts, tips, neutral highlights |13| `warning` | yellow | Warnings, caution states, pending actions |14| `error` | red | Errors, destructive actions, validation failures |15| `neutral` | slate | Text, borders, backgrounds, disabled states, chrome |1617### Choosing colors for components1819- **Primary action** on a page (submit, save, confirm) → `color="primary"`20- **Secondary actions** (cancel, back, alternative) → `color="neutral"` with `variant="outline"` or `"ghost"`21- **Destructive actions** (delete, remove) → `color="error"`22- **Status indicators** → match the semantic meaning: `success`, `warning`, `error`, `info`23- **Navigation and chrome** → `color="neutral"`2425### Configuring colors2627```ts28// Nuxt — app.config.ts29export default defineAppConfig({30ui: {31colors: {32primary: 'indigo',33secondary: 'violet',34success: 'emerald',35error: 'rose',36neutral: 'zinc'37}38}39})40```4142```ts43// Vue — vite.config.ts44ui({45ui: {46colors: { primary: 'indigo', secondary: 'violet', neutral: 'zinc' }47}48})49```5051Only colors that exist in your theme work — either Tailwind's defaults or custom colors defined with `@theme`.5253Available color palettes:54- **Standard Tailwind**: red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose55- **Neutral palettes** (for `neutral` key — pick one that matches the aesthetic):56- `slate` — cool blue-gray, professional (default)57- `gray` — true neutral, clean58- `zinc` — slightly cool, modern, techy59- `neutral` — perfectly balanced60- `stone` — warm gray, earthy61- `taupe` — warm brown-gray, sophisticated62- `mauve` — purple-tinted gray, elegant63- `mist` — soft blue-gray, airy64- `olive` — green-tinted gray, natural6566### Adding custom brand colors67681. Define all 11 shades in CSS:6970```css71/* app/assets/css/main.css */72@theme static {73--color-brand-50: #fef2f2;74--color-brand-100: #fee2e2;75--color-brand-200: #fecaca;76--color-brand-300: #fca5a5;77--color-brand-400: #f87171;78--color-brand-500: #ef4444;79--color-brand-600: #dc2626;80--color-brand-700: #b91c1c;81--color-brand-800: #991b1b;82--color-brand-900: #7f1d1d;83--color-brand-950: #450a0a;84}85```86872. Assign it: `ui: { colors: { primary: 'brand' } }`8889### Extending with new semantic color names9091To add a color beyond the 7 defaults (e.g., `tertiary`), register it in `theme.colors`:9293```ts94// nuxt.config.ts95export default defineNuxtConfig({96ui: {97theme: {98colors: ['primary', 'secondary', 'tertiary', 'info', 'success', 'warning', 'error']99}100}101})102```103104## Semantic utility classes105106Use these everywhere instead of raw palette colors:107108### Text109- `text-default` — primary body text110- `text-muted` — secondary text (descriptions, hints)111- `text-toned` — medium-emphasis text (between muted and default)112- `text-dimmed` — tertiary text (placeholders, disabled)113- `text-highlighted` — emphasized text (headings, important labels)114- `text-inverted` — text on inverted backgrounds (pair with `bg-inverted`)115116### Backgrounds117- `bg-default` — page background118- `bg-muted` — subtle backgrounds (hover states, alternating rows)119- `bg-elevated` — raised surfaces (cards, dropdowns)120- `bg-accented` — accent backgrounds (active states, selected items)121- `bg-inverted` — inverse background (dark on light, light on dark)122123### Borders124- `border-default` — standard borders125- `border-muted` — subtle borders (dividers, separators)126- `border-accented` — accent borders (active states)127- `border-inverted` — inverse borders128129## Variants130131Most components accept a `variant` prop. Choose based on visual weight:132133| Variant | Weight | When to use |134|---|---|---|135| `solid` | Highest | Primary actions, main CTAs |136| `outline` | Medium | Secondary actions, form fields |137| `soft` | Medium-low | Tags, badges, subtle buttons |138| `subtle` | Low | Background highlights, less prominent actions |139| `ghost` | Lowest | Inline actions, icon buttons, navigation items |140| `link` | Lowest | Text-only links inside content |141142### Rules143144- **One solid primary button per view** — everything else should be lower weight145- **Destructive buttons** use `color="error"` but not necessarily `variant="solid"` — use `variant="soft"` or `"outline"` unless it's the primary action on a confirmation dialog146- **Button groups** should use consistent variants — don't mix `solid` and `outline` siblings147148## Customizing components149150### `ui` prop151152Override theme **slots** on a single instance — wins over global config and variants.153154```vue155<UButton :ui="{ base: 'font-bold', trailingIcon: 'size-3 rotate-90' }" />156<UCard :ui="{ header: 'bg-muted', body: 'p-8' }" />157```158159Rules for `ui` overrides:160- **Prefer `defaultVariants`** over slot class overrides when possible (e.g., changing default button variant/size).161- **Don't duplicate default classes** — check the generated theme file first to see what's already there.162- Border radius defaults come from `--ui-radius`, but you can override with `rounded-*` classes in `ui` or `class` when you need a specific radius on a component.163164### `class` prop165166Override the **root** (or `base`) slot only — simpler than `ui` for single-slot changes.167168```vue169<UButton class="font-bold" />170```171172### Finding slot names173174Read the generated theme file for any component:175- **Nuxt**: `.nuxt/ui/<component>.ts`176- **Vue**: `node_modules/.nuxt-ui/ui/<component>.ts`177178These files show every available slot name, variant combination, and default class.179180### Global config181182Override `slots`, `variants`, `compoundVariants`, and `defaultVariants` globally in `app.config.ts` (Nuxt) or `vite.config.ts` (Vue):183184```ts185// Nuxt — app.config.ts186export default defineAppConfig({187ui: {188button: {189slots: {190base: 'font-bold'191},192compoundVariants: [{193color: 'neutral',194variant: 'outline',195class: 'ring-default hover:bg-accented'196}],197defaultVariants: {198color: 'neutral',199variant: 'outline'200}201}202}203})204```205206Tailwind Variants uses `tailwind-merge` under the hood — conflicting classes are resolved automatically.207208### `UTheme` (scoped overrides)209210Override theme for a section of the component tree without affecting the rest of the app. Renders no DOM element — uses `provide`/`inject`:211212```vue213<UTheme :ui="{ button: { slots: { base: 'rounded-full' } } }">214<UButton label="Rounded" />215<UButton label="Also rounded" />216</UTheme>217```218219### Global `defaultVariants`220221Override default `size` and `color` for **all** components at once:222223```ts224// nuxt.config.ts225export default defineNuxtConfig({226ui: {227theme: {228defaultVariants: {229size: 'lg',230color: 'neutral'231}232}233}234})235```236237### `theme.transitions`238239Controls whether interactive components get `transition-colors`. Enabled by default.240241```ts242// nuxt.config.ts — disable transitions243export default defineNuxtConfig({244ui: {245theme: {246transitions: false247}248}249})250```251252### `theme.prefix`253254When using Tailwind CSS with a prefix, configure the same prefix in Nuxt UI so component classes match:255256```ts257// nuxt.config.ts258export default defineNuxtConfig({259ui: {260theme: {261prefix: 'tw'262}263}264})265```266267```css268/* app/assets/css/main.css */269@import "tailwindcss" prefix(tw);270@import "@nuxt/ui";271```272273### Tree-shaking with `experimental.componentDetection`274275Enable automatic component detection to only generate CSS for components you actually use:276277```ts278// nuxt.config.ts279export default defineNuxtConfig({280ui: {281experimental: {282componentDetection: true283}284}285})286```287288For dynamic components (e.g., `<component :is="...">`), pass an array of component names to guarantee they're included:289290```ts291componentDetection: ['Modal', 'Dropdown', 'Popover']292```293294## CSS `@theme` customization295296Customize Tailwind design tokens in `main.css`:297298### Fonts299300```css301@theme {302--font-sans: 'Public Sans', system-ui, sans-serif;303--font-mono: 'JetBrains Mono', monospace;304}305```306307In Nuxt, fonts defined here are automatically loaded by `@nuxt/fonts`.308309### Breakpoints310311```css312@theme {313--breakpoint-3xl: 1920px;314}315```316317## CSS variables318319Nuxt UI exposes CSS variables you can override in `main.css`:320321```css322:root {323--ui-radius: 0.25rem;324--ui-container: 80rem;325--ui-header-height: 4rem;326}327```328329### Color shade overrides330331Each semantic color defaults to shade 500 in light mode, 400 in dark mode. Override per-mode:332333```css334:root {335--ui-primary: var(--ui-color-primary-700);336}337.dark {338--ui-primary: var(--ui-color-primary-200);339}340```341342You can use `var(--ui-color-<name>-<shade>)` to reference shades from the active palette (e.g., `var(--ui-color-neutral-800)` maps to whichever neutral palette is configured).343344### Black/white as primary345346`black` and `white` have no shades, so they can't be used in config. Set them directly:347348```css349:root {350--ui-primary: black;351}352.dark {353--ui-primary: white;354}355```356