Back to Blog

vue-multiple-themes v4: Dynamic Multi-Theme Support for Vue 2 & 3

AI Transformation Lead
  • Vue
  • TypeScript
  • Open Source
  • CSS
  • Themes
  • TailwindCSS
  • Dark Mode
  • WCAG
Abstract visualization of multiple color themes applied to a Vue.js application

I have been building UIs with Vue for years and one pattern comes up constantly, you need more than dark/light. Clients want seasonal themes, brand-specific palettes, and accessibility-compliant contrasts. I extracted all of that into a standalone, typed library: vue-multiple-themes.

Full Documentation & Demo

What It Solves

The standard approach is toggling a .dark class on <html> and writing a wall of CSS overrides. That works for two themes. Scale to three or more and you get duplicated selectors, fragile specificity battles, and no tooling for generating accessible palettes.

vue-multiple-themes replaces that with:

  • CSS custom properties (--vmt-*) injected at the target element: every theme is a swap of values at one cascade layer
  • A reactive useTheme() composable accessible anywhere in the component tree
  • 7 preset themes ready to use immediately
  • A TailwindCSS plugin that exposes those tokens as Tailwind utilities
  • WCAG color utilities for contrast checking, mixing, and palette generation: all SSR-safe

Installation

bash
pnpm add vue-multiple-themes

Requires Vue 2.7+ or Vue 3. Zero runtime dependencies beyond Vue itself.

Quick Start: Vue 3

Register the plugin once in main.ts:

typescript
import { createApp } from 'vue'; import { VueMultipleThemesPlugin } from 'vue-multiple-themes'; import App from './App.vue'; const app = createApp(App); app.use(VueMultipleThemesPlugin, { defaultTheme: 'dark', strategy: 'attribute', persist: true, }); app.mount('#app');

Then use useTheme() anywhere:

vue
<script setup lang="ts"> import { useTheme, PRESET_THEMES } from 'vue-multiple-themes'; const { currentTheme, setTheme, themes } = useTheme({ themes: PRESET_THEMES }); </script> <template> <button v-for="t in themes" :key="t.name" @click="setTheme(t.name)"> {{ t.label }} </button> </template>

CSS Custom Properties

Once a theme is active, --vmt-* variables are available on <html>. Style components against them:

css
.card { background: var(--vmt-background); color: var(--vmt-foreground); border: 1px solid var(--vmt-border); }

Switching themes updates every component instantly, no re-renders required.

The 7 Preset Themes

NameCharacter
lightClean white + indigo
darkDark gray + violet
sepiaWarm parchment browns
oceanDeep sea blues
forestRich greens
sunsetWarm oranges & reds
winterIcy blues & whites

Dynamic Theme Generation

typescript
import { generateThemePair, generateColorScale } from 'vue-multiple-themes'; const { light, dark } = generateThemePair('#6366f1'); const scale = generateColorScale('#6366f1', 9);

Ideal for SaaS products where each tenant sets a brand color and the full UI adapts automatically.

TailwindCSS Integration

javascript
const { createVmtPlugin } = require('vue-multiple-themes/tailwind'); module.exports = { plugins: [createVmtPlugin()] };
html
<div class="bg-vmt-surface text-vmt-foreground border-vmt-border"> Themes itself automatically on switch </div>

WCAG Utilities

Pure functions, no DOM, fully SSR-safe, tree-shakeable:

typescript
import { contrastRatio, autoContrast, checkContrast, lighten, darken } from 'vue-multiple-themes'; contrastRatio('#6366f1', '#ffffff'); // 4.54 autoContrast('#6366f1'); // '#ffffff' checkContrast('#6366f1', '#ffffff'); // { ratio: 4.54, aa: true, aaa: false, aaLarge: true, aaaLarge: true }

useTheme() API

OptionTypeDefaultDescription
themesThemeDefinition[]preset listAvailable themes
defaultThemestringlightInitial theme
strategyattribute / class / bothattributeDOM application strategy
persistbooleantrueSave to localStorage
storageKeystringvmt-themelocalStorage key

Returns: { currentTheme, currentName, themes, setTheme, nextTheme, prevTheme }

Vue 2 Support

javascript
import Vue from 'vue'; import { VueMultipleThemesPlugin } from 'vue-multiple-themes'; Vue.use(VueMultipleThemesPlugin, { defaultTheme: 'light' });

GitHub · npm · Full Documentation

X / Twitter
LinkedIn
Facebook
WhatsApp
Telegram
AI Engineering for B2B

Stuck between an AI pilot and a system your team can run?

I join your engineering team and build the agent layer alongside you, covering architecture, MCP integration, evals, and production deployment. When the engagement ends, your team owns the system and keeps shipping.

12+ years shipping production systems

Senior engineer turned AI specialist. React, Next.js, AWS, agent orchestration.

Dubai-based, working with B2B teams worldwide

Direct collaboration across UAE, Europe, and US time zones.

AI agent teams that ship, not demos that stall

Discovery, role design, MCP integration, evals, and production deployment.

Questions about this piece

Follow-ups readers ask most often about the argument above.

  • Yes. The package uses vue-demi for a single installation that supports Vue 2.7+ and Vue 3. The same composable API and plugin registration work identically across both versions.

  • The useTheme() composable is localStorage-persistent by default. The storageKey option (default: vmt-theme) controls which key is used. Set persist: false to opt out.

  • Yes. generateThemePair(hex) creates a light/dark pair from any hex color. generateColorScale(hex, steps) builds a full palette. Both are tree-shakeable and work without any DOM dependency.

  • Yes. A TailwindCSS plugin is included. After registering it in tailwind.config.js you get utilities like bg-vmt-primary, text-vmt-foreground, and border-vmt-border that map to live CSS custom properties.

  • checkContrast(fg, bg) returns the contrast ratio plus pass/fail flags for AA, AAA, AA-large, and AAA-large WCAG 2.1 levels. autoContrast(color) automatically picks white or black for maximum legibility.

Get practical AI and engineering playbooks

Weekly field notes on private AI, automation, and high-performance Next.js builds. Each edition is concise, implementation-ready, and tested in production work.

Open full subscription page

Get the latest insights on AI and full-stack development.