Back to Vuetify

UnoCSS with Vuetify preset

packages/docs/src/pages/en/features/css-utilities/unocss-vuetify-preset.md

4.1.56.0 KB
Original Source

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.

<PageFeatures /> <PromotedEntry />

:::: tabs

bash
# generate working project for reference
npx @vuetify/cli@latest init --type=vuetify --css=unocss-vuetify
bash
# generate working project for reference
pnpx @vuetify/cli@latest init --type=vuetify --css=unocss-vuetify
bash
# generate working project for reference
yarn dlx @vuetify/cli@latest init --type=vuetify --css=unocss-vuetify
bash
# generate working project for reference
bunx @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:

css
@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:

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

Install UnoCSS and the Vuetify preset:

::: tabs

bash
pnpm add -D unocss unocss-preset-vuetify
bash
yarn add -D unocss unocss-preset-vuetify
bash
npm i -D unocss unocss-preset-vuetify
bash
bun add -D unocss unocss-preset-vuetify

:::

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

ts
import UnoCSS from 'unocss/vite'

export default defineConfig({
  plugins: [
    UnoCSS(),
    // ...
  ],
})
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:

ts
import 'virtual:uno.css'

Nuxt

::: tabs

bash
pnpm add -D unocss unocss-preset-vuetify @unocss/nuxt
bash
yarn add -D unocss unocss-preset-vuetify @unocss/nuxt
bash
npm i -D unocss unocss-preset-vuetify @unocss/nuxt
bash
bun 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:

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.

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.

ts
{
  // presets: ...
  // outputToCssLayers: ...
  safelist: [
    ...Array.from({ length: 6 }, (_, i) => `elevation-${i}`),
    ['', '-0', '-sm', '-lg', '-xl', '-pill', '-circle', '-shaped'].map(suffix => `rounded${suffix}`),
  ],
}
<!-- TODO: color prop is kinda similar, but it depends on which color you use. - theme (semantic) colors are injected into HEAD as part of theme stylesheet. - colors from Material color palette provided by the UnoCSS preset require full class name to appear in the source code. color prop will remove bg-* and text-* prefixes, but it may be a bit confusing <v-card color="bg-orange-accent-2" variant="flat" /> <v-card color="text-lime-darken-3" variant="tonal" /> --> <!-- TODO: cover approach to border prop after releasing ESLint plugin -->