A reusable Vite plugin for Tailwind CSS 4 theming with dynamic color configuration. Inspired by Nuxt UI's theming system and made framework-agnostic.
Live Demo - See the plugin in action with interactive theme switching!
- Dynamic color theming with CSS variables
- Built-in dark/light mode support with adaptive shade shifting
- Semantic color utilities (text-default, bg-muted, border-accented)
- Custom CSS variables injection
- Framework agnostic (works with Vue, React, Svelte, etc.)
- Powered by Vite and Unplugin
- TypeScript support
- User @theme override detection
npm install tailwind-color-theme-plugin// vite.config.ts
import { defineConfig } from 'vite'
import tailwindTheme from 'tailwind-color-theme-plugin'
export default defineConfig({
plugins: [
tailwindTheme({
colors: {
primary: 'sky',
secondary: 'purple',
success: 'green',
warning: 'orange',
error: 'red',
neutral: 'gray'
}
})
]
})Import Tailwind and the theme CSS:
/* src/style.css */
@import "tailwindcss";
@import "tailwind-color-theme-plugin/theme.css";Override colors using Tailwind 4's @theme syntax:
@theme static {
--color-green-500: #00FFFF;
--color-green-600: #00E6E6;
}export interface TailwindThemeOptions {
colors?: Record<string, Color> & {
primary?: Color
secondary?: Color
success?: Color
info?: Color
warning?: Color
error?: Color
neutral?: Color
}
customVariables?: Record<string, string>
injectColors?: boolean
prefix?: string
extendTailwindTheme?: boolean
includeSemanticColors?: boolean
adaptiveShades?: boolean
}colors- Theme color configuration using Tailwind color namescustomVariables- Additional CSS variables to injectinjectColors- Whether to inject colors via JavaScript (default: true)prefix- CSS variable prefix (default: 'ui')extendTailwindTheme- Enable Tailwind theme extension (default: true)includeSemanticColors- Include semantic utilities (default: true)adaptiveShades- Enable adaptive shade shifting in dark mode (default: true)
<!-- Theme colors with shades -->
<button class="bg-primary-500 text-white">Primary Button</button>
<div class="text-secondary-600 border-success-300">Colored content</div>
<!-- Adaptive colors (automatically shift shades in dark mode) -->
<button class="bg-primary text-inverted">Adaptive Button</button>
<div class="text-secondary border-success">Adaptive content</div>
<!-- Semantic utilities -->
<p class="text-default">Default text</p>
<p class="text-muted">Muted text</p>
<div class="bg-elevated border-default">Elevated card</div>
<div class="bg-muted border-accented">Muted card</div>/* Theme colors */
--ui-primary: /* adaptive primary color */
--ui-secondary: /* adaptive secondary color */
--ui-color-primary-500: /* primary 500 shade */
/* Semantic colors */
--ui-text: /* default text color */
--ui-text-muted: /* muted text color */
--ui-bg: /* default background */
--ui-bg-elevated: /* elevated background */
--ui-border: /* default border color */The plugin automatically handles dark mode with adaptive shade shifting:
- Light mode: Primary uses shade 500
- Dark mode: Primary uses shade 400 (lighter for better contrast)
Toggle dark mode:
document.documentElement.classList.toggle('dark')Disable adaptive shades:
tailwindTheme({
adaptiveShades: false // Use same shade in both light and dark mode
})Framework-agnostic semantic utilities:
text-default- Primary texttext-muted- Secondary texttext-toned- Subtle texttext-dimmed- Disabled texttext-highlighted- Emphasized texttext-inverted- Inverted text
bg-default- Default backgroundbg-muted- Muted backgroundbg-elevated- Elevated/card backgroundbg-accented- Accented backgroundbg-inverted- Inverted background
border-default- Default borderborder-muted- Muted borderborder-accented- Accented borderborder-inverted- Inverted border
Inject additional CSS variables:
tailwindTheme({
customVariables: {
'border-radius': '0.5rem',
'font-family': '"Inter", sans-serif',
'spacing-unit': '4px'
}
})Available as --ui-border-radius, --ui-font-family, etc.
The plugin automatically detects user @theme overrides and excludes those colors from generation:
@theme static {
--color-green-500: #00FFFF;
--color-green-600: #00E6E6;
}Check out the example/ directory for a complete implementation showing:
- Color palette showcase
- Semantic design system demonstration
- Dark mode functionality
- Dynamic theme switching with ThemePicker component
- Tailwind 4 @theme syntax usage
The example includes a ThemePicker component that demonstrates how to build dynamic color switching functionality.
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindTheme from 'tailwind-color-theme-plugin'
export default defineConfig({
plugins: [vue(), tailwindTheme()]
})import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindTheme from 'tailwind-color-theme-plugin'
export default defineConfig({
plugins: [react(), tailwindTheme()]
})import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
import tailwindTheme from 'tailwind-color-theme-plugin'
export default defineConfig({
plugins: [svelte(), tailwindTheme()]
})- Vite 6.0+ or 7.0+
- Tailwind CSS 4.0+
- Node.js 18+
- Nuxt UI: For the Main Inspiration for this plugin and their incredible Theming System
MIT