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### Replace instead of merge209210Classes from the `ui` prop, the `class` prop, and global config are merged onto the component defaults. To replace a slot's defaults entirely instead, set it to a function in the `ui` prop or global config. It receives the resolved default classes as its argument, so you can reuse part of them.211212```vue213<UButton :ui="{ label: () => 'text-base font-bold' }" />214```215216```ts217// app.config.ts, applies to every instance218export default defineAppConfig({219ui: {220button: {221slots: {222label: () => 'text-base font-bold'223}224}225}226})227```228229### Theme component230231Override theme for a section of the component tree without affecting the rest of the app. Renders no DOM element — uses `provide`/`inject`:232233```vue234<UTheme :ui="{ button: { slots: { base: 'rounded-full' } } }">235<UButton label="Rounded" />236<UButton label="Also rounded" />237</UTheme>238```239240### Global `defaultVariants`241242Override default `size` and `color` for **all** components at once:243244```ts245// nuxt.config.ts246export default defineNuxtConfig({247ui: {248theme: {249defaultVariants: {250size: 'lg',251color: 'neutral'252}253}254}255})256```257258### `theme.transitions`259260Controls whether interactive components get `transition-colors`. Enabled by default.261262```ts263// nuxt.config.ts — disable transitions264export default defineNuxtConfig({265ui: {266theme: {267transitions: false268}269}270})271```272273### `theme.prefix`274275When using Tailwind CSS with a prefix, configure the same prefix in Nuxt UI so component classes match:276277```ts278// nuxt.config.ts279export default defineNuxtConfig({280ui: {281theme: {282prefix: 'tw'283}284}285})286```287288```css289/* app/assets/css/main.css */290@import "tailwindcss" prefix(tw);291@import "@nuxt/ui";292```293294### Tree-shaking with `experimental.componentDetection`295296Enable automatic component detection to only generate CSS for components you actually use:297298```ts299// nuxt.config.ts300export default defineNuxtConfig({301ui: {302experimental: {303componentDetection: true304}305}306})307```308309For dynamic components (e.g., `<component :is="...">`), pass an array of component names to guarantee they're included:310311```ts312componentDetection: ['Modal', 'Dropdown', 'Popover']313```314315## CSS `@theme` customization316317Customize Tailwind design tokens in `main.css`:318319### Fonts320321```css322@theme {323--font-sans: 'Public Sans', system-ui, sans-serif;324--font-mono: 'JetBrains Mono', monospace;325}326```327328In Nuxt, fonts defined here are automatically loaded by `@nuxt/fonts`.329330### Breakpoints331332```css333@theme {334--breakpoint-3xl: 1920px;335}336```337338## CSS variables339340Nuxt UI exposes CSS variables you can override in `main.css`:341342```css343:root {344--ui-radius: 0.25rem;345--ui-container: 80rem;346--ui-header-height: 4rem;347}348```349350### Color shade overrides351352Each semantic color defaults to shade 500 in light mode, 400 in dark mode. Override per-mode:353354```css355:root {356--ui-primary: var(--ui-color-primary-700);357}358.dark {359--ui-primary: var(--ui-color-primary-200);360}361```362363You 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).364365### Black/white as primary366367`black` and `white` have no shades, so they can't be used in config. Set them directly:368369```css370:root {371--ui-primary: black;372}373.dark {374--ui-primary: white;375}376```377