Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

Vuetify User Guide

Generated June 2026 from vuetifyjs/vuetify at bbffe05

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

Vuetify is a Vue 3 Material Design component framework. It ships more than one hundred ready-made UI components — buttons, forms, data tables, dialogs, navigation, pickers, and more — together with a reactive system for theming, responsive breakpoints, icons, internationalization, and global configuration. You write Vue templates with components like <v-btn> and <v-text-field>, and Vuetify handles the styling, accessibility scaffolding, and Material Design behavior.

This guide covers everything you need to install Vuetify, configure it, and use its components and features in a real application. It is built from the framework's source code at version 4.1.0, so every option, breakpoint, color, and command below reflects what the code actually does.

Note

Vuetify 4 requires Vue 3.5.0 or later and Node.js 24.11.1+ for local development tooling. It is published under the MIT license.


Table of Contents

  1. Quick Start
  2. Installation
  3. Core Concepts
  4. The Application Layout
  5. Theme & Colors
  6. Display & Breakpoints
  7. Icons
  8. Global Defaults
  9. Blueprints
  10. Internationalization & RTL
  11. Dates
  12. The Component Catalog
  13. Forms & Validation
  14. Directives
  15. Programmatic Scrolling
  16. Styling, Utility Classes & SASS
  17. Tree-Shaking & Production Builds
  18. Server-Side Rendering (SSR)
  19. Troubleshooting
  20. Frequently Asked Questions
  21. Reference

1. Quick Start

The fastest path to a running Vuetify app is the official scaffolding tool, create-vuetify. It generates a complete Vite + Vue 3 + Vuetify project with sensible defaults.

pnpm

pnpm create vuetify

npm

npm create vuetify@latest

yarn

yarn create vuetify

bun

bun create vuetify

The tool prompts you for a project name, whether to use TypeScript, and which package manager to install with:

success Installed "create-vuetify@x.x.x" with binaries:
    - create-vuetify

? Project name: ❯ vuetify-project
? Use TypeScript?: ❯ No / Yes
? Would you like to install dependencies with yarn, npm, or pnpm?:
  ❯ yarn
    npm
    pnpm
    bun
    none

Once the scaffold finishes, start the dev server:

cd vuetify-project
pnpm dev
  VITE v7.x  ready in 412 ms

  ➜  Local:   http://localhost:3000/
  ➜  Network: use --host to expose

Open the printed URL and you have a working Vuetify application. Every component, the theme system, and the icon set are already wired up.

Tip

create-vuetify is the recommended starting point for new projects. If you are adding Vuetify to an existing project, follow the manual installation steps instead.


2. Installation

Vuetify supports many environments. Pick the one that matches your project.

Use create-vuetify as shown in the Quick Start. This sets up Vite, the vite-plugin-vuetify for automatic tree-shaking, fonts, and icons for you.

Using Nuxt 3

You can either use the dedicated module or wire Vuetify in manually.

Manual setup. Create a Nuxt app, then add Vuetify and the Vite plugin as dev dependencies plus an icon font:

pnpm

pnpx nuxi@latest init <project-name>
cd <project-name>
# Create a .npmrc file with shamefully-hoist=true
pnpm install
pnpm i -D vuetify vite-plugin-vuetify
pnpm i @mdi/font

npm

npx nuxi@latest init <project-name>
cd <project-name>
npm install
npm i -D vuetify vite-plugin-vuetify
npm i @mdi/font

Add the plugin to nuxt.config.ts:

import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify'

export default defineNuxtConfig({
  build: {
    transpile: ['vuetify'],
  },
  vite: {
    plugins: [
      // @ts-expect-error
      vuetify({ autoImport: true }),
    ],
    vue: {
      template: {
        transformAssetUrls,
      },
    },
  },
})

Initialize Vuetify as a Nuxt plugin in ~/plugins/vuetify.ts:

import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'

export default defineNuxtPlugin((app) => {
  const vuetify = createVuetify({
    // ... your configuration
  })
  app.vueApp.use(vuetify)
})

Finally, wrap your app in the root <v-app> component in ~/app.vue or ~/layouts/default.vue:

<template>
  <NuxtLayout>
    <v-app>
      <NuxtPage />
    </v-app>
  </NuxtLayout>
</template>

Tip

The opinionated vuetify-nuxt-module (Vite only) works out of the box with zero configuration for most use cases.

Using Laravel

As long as you chain .use() on your Vue app, Vuetify registers correctly. In resources/js/app.ts:

import { createApp } from 'vue'
import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'

const app = createApp()
const vuetify = createVuetify()
app.use(vuetify).mount('#app')

And add the Vite plugin to vite.config.ts:

import vuetify from 'vite-plugin-vuetify'

export default defineConfig({
  plugins: [
    vuetify({ autoImport: true }),
  ],
})

Warning

If a font is defined in resources/views/app.blade.php, Vuetify's own font settings will not take effect.

Using a CDN

For quick prototypes with no build tooling, load the precompiled CSS and JS bundles from jsDelivr. All components and styles are included.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify@4.1.0/dist/vuetify.min.css" />
  </head>
  <body>
    <div id="app">
      <v-app>
        <v-container>
          <v-text-field label="My field" />
        </v-container>
      </v-app>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuetify@4.1.0/dist/vuetify.min.js"></script>
    <script>
      const { createApp } = Vue
      const { createVuetify } = Vuetify
      const vuetify = createVuetify()
      const app = createApp()
      app.use(vuetify).mount('#app')
    </script>
  </body>
