Skip to main content
Vuetify0 is now in alpha!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

useTheme


IntermediateApr 9, 2026

Theme management with multiple themes, CSS custom properties, and token alias resolution.

Installation

Install the Theme plugin in your app’s entry point:

main.ts
import { createApp } from 'vue'
import { createThemePlugin } from '@vuetify/v0'
import App from './App.vue'

const app = createApp(App)

app.use(
  createThemePlugin({
    default: 'light',
    themes: {
      light: {
        dark: false,
        colors: {
          primary: '#3b82f6',
        },
      },
      dark: {
        dark: true,
        colors: {
          primary: '#675496',
        },
      },
    },
  })
)

app.mount('#app')

Usage

Once the plugin is installed, use the useTheme composable in any component:

vue
<script setup lang="ts">
  import { useTheme } from '@vuetify/v0'

  const theme = useTheme()

  function toggleTheme() {
    theme.cycle(['light', 'dark'])
  }
</script>

<template>
  <div>
    <h1>Current Theme: {{ theme.selectedId }}</h1>
    <p>Dark mode: {{ theme.isDark ? 'enabled' : 'disabled' }}</p>
    <button @click="toggleTheme">Toggle Theme</button>
  </div>
</template>

Adapters

Adapters let you swap the underlying CSS injection strategy without changing your application code.

AdapterImportDescription
V0StyleSheetThemeAdapter@vuetify/v0Injects CSS via adoptedStyleSheets (default, SPA only)
V0UnheadThemeAdapter@vuetify/v0/theme/adapters/unheadInjects CSS via Unhead↗ for SSR/SSG

Both adapters set a data-theme attribute on the root element. Theme CSS is scoped to [data-theme="light"] / [data-theme="dark"] selectors so multiple themes can coexist in the same stylesheet.

When to use each:

  • V0StyleSheetThemeAdapter (default) — SPAs without SSR. Uses document.adoptedStyleSheets to inject a live CSSStyleSheet — no DOM <style> element, zero flicker, works well with CSP when configured.

  • V0UnheadThemeAdapter — SSR or SSG (Nuxt, VitePress). Manages the <style> tag and data-theme attribute via Unhead so the correct theme is rendered in the initial HTML, avoiding a flash of the wrong theme on hydration. Requires @unhead/vue.

Architecture

useTheme extends createSingle for theme selection and createTokens for color resolution:

Theme Hierarchy

Use controls to zoom and pan. Click outside or press Escape to close.

Theme Hierarchy

Reactivity

Theme selection and computed colors are reactive. Switching themes automatically updates CSS variables.

Property/MethodReactiveNotes
selectedIdCurrent theme ID
selectedItemCurrent theme ticket
selectedValueCurrent theme colors
selectedIndexIndex in registry
colorsResolved colors for all registered themes (keyed by theme ID)
isDarkCurrent theme is dark
select(id)Switch to a specific theme by ID
cycle(ids?)Advance to the next theme. Pass an array to restrict which themes to cycle

Examples

Color Studio

Color Studio

A theme explorer using createTheme with a shared palette of token aliases. Switch between predefined themes, inspect resolved colors, and register new themes at runtime.

FileRole
context.tsCreates createTheme with palette aliases and four themes
Preview.vueMini app UI that renders using resolved theme colors
color-studio.vueTheme selector, swatch grid, and dynamic registration
A
Alex Chen
alex@example.com
Online
Sprint progress
68%
Design Frontend Q2
Palette tokens
blue
emerald
rose
amber
violet
Light mode4 themes

API Reference

The following API details are for the useTheme composable.

Functions

createTheme

(_options?: ThemeOptions<ThemeRecord>) => ThemeContext<ThemeTicketInput, ThemeTicket<ThemeTicketInput>>

Creates a new theme instance.

createThemeContext

<_E>(_options?: ThemePluginOptions | undefined) => ContextTrinity<_E>

createThemePlugin

(_options?: ThemePluginOptions | undefined) => Plugin

