GuideBest Practicesshadcn-vuecomparisondesign-tokenscss-variablesnuxt-ui

Nuxt UI vs shadcn-vue: How Theming Compares

Compare how Nuxt UI v4 and shadcn-vue handle colors, dark mode, radius, and component customization, and when each approach fits your Vue or Nuxt project.

Nuxt UI and shadcn-vue are both built on Reka UI and styled with Tailwind CSS, so their components behave alike. Where they differ is ownership: Nuxt UI is a library you install and configure, while shadcn-vue copies component source into your project for you to edit. That choice shapes how theming works in each.

At a Glance

TopicNuxt UI v4shadcn-vue
Where components livenode_modules, updated with the packageYour repo (components/ui), updated by hand
Color modelSemantic roles mapped to full 50–950 palettesOne CSS variable per role, paired with a foreground
Built-in rolesprimary, secondary, success, info, warning, error, neutralprimary, secondary, muted, accent, destructive, plus surfaces
Where colors are setapp.config.ts (palette names) + CSS variablesCSS variables in your main stylesheet
Dark modeToken defaults per mode, override under .darkEvery variable redefined under .dark
Radius--ui-radius, scale multiplies it--radius, smaller steps subtract from it
Per-component stylingapp.config.ts slots, ui prop, classEdit the component file

Colors

Nuxt UI assigns each semantic role a whole Tailwind palette:

export default defineAppConfig({
  ui: {
    colors: {
      primary: "indigo",
      neutral: "zinc",
    },
  },
});

Components then pick shades from that palette for each state: solid fills, soft backgrounds, hover, and focus rings. You get consistent variants for free, and you can shift the main shade (--ui-primary) per mode.

shadcn-vue defines one value per role, each paired with a text color that sits on it:

/* shadcn-vue, zinc base color */
:root {
  --primary: oklch(0.21 0.006 285.885);
  --primary-foreground: oklch(0.985 0 0);
  --muted: oklch(0.967 0.001 286.375);
  --muted-foreground: oklch(0.552 0.016 285.938);
}

That gives exact control over every pairing, but you choose each value yourself and there's no ready-made success, warning, or info role.

Dark Mode

Nuxt UI ships light and dark defaults for every token (--ui-bg, --ui-text-muted, --ui-border, and so on), so switching palettes gives a working dark mode immediately. You override only what you want to change under .dark.

shadcn-vue defines every variable a second time under .dark, and you tune both sets. It's more to maintain, and just as flexible. See Dark Mode Theming with Nuxt UI for the Nuxt UI side.

Radius

Both use one base variable. Nuxt UI multiplies --ui-radius (buttons use 1.5x, cards 2x), so the scale grows proportionally. shadcn-vue treats --radius as the large step and subtracts fixed amounts for smaller ones (calc(var(--radius) - 4px) for small). Details in Change the Border Radius Everywhere in Nuxt UI.

Customizing Components

In shadcn-vue you open the copied .vue file and change its classes, since the component is yours. Upstream fixes don't arrive automatically, though.

In Nuxt UI you override the component's theme from app.config.ts and keep receiving updates:

export default defineAppConfig({
  ui: {
    button: {
      slots: { base: "rounded-full" },
    },
  },
});

Which Fits Your Project

  • Choose Nuxt UI for a large component set (125+) that follows one theme config, full palettes behind every role, and upgrades through your package manager. It fits Nuxt apps, dashboards, and docs sites that value speed and consistency.
  • Choose shadcn-vue if you want to own and fork every component, prefer hand-tuned color pairs, or are building a design system that will diverge heavily from any default.

Get the shadcn Look in Nuxt UI

Like the shadcn aesthetic but want Nuxt UI's component library? The shadcn theme recreates it with zinc neutrals, a near-black primary in light mode and near-white in dark mode, and Geist. Load it in the Theme Builder and adjust from there.

Next Steps