</html>

Using an ES Module with a CDN

With an import map you can use Vuetify as native ES modules without a bundler. Note the bundle is vuetify.esm.js, not .min.js:

<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vuetify@4.1.0/dist/vuetify.min.css" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@mdi/font@latest/css/materialdesignicons.min.css" />
  <link rel="stylesheet" href="https://fonts.bunny.net/css?family=roboto:400,500,700" />
  <script type="importmap">
  {
    "imports": {
      "vue": "https://cdn.jsdelivr.net/npm/vue@latest/dist/vue.esm-browser.js",
      "vuetify": "https://cdn.jsdelivr.net/npm/vuetify@4.1.0/dist/vuetify.esm.js"
    }
  }
  </script>
</head>

Using VitePress

After initializing a VitePress project, add Vuetify and register it in .vitepress/theme/index.ts:

import DefaultTheme from 'vitepress/theme'
import 'vuetify/styles'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import { createVuetify } from 'vuetify'

const vuetify = createVuetify({ components, directives })

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    app.use(vuetify)
  },
}

Existing projects

To add Vuetify to an existing project without scaffolding, install the package:

pnpm

pnpm i vuetify

npm

npm i vuetify

yarn

yarn add vuetify

bun

bun add vuetify

Then register it where you create the Vue app:

import { createApp } from 'vue'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'
import * as components from 'vuetify/components'
import * as directives from 'vuetify/directives'
import App from './App.vue'

const vuetify = createVuetify({
  components,
  directives,
})

createApp(App).use(vuetify).mount('#app')

Important

Importing all components and directives like this is convenient but increases your bundle size during development. For production, prefer the Vite plugin with autoImport so only the components you actually use are bundled.

Fonts

Vuetify uses Roboto as its default font. You must add it yourself. The recommended approach uses @fontsource/roboto:

pnpm

pnpm i @fontsource/roboto

npm

npm i @fontsource/roboto

Then import the weights you need in main.ts:

import '@fontsource/roboto/100.css'
import '@fontsource/roboto/300.css'
import '@fontsource/roboto/400.css'
import '@fontsource/roboto/500.css'
import '@fontsource/roboto/700.css'
import '@fontsource/roboto/900.css'

A cleaner alternative bundles fonts with unplugin-fonts so they are downloaded once at build time. See the Reference for the vite.config.ts snippet.


3. Core Concepts

The createVuetify plugin

Everything starts with createVuetify(). It returns a Vue plugin that you register with app.use(). Internally, it builds the framework's reactive subsystems and provides them to every component in your app:

import { createVuetify } from 'vuetify'

const vuetify = createVuetify({
  theme:   { /* ... */ },   // colors, light/dark
  display: { /* ... */ },   // responsive breakpoints
  icons:   { /* ... */ },   // icon sets and aliases
  locale:  { /* ... */ },   // translations and RTL
  date:    { /* ... */ },   // date adapter for pickers
  defaults:{ /* ... */ },   // global prop defaults
  blueprint: /* ... */,     // a preset bundle of the above
  ssr: true,                // enable when server-rendering
})

When the plugin installs, it registers your components and directives globally and exposes a single $vuetify object on every component instance, with defaults, display, theme, icons, locale, and date.

Note

The full list of options is aliases, blueprint, components, date, directives, defaults, display, goTo, theme, icons, locale, and ssr. Each one is described in its own section of this guide and summarized in the Admin Guide configuration reference.

Accessing framework state in your components

Every subsystem has a composable you can call from <script setup>. They return reactive objects:

<script setup>
import { useTheme } from 'vuetify'
import { useDisplay } from 'vuetify'

const theme = useTheme()
const { mobile, mdAndUp } = useDisplay()
</script>

Caution

These composables must be called during a component's setup(). Calling useTheme() or useDisplay() outside of a component (for example, in a plain module) throws "Could not find Vuetify … injection" because the injection context does not exist there.


4. The Application Layout

Vuetify provides a coordinated layout system. The root component is <v-app>; every other layout component registers itself with it so that app bars, drawers, and footers automatically reserve space and never overlap your main content.

Component Role
<v-app> Required root. Wraps the whole UI and hosts theme + layout state.
<v-main> The content area that flexes around bars and drawers.
<v-app-bar> Top (or bottom) application toolbar.
<v-system-bar> Slim status bar above the app bar.
<v-navigation-drawer> Side navigation panel (left/right, permanent/temporary).
<v-footer> Bottom footer; can be made app to integrate with the layout.
<v-layout> / <v-layout-item> Lower-level building blocks for custom layouts.

A typical shell looks like this:

<template>
  <v-app>
    <v-app-bar title="My Application" />

    <v-navigation-drawer>
      <v-list>
        <v-list-item title="Dashboard" to="/" />
        <v-list-item title="Settings" to="/settings" />
      </v-list>
    </v-navigation-drawer>

    <v-main>
      <v-container>
        <router-view />
      </v-container>
    </v-main>

    <v-footer app>© 2026 My Company</v-footer>
  </v-app>
</template>

Important

Wrap your application in exactly one <v-app>. Many components — overlays, menus, dialogs, theming — depend on the providers that <v-app> and the createVuetify plugin set up. Without it, layout offsets and theme classes will not apply correctly.

Tip

Put page content inside <v-container> (centered, responsive gutters), then use <v-row> and <v-col> for the 12-column grid. See The Component Catalog → Grid & Layout.


5. Theme & Colors

