BlogPlaygroundOne

UnoCSS with Vuetify preset

Generate Vuetify’s built-in utility classes on demand with unocss-preset-vuetify, maintained by the Vuetify team.

No class-naming convention change required — use the same Vuetify class names you already know, generated on demand instead of shipped in full.

Edit this page
Copy Page as Markdown

# generate working project for reference
npx @vuetify/cli@latest init --type=vuetify --css=unocss-vuetify

Establish CSS layer order

Create a layers.css file that declares the cascade layers in order. uno goes above component styles but below vuetify-final, where Vuetify keeps its transitions:

@layer vuetify-core;
@layer vuetify-components;
@layer vuetify-overrides;
@layer vuetify-utilities;
@layer uno;
@layer vuetify-final;

This file must be loaded before any other styles. In a Vite project, save it as src/styles/layers.css and import it at the top of src/plugins/vuetify.ts, before vuetify/styles.

Setup dependencies

Vite

Import the layers file at the top of src/plugins/vuetify.ts, before vuetify/styles:

src/plugins/vuetify.ts
import '../styles/layers.css'
import 'vuetify/styles'
// ...

Install UnoCSS and the Vuetify preset:

pnpm add -D unocss unocss-preset-vuetify

Register the UnoCSS Vite plugin in vite.config.ts and create uno.config.ts:

vite.config.ts
import UnoCSS from 'unocss/vite'

export default defineConfig({
  plugins: [
    UnoCSS(),
    // ...
  ],
})
uno.config.ts
import { defineConfig } from 'unocss'
import { presetVuetify } from 'unocss-preset-vuetify'

export default defineConfig({
  presets: [
    presetVuetify({
      typography: 'md3',     // accepts 'md2' or custom object
      elevation: 'md3',      // accepts 'md2' or custom object
      font: {                // your custom fonts
        heading: 'K2D, sans-serif',
        body: '"Work Sans", sans-serif',
      },
    }),
  ],
  outputToCssLayers: {
    cssLayerName: (layer) => layer === 'properties' ? null : `uno.${layer}`,
  },
})

Add the UnoCSS virtual import to your entry point:

src/main.ts
import 'virtual:uno.css'

Nuxt

pnpm add -D unocss unocss-preset-vuetify @unocss/nuxt

Register the module in nuxt.config.ts. The css array controls load order — layers.css must come first, followed by vuetify/styles. Set disableVuetifyStyles: true — otherwise the module injects styles automatically and the order above is ignored:

nuxt.config.ts
import { presetVuetify } from 'unocss-preset-vuetify'

export default defineNuxtConfig({
  modules: [
    '@unocss/nuxt',
    'vuetify-nuxt-module',
    // ...
  ],

  css: [
    'assets/styles/layers.css',
    'vuetify/styles',
  ],

  vuetify: {
    moduleOptions: {
      disableVuetifyStyles: true,
      styles: { configFile: 'assets/styles/settings.scss' },
    },
    vuetifyOptions: {
      theme: {
        defaultTheme: 'dark', // 'system' requires ssr: false
      },
    },
  },

  unocss: {
    presets: [
      presetVuetify(),
    ],
    outputToCssLayers: {
      cssLayerName: (layer) => layer === 'properties' ? null : `uno.${layer}`,
    },
  },
})

Disable Vuetify’s built-in utilities

Turn off Vuetify’s built-in utility classes and the Material color palette so UnoCSS handles them on demand instead.

settings.scss
@use 'vuetify/settings' with (
  $color-pack: false,
  $utilities: false,
);

How on-demand generation works

UnoCSS scans your source files statically, looking for class name strings. A class like elevation-4 in class="elevation-4" gets picked up and its CSS is generated. The problem arises with props like elevation, rounded and border: when you write <v-card elevation="4">, Vuetify’s component logic converts the prop value into the class elevation-4 internally — the string elevation-4 never appears literally in your source, so UnoCSS won’t generate it.

The safelist option solves this: it specifies classes (or patterns) that UnoCSS should always generate regardless of whether they appear in scanned files.

Safelist prop-driven classes

Add safelist entries for convenience props (e.g. elevation and rounded) that just add CSS classes. Because these class names are generated at runtime by Vuetify components, UnoCSS cannot detect them by scanning source files.

uno.config.ts
{
  // presets: ...
  // outputToCssLayers: ...
  safelist: [
    ...Array.from({ length: 6 }, (_, i) => `elevation-${i}`),
    ['', '-0', '-sm', '-lg', '-xl', '-pill', '-circle', '-shaped'].map(suffix => `rounded${suffix}`),
  ],
}

Ready for more?

Continue your learning with related content selected by the Team or move between pages by using the navigation links below.