@themeshift/vite-plugin
v0.4.0
Published
Vite plugin wrapper for ThemeShift core token tooling.
Readme
@themeshift/vite-plugin
ThemeShift is a Vite plugin that makes working with Style Dictionary easy as pie 🥧
Migration note: this package was renamed from
@themeshift/vite-plugin-themeshiftto@themeshift/vite-plugin.
It watches your token files, rebuilds generated outputs, and gives you a simple token() helper for Sass. It can also start from tokens published by a UI package and layer app-level overrides on top.
This package lives inside the ThemeShift monorepo. Use the repo root for local development and apps/ui-app to test the full flow with @themeshift/ui.
What it does
- Watches
tokens/**/*.json - Builds CSS variables, Sass tokens, and token manifests
- Supports
light,dark, and optionalprintthemes - Injects a global Sass
token()helper - Ships a standalone Sass and JavaScript
tokenmodule - Lets apps extend tokens from installed packages such as
@themeshift/ui
Quick start
Install the package and the tools it needs:
npm install --save-dev @themeshift/vite-plugin sassAdd the plugin to vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { themeShift } from '@themeshift/vite-plugin';
export default defineConfig({
plugins: [react(), themeShift()],
});Create tokens/theme.json:
{
"theme": {
"text": {
"base": { "$value": "#0f172a" }
}
}
}Import the generated CSS:
import './css/tokens.css';By default, ThemeShift writes:
src/css/tokens.csssrc/sass/_tokens.static.scsssrc/design-tokens/token-paths.{json,ts}src/design-tokens/token-values.{json,ts}
Common Sass usage
ThemeShift injects a global token() helper by default, so this works in app styles:
.button {
color: token('text.primary');
}If you prefer an explicit import, use the published Sass module:
@use '@themeshift/vite-plugin/token' as themeShift;
.button {
color: themeShift.token('text.primary');
}If you use cssVarPrefix, you can pass it per call:
@use '@themeshift/vite-plugin/token' as themeShift;
.button {
color: themeShift.token('components.button.font', 'themeshift');
}For shared mixins and partials, prefer the namespaced import:
@use '@themeshift/vite-plugin/token' as themeShift;
@mixin text-style($path) {
font: themeShift.token('typography.styles.#{$path}.font');
}JavaScript helpers
ThemeShift ships a JavaScript helper on the same ./token path.
Use token() to read the current CSS variable value in the browser:
import { token } from '@themeshift/vite-plugin/token';
const textColor = token('text.primary', { prefix: 'themeshift' });Use tokenValue() to read a value from the generated token manifest:
import { tokenValue } from '@themeshift/vite-plugin/token';
import { tokenValues } from './design-tokens/token-values';
const titleStyle = tokenValue('text.style.title', { values: tokenValues });Color functions
ThemeShift also provides functions for modifying colours.
Supported functions:
mix(color1, color2, amount)lighten(color, amount)darken(color, amount)alpha(color, amount)
Example:
{
"components": {
"button": {
"light": {
"intents": {
"primary": {
"bg": { "$value": "{color.blue.400}" },
"hover": { "$value": "lighten({color.blue.300}, 0.1)" },
"pressed": { "$value": "darken({color.blue.500}, 0.1)" }
}
}
}
}
}
}amount must be between 0 and 1.
Hybrid token nodes
ThemeShift supports token nodes with both a main value and nested child token values. This is useful for state tokens such as bg.hover and fg.disabled.
Example:
{
"components": {
"button": {
"light": {
"intents": {
"primary": {
"bg": {
"$value": "{color.blue.400}",
"hover": { "$value": "{color.blue.300}" },
"disabled": { "$value": "alpha({color.blue.300}, 0.3)" }
},
"fg": {
"$value": "{color.blue.400.text}",
"disabled": { "$value": "alpha({color.blue.400.text}, 0.5)" }
}
}
}
}
}
}
}This gives you token paths like:
components.button.light.variant.primary.backgroundcomponents.button.light.variant.primary.background.hovercomponents.button.light.variant.primary.textcomponents.button.light.variant.primary.text.disabled
Theme modes
To support theme modes, split your token files by theme:
tokens/theme.light.json
{
"theme": {
"light": {
"text": {
"base": { "$value": "#0f172a" }
},
"surface": {
"base": { "$value": "#ecf0f1" }
}
}
}
}tokens/theme.dark.json
{
"theme": {
"dark": {
"text": {
"base": { "$value": "#e2e8f0" }
},
"surface": {
"base": { "$value": "#2c3e50" }
}
}
}
}Then set data-theme on the document root:
<html lang="en" data-theme="dark">
...
</html>Plugin options
These are the options most apps use.
extends
Use extends to load token files from an installed package before local tokens. Local files still win.
Simple example:
themeShift({
extends: ['@themeshift/ui'],
cssVarPrefix: 'themeshift',
});Explicit package config:
themeShift({
extends: [
{
package: '@themeshift/ui',
tokensGlob: 'dist/tokens/**/*.json',
},
],
});cssVarPrefix
Use cssVarPrefix to prefix generated CSS variables.
themeShift({
cssVarPrefix: 'themeshift',
});This changes:
--components-button-font- to
--themeshift-components-button-font
groups
Use groups to control comment sections in generated tokens.css.
themeShift({
groups: [
{ label: 'Colors', match: (name) => name.startsWith('color-') },
{ label: 'Theme', match: (name) => name.startsWith('theme-') },
{ label: 'Components', match: (name) => name.startsWith('components-') },
{ label: 'Other', match: () => true },
],
});defaultTheme
Use defaultTheme when you want one theme copied into plain :root as a fallback.
themeShift({
defaultTheme: 'light',
});outputPrintTheme
Set outputPrintTheme: true if you want print theme output.
themeShift({
outputPrintTheme: true,
});outputComments
Set outputComments: true to include token descriptions in generated CSS and Sass.
themeShift({
outputComments: true,
});Example token:
{
"space": {
"4": {
"$value": "1rem",
"$description": "16px"
}
}
}filters
Use filters to choose which tokens are written to each output.
themeShift({
filters: {
scss: {
includePrefixes: ['radius-', 'spacing-', 'font-', 'text-', 'layout-'],
excludePrefixes: ['theme-', 'components-'],
},
},
});You can also use a function:
themeShift({
filters: {
scss: (token) => !token.attributes?.theme,
},
});reloadStrategy
Use reloadStrategy: 'full' if you want a full page reload instead of HMR when token files change.
themeShift({
reloadStrategy: 'full',
});log
Use log to show or hide Style Dictionary output.
Show warnings:
themeShift({
log: { warnings: 'warn' },
});Keep output quiet:
themeShift({
log: { verbosity: 'silent', warnings: 'disabled' },
});Playground
This repo includes a small playground in playground/.
npm install
npm -C playground install
npm run playgroundDevelopment
Run the package in watch mode:
npm run devBuild the package:
npm run buildLicense
MIT