Vuetify ships a complete theming engine. It generates CSS custom properties for a palette and exposes a reactive API to switch themes at runtime.

Built-in themes

Two themes are defined out of the box: light and dark. The default theme is system, which automatically follows the operating system's prefers-color-scheme setting and switches live when the user changes it.

const vuetify = createVuetify({
  theme: {
    defaultTheme: 'dark', // 'light' | 'dark' | 'system' | your custom name
  },
})

The default light and dark palettes (exact values from source) include:

Token Light Dark
background #FFFFFF #121212
surface #FFFFFF #212121
primary #1867C0 #2196F3
secondary #48A9A6 #54B6B2
success #4CAF50 #4CAF50
info #2196F3 #2196F3
warning #FB8C00 #FB8C00
error #B00020 #CF6679

Defining a custom theme

const vuetify = createVuetify({
  theme: {
    defaultTheme: 'myTheme',
    themes: {
      myTheme: {
        dark: false,
        colors: {
          primary: '#1976D2',
          secondary: '#424242',
          surface: '#FFFFFF',
          background: '#F5F5F5',
          error: '#FF5252',
        },
      },
    },
  },
})

Each color you declare produces matching utility classes (bg-primary, text-primary, border-primary) and a contrasting on- color (for example on-primary) is computed automatically based on luminance so text stays legible on any background.

Tip

You do not have to define on-primary, on-surface, etc. Vuetify derives them for you using the theme's theme-on-light / theme-on-dark variables. Override one only if you want a specific contrast color.

Switching themes at runtime

useTheme() returns the theme instance with these methods:

<script setup>
import { useTheme } from 'vuetify'

const theme = useTheme()

function toggle () {
  theme.toggle()                 // swap between ['light', 'dark']
}

function goDark () {
  theme.change('dark')           // switch to a named theme
}

function next () {
  theme.cycle(['light', 'dark', 'myTheme'])  // rotate through a list
}
</script>

<template>
  <v-btn @click="toggle">Toggle theme</v-btn>
  <div>Current theme: {{ theme.name.value }}</div>
</template>
Method Behavior
change(name, transition?) Switch to a named theme. Warns if the name is unknown.
toggle(['a','b']?, transition?) Cycle between two themes (defaults to light/dark).
cycle([names]?, transition?) Advance to the next theme in a list, wrapping around.
setTransitionOrigin(event) Set the origin point for the animated theme transition.

Useful reactive properties on the instance include name (current theme name), current (the resolved theme definition), themes (all definitions), isSystem (whether following the OS), and global.name.

Animated theme transitions

Set transition: true to animate theme changes with a circular reveal using the View Transitions API (where the browser supports it). You can also pass per-change options:

createVuetify({
  theme: {
    transition: { duration: '500ms' },
  },
})
theme.setTransitionOrigin(pointerEvent) // start the reveal where the user clicked
theme.toggle(undefined, true)

Note

The transition automatically respects the user's prefers-reduced-motion setting and falls back to an instant switch when reduced motion is requested or the browser lacks document.startViewTransition.

Color variations

You can auto-generate lighter and darker shades of named colors:

createVuetify({
  theme: {
    variations: {
      colors: ['primary', 'secondary'],
      lighten: 3,   // generates primary-lighten-1..3
      darken: 2,    // generates primary-darken-1..2
    },
  },
})

Content Security Policy

If your site uses a CSP nonce, pass it so the injected <style> element is allowed:

createVuetify({ theme: { cspNonce: 'your-nonce' } })

6. Display & Breakpoints

The display system makes your UI responsive. It tracks viewport size and exposes reactive booleans for each breakpoint.

Breakpoint thresholds

The default thresholds (in pixels, from source) are:

Breakpoint Range
xs 0 – 599
sm 600 – 839
md 840 – 1144
lg 1145 – 1544
xl 1545 – 2137
xxl 2138+

Warning

These thresholds changed in Vuetify 4. If you are migrating from Vuetify 3, the md/lg boundaries are different, so layouts that keyed off the old values may shift. Override them via display.thresholds if you need the old behavior.

Using useDisplay

<script setup>
import { useDisplay } from 'vuetify'

const { mobile, name, width, height, mdAndUp, smAndDown, platform } = useDisplay()
</script>

<template>
  <v-navigation-drawer :permanent="mdAndUp" :temporary="smAndDown" />
  <div v-if="mobile">Compact layout</div>
  <div>Current breakpoint: {{ name }} ({{ width }}×{{ height }})</div>
</template>

Available reactive members:

  • Exact: xs, sm, md, lg, xl, xxl
  • And up: smAndUp, mdAndUp, lgAndUp, xlAndUp
  • And down: smAndDown, mdAndDown, lgAndDown, xlAndDown
  • Values: name, width, height, mobile, mobileBreakpoint, thresholds
  • Platform: platform.android, platform.ios, platform.mac, platform.win, platform.linux, platform.chrome, platform.firefox, platform.touch, and more.

The mobile breakpoint

mobile is true when the viewport is narrower than the mobile breakpoint, which defaults to 'lg' (1145px). Many components change behavior below it (for example dialogs become fullscreen). Configure it globally or per component:

createVuetify({
  display: {
    mobileBreakpoint: 'sm',
    thresholds: { sm: 480, md: 768, lg: 1024, xl: 1440, xxl: 1920 },
  },
})
<v-data-table :mobile-breakpoint="600" />

7. Icons

Vuetify's icon system is pluggable. A component never hard-codes an SVG path; it asks for an icon value which is resolved through the configured icon set.