useTheme

<_E>(namespace?: string) => _E

Options

events

boolean | undefined

Enable event emission for registry operations

Default: false

reactive

boolean | undefined

Enable reactive behavior for registry operations

Default: false

adapter

ThemeAdapter | undefined

The theme adapter to use.

default

ID | undefined

The default theme ID to select on initialization.

foreground

boolean | undefined

Automatically generate `on-*` foreground colors for each theme color using APCA contrast analysis.

palette

TokenCollection | undefined

A collection of tokens to use for resolving theme colors.

rgb

boolean | undefined

Output CSS variable values as decomposed RGB channels (`R, G, B`) instead of hex strings.

themes

Record<ID, Z> | undefined

A record of themes to register.

target

string | HTMLElement | null | undefined

The target element or selector to apply theme classes to.

Properties

collection

ReadonlyMap<ID, E>

The collection of tickets in the registry

size

number

The number of tickets in the registry

selectedIds

Reactive<Set<ID>>

Set of currently selected ticket IDs

selectedItems

ComputedRef<Set<E>>

Computed Set of selected ticket instances

selectedValues

ComputedRef<Set<E["value"] extends Ref<infer U, infer U> ? U : E["value"]>>

Computed Set of selected ticket values

disabled

MaybeRefOrGetter<boolean>

Disabled state for the entire model instance

multiple

MaybeRefOrGetter<boolean>

Whether the selection allows multiple selections

selectedId

ComputedRef<ID | undefined>

selectedIndex

ComputedRef<number>

selectedItem

ComputedRef<E | undefined>

selectedValue

ComputedRef<E["value"] | undefined>

colors

ComputedRef<Record<string, Colors>>

A computed reference to the resolved colors of all registered themes.

isDark

Readonly<Ref<boolean, boolean>>

A ref indicating whether the current theme is dark.

Methods

clear

() => void

Clear the entire registry

has

(id: ID) => boolean

Check if a ticket exists by ID

keys

() => readonly ID[]

Get all registered IDs

browse

(value: E["value"]) => ID[] | undefined

Browse for an ID(s) by value

lookup

(index: number) => ID | undefined

lookup a ticket by index number

get

(id: ID) => E | undefined

Get a ticket by ID

upsert

(id: ID, ticket?: Partial<Z>, event?: string) => E

Update or insert a ticket by ID

values

() => readonly E[]

Get all values of registered tickets

entries

() => readonly [ID, E][]

Get all entries of registered tickets

unregister

(id: ID) => void

Unregister a ticket by ID

reindex

() => void

Reset the index directory and update all tickets

move

(id: ID, toIndex: number) => E | undefined

Seek for a ticket based on direction and optional predicate

seek

(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefined

on

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Listen for registry events

off

<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => void

Stop listening for registry events

emit

<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => void

Emit an event with data

dispose

() => void

Clears the registry and removes all listeners

offboard

(ids: ID[]) => void

Offboard multiple tickets at once

batch

<R>(fn: () => R) => R

Execute operations in a batch, deferring cache invalidation and event emission until complete

reset

() => void

Reset selection state without destroying the registry

select

(id: ID) => void

Select a ticket by ID

unselect

(id: ID) => void

Unselect a ticket by ID

toggle

(id: ID) => void

Toggle a ticket's selection state

selected

(id: ID) => boolean

Check if a ticket is currently selected

apply

(values: unknown[], options?: { multiple?) => void

Apply external values to the model

mandate

() => void

Mandate selected ID based on "mandatory" option

onboard

(registrations: Partial<Z>[]) => E[]

Onboard multiple tickets at once

cycle

(themes?: ID[]) => void

Cycles through the provided themes in order.

register

(registration?: Partial<Z>) => E

Register a theme with optional colors. When `colors` is provided, onboards them as flat tokens for alias resolution and stores them as the ticket value.

Was this page helpful?

© 2016-1970 Vuetify, LLC
Ctrl+/