Choosing an icon set

The default set is Material Design Icons (mdi), using the font version. Fifteen sets ship in the box: mdi, mdi-svg, md, fa (Font Awesome font), fa-svg, fa4, fa6, lucide, tabler, carbon, ph (Phosphor), ri (Remix), bx (BoxIcons), ms, and mdi-unocss.

import { aliases, mdi } from 'vuetify/iconsets/mdi'

createVuetify({
  icons: {
    defaultSet: 'mdi',
    aliases,
    sets: { mdi },
  },
})

For the tree-shakeable SVG version of Material Design Icons:

import { aliases, mdi } from 'vuetify/iconsets/mdi-svg'

createVuetify({
  icons: { defaultSet: 'mdi', aliases, sets: { mdi } },
})

Using icons

The <v-icon> component and any *-icon prop accept an icon value in several forms:

<!-- From the default set, by name -->
<v-icon icon="mdi-account" />

<!-- A built-in semantic alias (prefixed with $) -->
<v-icon icon="$success" />

<!-- Explicitly from a named set using set:name syntax -->
<v-icon icon="fa:fas fa-home" />

<!-- A raw SVG path string -->
<v-icon icon="svg:M12,2C17.5..." />

Note

Aliases starting with $ map to Vuetify's semantic icons — the icons components use internally for states like checkboxes, sorting, navigation, and ratings. Overriding an alias (for example $success) re-skins every component that uses it. The full alias list includes complete, cancel, close, delete, clear, success, info, warning, error, prev, next, checkboxOn, checkboxOff, checkboxIndeterminate, sortAsc, sortDesc, expand, collapse, menu, dropdown, radioOn, radioOff, edit, ratingEmpty, ratingFull, ratingHalf, loading, first, last, file, plus, minus, calendar, and more.

Customizing aliases

import { aliases, mdi } from 'vuetify/iconsets/mdi-svg'
import { mdiHome } from '@mdi/js'

createVuetify({
  icons: {
    defaultSet: 'mdi',
    aliases: { ...aliases, customHome: mdiHome },
    sets: { mdi },
  },
})
<v-icon icon="$customHome" />

8. Global Defaults

The defaults system lets you set default prop values for any component, globally or for a scoped subtree. This is how you enforce a consistent look without repeating props on every element.

Global defaults

createVuetify({
  defaults: {
    global: {
      ripple: false,            // applies to every component that has a ripple prop
    },
    VBtn: {
      variant: 'flat',
      color: 'primary',
      rounded: 'lg',
    },
    VTextField: {
      variant: 'outlined',
      density: 'comfortable',
    },
  },
})

Now every <v-btn> is flat and primary-colored unless you override it inline. Resolution order is: prop set on the element → component default (VBtn) → global default (global) → the component's own built-in default.

Scoped defaults with <v-defaults-provider>

To apply defaults to only part of the tree, wrap that part in <v-defaults-provider>:

<v-defaults-provider :defaults="{ VBtn: { size: 'small', variant: 'text' } }">
  <v-btn>Small text button</v-btn>
  <v-btn>Another one</v-btn>
</v-defaults-provider>

Tip

Defaults can also target nested sub-components. A key like VBtn inside another component's defaults applies only to buttons rendered by that component, which is how you theme, for example, the buttons inside a VCard.


9. Blueprints

A blueprint is a pre-packaged bundle of createVuetify options — themes, defaults, icons — that gives your whole app a consistent design language in one line. Three Material Design blueprints ship in the box: md1, md2, and md3 (Material Design 1, 2, and 3).

import { createVuetify } from 'vuetify'
import { md3 } from 'vuetify/blueprints/md3'

const vuetify = createVuetify({
  blueprint: md3,
})

Your own options are merged on top of the blueprint, so you can adopt the Material 3 look and still override individual colors or defaults:

const vuetify = createVuetify({
  blueprint: md3,
  theme: {
    themes: { light: { colors: { primary: '#6750A4' } } },
  },
})

10. Internationalization & RTL

Vuetify components display some text of their own (pagination labels, data-table messages, "no data" strings, etc.). The locale system controls that text and supports right-to-left layouts.

Built-in languages

Translations ship for 43 languages, including English (en, the fallback), German (de), Spanish (es), French (fr), Chinese (zh-Hans / zh-Hant), Japanese (ja), Korean (ko), Arabic (ar), Hebrew (he), Persian (fa), Russian (ru), Portuguese (pt), Italian (it), and many more.

import { createVuetify } from 'vuetify'
import { en, de, es } from 'vuetify/locale'

const vuetify = createVuetify({
  locale: {
    locale: 'de',
    fallback: 'en',
    messages: { en, de, es },
  },
})

You can also set the decimal and grouping separators used by number formatting:

createVuetify({
  locale: { decimalSeparator: ',', numericGroupSeparator: '.' },
})

Switching locale at runtime

<script setup>
import { useLocale } from 'vuetify'

const { current } = useLocale()
function setGerman () { current.value = 'de' }
</script>

Integrating with vue-i18n

If your app already uses vue-i18n, plug it into Vuetify with the supplied adapter so both share one source of translations:

import { createI18n, useI18n } from 'vue-i18n'
import { createVueI18nAdapter } from 'vuetify/locale/adapters/vue-i18n'
import { en, de } from 'vuetify/locale'

const i18n = createI18n({
  legacy: false,
  locale: 'en',
  messages: { en: { $vuetify: en }, de: { $vuetify: de } },
})

const vuetify = createVuetify({
  locale: {
    adapter: createVueI18nAdapter({ i18n, useI18n }),
  },
})

Right-to-left (RTL)

The languages ar (Arabic), fa (Persian), and he (Hebrew) are RTL by default. Enable RTL globally or scope it to part of the page with <v-locale-provider>:

<v-locale-provider rtl>
  <!-- this subtree renders right-to-left -->
</v-locale-provider>

Use useRtl() to read or react to the current direction:

<script setup>
import { useRtl } from 'vuetify'
const { isRtl } = useRtl()
</script>

11. Dates

The date-based components — <v-date-picker>, <v-date-input>, <v-calendar> — work through a date adapter so you can use whichever date library your project already depends on. The built-in VuetifyDateAdapter uses the native Intl API and needs no extra dependency.

import { createVuetify } from 'vuetify'

// Uses the built-in adapter — nothing else required
const vuetify = createVuetify()

To use date-fns, luxon, dayjs, or moment, install the matching @date-io adapter and pass it:

import { createVuetify } from 'vuetify'
import DateFnsAdapter from '@date-io/date-fns'
import enUS from 'date-fns/locale/en-US'

const vuetify = createVuetify({
  date: {
    adapter: DateFnsAdapter,
    locale: { en: enUS },
  },
})

Note

Vuetify maps its locale codes to standard locale strings for dates automatically (for example en → en-US, de → de-DE, ja → ja-JP), so date formatting follows the active language out of the box.


12. The Component Catalog

Vuetify ships 104 stable components plus a set of experimental labs components. Every component is registered globally by createVuetify, so you can use them in any template without importing them (with the Vite plugin handling tree-shaking). Components are written in PascalCase (VTextField) and used in kebab-case in templates (<v-text-field>).

Important

Each component exposes a large, strongly-typed set of props, slots, and events. The exhaustive, always-current per-prop API reference is generated directly from the source types and published at vuetifyjs.com. This guide groups the components by purpose so you can find the right one; consult the online API for the full prop signature of any individual component.

Layout & Application

Component Purpose
v-app Required root wrapper.
v-main Main content region that flexes around bars/drawers.
v-app-bar Top/bottom application toolbar.
v-system-bar Slim status bar.
v-toolbar Generic toolbar (used standalone or inside bars).
v-navigation-drawer Side navigation panel.
v-footer Page footer.
v-layout / v-layout-item Low-level layout primitives.

Grid & Layout

Component Purpose
v-container Centered, responsive content wrapper.
v-row / v-col 12-column responsive flexbox grid.
v-spacer Flexible space inside flex containers.
v-responsive Enforces an aspect ratio / responsive sizing.
v-sheet A themed surface — the base for cards and panels.
v-divider Horizontal or vertical separating line.

Buttons & Actions

Component Purpose
v-btn Button (text, outlined, flat, icon, block, loading…).
v-btn-group / v-btn-toggle Grouped and toggle-selectable buttons.
v-icon-btn Icon-only button variant.
v-fab Floating action button.
v-speed-dial FAB that expands to reveal more actions.
v-icon Render an icon from any configured set.

Form Inputs & Controls

Component Purpose
v-text-field Single-line text input.
v-textarea Multi-line text input.
v-select Dropdown selection.
v-autocomplete Select with type-ahead filtering.
v-combobox Autocomplete that also accepts free input.
v-checkbox / v-radio / v-radio-group Selection controls.
v-switch On/off toggle.
v-slider / v-range-slider Single and dual-handle sliders.
v-file-input / v-file-upload File selection and upload.
v-otp-input One-time-password entry.
v-number-input Numeric input with steppers.
v-color-input / v-color-picker Color selection.
v-date-input / v-date-picker Date selection.
v-time-picker Time selection.
v-rating Star/icon rating input.
v-form Form wrapper with validation orchestration.
v-input / v-field / v-label / v-messages / v-counter Building blocks shared by the inputs above.
v-selection-control / v-selection-control-group Low-level primitives for checkbox/radio/switch.
v-confirm-edit Inline edit-with-confirm wrapper.
v-validation Standalone validation wrapper.

Data Presentation

Component Purpose
v-data-table Sortable, paginated, selectable data table (with server-side and virtual variants).
v-data-iterator Headless iteration over data with the same sorting/paging logic.
v-table Plain styled HTML table.
v-list Vertical list with items, groups, subheaders, dividers.
v-virtual-scroll Renders only visible rows for huge lists.
v-treeview Hierarchical tree with selection (labs/stable).
v-timeline Vertical/horizontal event timeline.
v-sparkline Inline mini line/bar chart.
v-infinite-scroll Load more content as the user scrolls.
v-pagination Page navigation control.

Containers & Surfaces

Component Purpose
v-card Material card with title, text, actions.
v-expansion-panel Accordion-style collapsible panels.
v-banner Prominent message banner.
v-alert Contextual alert/notification box.
v-chip / v-chip-group Compact tags / filter chips.
v-avatar Circular image/initials container.
v-badge Small status indicator overlaid on a child.
v-empty-state Friendly placeholder for empty content.
v-kbd / v-code Keyboard-key and inline-code styling.
Component Purpose
v-tabs Tabbed navigation.
v-breadcrumbs Breadcrumb trail.
v-bottom-navigation Mobile bottom navigation bar.
v-stepper / v-stepper-vertical Multi-step wizard.
v-window Swipeable/animated view container.
v-carousel Image/content carousel.
v-menu Anchored popup menu.
v-dialog Modal dialog.
v-bottom-sheet Sheet that slides up from the bottom.
v-overlay Low-level scrim/positioning primitive behind menus and dialogs.
v-tooltip Hover/focus tooltip.
v-snackbar / v-snackbar-queue Transient toast notifications (single and queued).

Feedback & Progress

Component Purpose
v-progress-linear Linear progress / loading bar.
v-progress-circular Circular progress spinner.
v-skeleton-loader Placeholder shimmer while content loads.
v-pull-to-refresh Pull-down-to-refresh gesture wrapper.

Media & Utility

Component Purpose
v-img Responsive image with lazy-loading and placeholders.
v-parallax Parallax-scrolling image.
v-hover Exposes hover state to its slot.
v-lazy Defers rendering until the element scrolls into view.
v-no-ssr Renders children only on the client.
v-hotkey Displays and binds keyboard shortcuts.
v-item-group Generic selectable group logic.
v-slide-group Horizontally scrollable group of items.

Providers (configuration components)

Component Purpose
v-theme-provider Apply a theme to a subtree.
v-locale-provider Apply a locale / RTL to a subtree.
v-defaults-provider Apply prop defaults to a subtree.

Labs (experimental)

The labs entry contains newer components whose API may still change: VAvatarGroup, VCommandPalette, VDateRangePicker, VHeatmap, VHighlight, VMaskInput, VMonthPicker, VPie, VProgress, and VVideo. Opt in explicitly:

import { createVuetify } from 'vuetify'
import { VTreeview } from 'vuetify/labs/VTreeview'

createVuetify({
  components: { VTreeview },
})

Warning

Labs components are production-usable but not API-stable. Pin your Vuetify version and review the changelog before upgrading if you depend on a labs component.

Example: a small but real form

<template>
  <v-card class="mx-auto pa-6" max-width="420">
    <v-card-title>Sign up</v-card-title>
    <v-form @submit.prevent="onSubmit">
      <v-text-field
        v-model="email"
        label="Email"
        :rules="[v => !!v || 'Required', v => /.+@.+/.test(v) || 'Invalid email']"
        prepend-inner-icon="$info"
      />
      <v-text-field v-model="password" label="Password" type="password" />
      <v-btn type="submit" color="primary" block class="mt-2">Create account</v-btn>
    </v-form>
  </v-card>
</template>

<script setup>
import { ref } from 'vue'
const email = ref('')
const password = ref('')
function onSubmit (e) { /* e is a SubmitEventPromise — see Forms section */ }
</script>

13. Forms & Validation

<v-form> coordinates validation across the inputs it contains. Each input registers itself with the form; the form aggregates their validity into a single reactive state.

Per-field rules

Every input accepts a :rules array. Each rule is a function returning true when valid or a string error message when invalid:

<v-text-field
  v-model="username"
  label="Username"
  :rules="[
    v => !!v || 'Username is required',
    v => v.length >= 3 || 'Must be at least 3 characters',
  ]"
/>

Form-level validation

<script setup>
import { ref } from 'vue'

const form = ref(null)

async function submit () {
  const { valid } = await form.value.validate()
  if (valid) {
    // all fields passed — proceed
  }
}

function clear () {
  form.value.reset()           // clear values and validation
  form.value.resetValidation() // clear only validation messages
}
</script>

<template>
  <v-form ref="form">
    <!-- inputs -->
    <v-btn @click="submit">Submit</v-btn>
    <v-btn @click="clear">Reset</v-btn>
  </v-form>
</template>

When validation runs

The validate-on prop controls timing. The default is input (validate as the user types). Other values let you validate on blur, on submit, or combinations such as blur lazy.

<v-form validate-on="submit">…</v-form>

Submitting

<v-form>'s @submit event provides a SubmitEventPromise — a native submit event that is also a promise resolving to { valid, errors }:

<v-form @submit.prevent="(e) => e.then(({ valid }) => valid && save())">
Prop / option Effect
validate-on When fields validate (input default, blur, submit, lazy…).
fast-fail Stop validating at the first failing field.
disabled Disable every input in the form.
readonly Make every input read-only.

Tip

Use fast-fail on large forms where you only need to know whether the form is valid, not collect every error at once — it stops at the first failure.


14. Directives

Directives add low-level DOM behavior to any element, not just Vuetify components. Register them globally (createVuetify({ directives })) or individually. Eight directives ship:

Directive Usage Purpose
v-ripple v-ripple Material "ink" ripple on click/touch.
v-resize v-resize="onResize" Call a handler when the window resizes.
v-intersect v-intersect="onIntersect" Fire when the element enters/leaves the viewport (IntersectionObserver).
v-mutate v-mutate="onMutate" Fire when the element's DOM changes (MutationObserver).
v-scroll v-scroll="onScroll" Call a handler on scroll.
v-touch v-touch="{ left, right, up, down }" Detect swipe gestures.
v-click-outside v-click-outside="onOutside" Fire when a click lands outside the element.
v-tooltip v-tooltip="'Help text'" Attach a tooltip directly to an element.
<div v-ripple class="pa-4">Click me for a ripple</div>

<div v-intersect="(isIntersecting) => visible = isIntersecting">
  Lazy-loaded section
</div>

<v-card v-touch="{ left: next, right: prev }">Swipe me</v-card>

Note

Many components use these directives internally — <v-btn>, for example, applies v-ripple automatically (toggle it with the ripple prop). You only need to register a directive yourself when applying it to your own elements.


15. Programmatic Scrolling

The useGoTo() composable performs smooth, animated scrolling to a target — an element, a CSS selector, a component ref, or a pixel offset.

<script setup>
import { useGoTo } from 'vuetify'

const goTo = useGoTo()

function scrollToFaq () {
  goTo('#faq')                          // to an element by selector
}

function scrollToTop () {
  goTo(0)                               // to a pixel offset
}

function scrollSidewaysTo () {
  goTo.horizontal('#col-5')             // horizontal scrolling
}
</script>

Configure duration, easing, offset, and container globally or per call:

createVuetify({
  goTo: {
    duration: 300,           // ms (default)
    easing: 'easeInOutCubic', // default easing pattern
    offset: 0,
  },
})
goTo('#section', { duration: 600, offset: -64 }) // offset accounts for a fixed app bar

Note

useGoTo automatically falls back to an instant jump when the user prefers reduced motion, and it respects RTL for horizontal scrolling.


16. Styling, Utility Classes & SASS

Utility classes

Vuetify generates utility classes for theme colors and common layout needs:

  • Color: bg-primary, text-secondary, border-error (one set per theme color).
  • Spacing: pa-4 (padding all), ma-2 (margin all), mt-3, px-6, etc., on a 4px scale.
  • Display & elevation: responsive display helpers and elevation-0 … elevation-24.
  • Screen-reader and pointer-event helpers.
<v-sheet class="bg-primary text-white pa-6 rounded-lg elevation-4">
  Themed, padded, elevated surface
</v-sheet>

Importing precompiled CSS

The simplest option imports the precompiled stylesheet:

import 'vuetify/styles'

Customizing with SASS variables

To override Vuetify's SASS variables (colors, spacing scale, component variables), configure the Vite or Webpack plugin to point at your own SASS entry, then import the settings:

// src/styles/settings.scss
@use 'vuetify/settings' with (
  $button-height: 44px,
  $border-radius-root: 6px,
);

The framework exposes three SASS entry points:

Entry Contents
vuetify Global CSS (reset, utilities), no component styles.
vuetify/settings All SASS variables, including per-component variables.
vuetify/tools Mixins and functions.

Tip

Editing SASS variables requires the build plugin (vite-plugin-vuetify or webpack-plugin-vuetify) with its styles.configFile option set — the precompiled vuetify/styles import cannot be customized after the fact.


17. Tree-Shaking & Production Builds

Importing every component is fine for prototypes but bloats production bundles. The official build plugins import only the components you actually use, automatically.

Vite plugin

import vuetify from 'vite-plugin-vuetify'

export default defineConfig({
  plugins: [
    vuetify({ autoImport: true }), // auto-imports only used components + directives
  ],
})

With autoImport: true you simply write <v-btn> in a template and the plugin adds the matching import behind the scenes — no manual import and no full-library bundle.

Manual per-component imports

Without the plugin, import components from their grouped path:

import { VBtn } from 'vuetify/components/VBtn'
import { VList, VListItem } from 'vuetify/components/VList'

Note

Components are grouped by their top-level name. VListItem, VListGroup, and VListItemTitle all live under vuetify/components/VList. Directives import from vuetify/directives/<name>.


18. Server-Side Rendering (SSR)

Vue 3 cannot auto-detect SSR, so frameworks like Nuxt and Gridsome must tell Vuetify explicitly by setting ssr: true:

import '@mdi/font/css/materialdesignicons.css'
import 'vuetify/styles'
import { createVuetify } from 'vuetify'

const vuetify = createVuetify({
  ssr: true,
})

You may pass an object to seed the display dimensions used during the server render:

createVuetify({
  ssr: { clientWidth: 1280, clientHeight: 800 },
})

Important

When ssr is enabled, Vuetify defers its first display update until after hydration to avoid a hydration mismatch between the server-rendered and client-rendered markup. If you see hydration warnings, confirm ssr: true is set.


19. Troubleshooting

The issues below are drawn from the framework's own issue tracker and the behaviors visible in source. Each lists the symptom, the cause, and what to do.

Error: Could not find Vuetify theme injection

  • Cause: useTheme() (or another use* composable) was called outside a component's setup(), or the component is not a descendant of an app that registered the createVuetify plugin.
  • Solution: Call the composable inside <script setup> / setup(), and ensure app.use(vuetify) ran and your UI is wrapped in <v-app>.
  • Prevention: Never call useTheme/useDisplay/useLocale from plain module scope.

Error: Could not find aliased icon "$xyz"

  • Cause: An icon value used a $alias that is not defined in your icons.aliases.
  • Solution: Add the alias to your icons.aliases, or import the set's default aliases and spread them: aliases: { ...aliases, xyz: mdiSomething }.
  • Prevention: Always pass the set's aliases export to createVuetify.

Theme toggle() behaves inconsistently after enabling theme transitions

  • Cause: With animated transitions enabled, a transition origin set by a previous call can carry over (tracked upstream for ThemeInstance.toggle()).
  • Solution: Call theme.setTransitionOrigin(event) immediately before the toggle, or toggle without a transition (theme.toggle(undefined, false)) when you do not need the animation.

VBtn size as a number does not change the font size

  • Cause: Numeric size controls dimensions but not typography in the current version.
  • Solution: Use a named size (x-small, small, default, large, x-large) or add a text utility class (text-h6) for font scaling.

VSelect with multiple and duplicate items cannot deselect an option

  • Cause: Duplicate item values make selection ambiguous.
  • Solution: Ensure each item has a unique value via item-value, or de-duplicate the items array before binding it.

VDialog with a percentage max-width is not respected

  • Cause: Percentage widths on the dialog were affected by a layout change.
  • Solution: Use an explicit pixel/rem max-width, or wrap the dialog content in a sized container.

MDI icons do not render in an offline PWA

  • Cause: The Material Design Icons font files were not cached by the service worker, so glyphs cannot load offline.
  • Solution: Ensure your PWA precaches the @mdi/font files, or switch to the tree-shakeable SVG set (vuetify/iconsets/mdi-svg) so icon paths are bundled into JS.

Icons / styles don't appear at all

  • Cause: Missing stylesheet or font import.
  • Solution: Confirm you imported 'vuetify/styles' and an icon font/CSS (for example '@mdi/font/css/materialdesignicons.css'), and that the app is inside <v-app>.

Tip

For a question that isn't covered here, the Vuetify community Discord and the issue generator at issues.vuetifyjs.com are the official support channels.


20. Frequently Asked Questions

Q: Which Vue version does Vuetify 4 require? Vue 3.5.0 or later. Vuetify 4 does not support Vue 2.

Q: Do I have to import each component? No. With create-vuetify or the Vite plugin's autoImport, components are registered and tree-shaken automatically. Manual imports are only needed if you are not using the plugin.

Q: Why do I need <v-app>? It establishes the layout root and hosts theming and overlay providers. Components like menus, dialogs, app bars, and drawers rely on it to position correctly.

Q: How do I switch between light and dark mode? Call useTheme().toggle(), or set theme.defaultTheme to 'system' to follow the OS.

Q: Does Vuetify follow the operating system's dark mode automatically? Yes. The default theme is 'system', which tracks prefers-color-scheme and updates live.

Q: How do I change the default look of all buttons (or any component)? Use the defaults option in createVuetify, keyed by the component name (e.g. VBtn), or wrap a subtree in <v-defaults-provider>.

Q: Can I use a font icon library other than Material Design Icons? Yes. Choose from 15 built-in sets (Font Awesome, Lucide, Tabler, Phosphor, Remix, Carbon, BoxIcons, Material Symbols, and more) via icons.defaultSet, or mix sets using the set:name prefix.

Q: How do I make my app responsive? Use useDisplay() for reactive breakpoint booleans (mobile, mdAndUp, etc.) and the 12-column grid (<v-row> / <v-col>) with responsive props.

Q: Which languages are supported out of the box? 43, with English as the fallback. You can also wire Vuetify into an existing vue-i18n setup.

Q: How do I support right-to-left languages? Arabic, Persian, and Hebrew are RTL by default. Use <v-locale-provider rtl> or useRtl() to control direction.

Q: My date picker needs a specific date library — is that possible? Yes. The built-in adapter uses native Intl; for date-fns, luxon, dayjs, or moment, pass the matching @date-io adapter to the date option.

Q: Are the "labs" components safe to use? They work, but their API is not stable. Pin your Vuetify version and check the changelog before upgrading.

Q: How do I customize SASS variables? Configure the Vite/Webpack plugin's styles.configFile and @use 'vuetify/settings' with your overrides. The precompiled vuetify/styles import cannot be customized.

Q: How do I reduce my production bundle size? Use the Vite plugin with autoImport: true, the SVG icon set, and import only the locales you ship.


21. Reference

createVuetify options at a glance

Option Purpose
theme Light/dark/custom palettes, default theme, transitions, variations.
display Breakpoint thresholds and the mobile breakpoint.
icons Default icon set, sets, and $ aliases.
locale Translations, fallback, RTL, separators, i18n adapter.
date Date adapter and locale map for date components.
defaults Global and per-component default prop values.
goTo Default scroll duration, easing, offset, container.
blueprint A preset bundle (md1/md2/md3) merged under your options.
components / directives / aliases Explicit registration of components, directives, and component aliases.
ssr Enable server-side rendering support.

Breakpoint thresholds (px)

xs sm md lg xl xxl
0 600 840 1145 1545 2138

Default theme colors

Token Light Dark
primary #1867C0 #2196F3
secondary #48A9A6 #54B6B2
background #FFFFFF #121212
surface #FFFFFF #212121
success #4CAF50 #4CAF50
info #2196F3 #2196F3
warning #FB8C00 #FB8C00
error #B00020 #CF6679

Composables

Composable Returns
useTheme() Theme instance: name, current, change, toggle, cycle.
useDisplay() Breakpoint booleans, mobile, width/height, platform.
useLocale() Current locale, translation function.
useRtl() isRtl, rtlClasses.
useGoTo() Smooth-scroll function (with .horizontal).
useDefaults() Resolved props merged with global/scoped defaults.

Key exports

Path Contents
vuetify createVuetify, public composables.
vuetify/styles Precompiled global CSS.
vuetify/components / vuetify/components/<Name> All / grouped components.
vuetify/directives / vuetify/directives/<name> All / individual directives.
vuetify/blueprints/<name> md1, md2, md3 blueprints.
vuetify/locale / vuetify/locale/adapters/<name> Translations / i18n adapters.
vuetify/iconsets/<name> Icon set presets.
import { defineConfig } from 'vite'
import ViteFonts from 'unplugin-fonts/vite'

export default defineConfig({
  plugins: [
    ViteFonts({
      fontsource: {
        families: [
          { name: 'Roboto', weights: [100, 300, 400, 500, 700, 900], styles: ['normal', 'italic'] },
        ],
      },
    }),
  ],
})
// main.ts
import 'unfonts.css'