tailwind-dictionary
v2.3.2
Published
Creating a Tailwind Theme from design tokens
Maintainers
Readme
Tailwind Dictionary
Tailwind Dictionary is a package based on Style Dictionary that allows creating a Tailwind Theme from design tokens.
Installation
$ npm install tailwind-dictionary --save-dev
# or
$ yarn add tailwind-dictionary --devUsage
$ tailwind-dictionary| Flag | Short Flag | Description | | ----------------- | ---------- | ------------------------------------------------ | | --config [path] | -c | Set the config file to use. Must be a .json file |
Example
As an example of usage, you can look at the pbstyles style library.
config.json
{
"version": 4,
"source": ["tokens/**/*.json"],
"output": "./styles",
"themeAliases": { ... }
}| Property | Type | Required | Description |
| :----------- | :----- | :------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| version | Number | yes | Tailwind CSS version (3 or 4). Default is 4. |
| source | Array | yes | An array of file path globs to design token files. Exactly like Style Dictionary. |
| output | String | yes | Base path to build the files, must end with a trailing slash. By default is "./styles". |
| themeAliases | Object | yes | Aliases for the Tailwind Theme. Complete theme and documentation. |
| themes | Object | no | Optional light/dark theme override token files and prefix for semantic CSS variables (v4). See Dark theme section below. |
Example of theme aliases
The entire list of keys for the Tailwind theme can be found in the documentation or the full default theme. The most important thing is to use the same keys in the config for the theme as in the original theme, such as “fontFamily”.
Aliases must include a category for CTI, for example rounded. They can also include both a category and a type, for instance font/family, where font is the category and family is the type.
Config for Tailwind version 4
{
...
"themeAliases": {
"font": "font/family",
"font-weight": "font/weight",
"leading": "font/leading",
"text": "font/size",
"color": "color",
"spacing": "1px",
"radius": "rounded",
"shadow": "shadow",
"breakpoint": "screen",
"animation": "animation",
"keyframes": "keyframes"
}
}Config for Tailwind version 3
{
...
"themeAliases": {
"fontFamily": "font/family",
"fontWeight": "font/weight",
"lineHeight": "font/leading",
"fontSize": "font/size",
"colors": "color",
"screens": "screen",
"spacing": "size",
"borderRadius": "rounded",
"borderWidth": "stroke",
"extend": {
"opacity": "opacity",
"boxShadow": "shadow",
"spacing": "container"
}
}
}Design-tokens
{
"font": {
"family": {
"sans": { "value": "Inter, sans-serif" }
},
"weight": {
"regular": { "value": 400 },
"medium": { "value": 600 },
"bold": { "value": 700 }
},
"leading": {
"none": { "value": 1 },
"tight": { "value": 1.25 },
"normal": { "value": 1.5 }
}
},
"rounded": {
"0": { "value": "0px" },
"4": { "value": "4px" },
"6": { "value": "6px" },
"8": { "value": "8px" },
"999": { "value": "999px" }
}
}Tailwind Theme version 4
@theme {
--*: initial;
--font-sans: 'Inter', sans-serif;
--font-weight-regular: 400;
--font-weight-medium: 600;
--font-weight-bold: 700;
--leading-none: 1;
--leading-tight: 1.25;
--leading-normal: 1.5;
--spacing: 1px;
--radius-0: 0px;
--radius-4: 4px;
--radius-6: 6px;
--radius-8: 8px;
--radius-999: 999px;
}Tailwind Theme version 3
module.exports = {
fontFamily: {
sans: 'Inter, sans-serif',
},
fontWeight: {
regular: 400,
medium: 600,
bold: 700,
},
lineHeight: {
none: 1,
tight: 1.25,
normal: 1.5,
},
borderRadius: {
0: '0px',
4: '4px',
6: '6px',
8: '8px',
999: '999px',
},
};Example of dark theme
Config for Tailwind version 4
{
...
"themes": {
"light": ["tokens/themes/light.json"],
"dark": ["tokens/themes/dark.json"]
}
}Semantic tokens are exposed as plain CSS variables --<prefix>-<key>-<name>, where key is the theme alias key (color, radius, …). Optional prefix (e.g. "prefix": "app") replaces the default theme prefix: --app-color-background instead of --theme-color-background.
Config for Tailwind version 3
{
...
"themes": {
"light": ["tokens/themes/light.json"],
"dark": ["tokens/themes/dark.json"]
}
}Design-tokens
{
"color": {
"background": { "value": "#ffffff" },
"foreground": { "value": "#0f0f0f" }
}
}tokens/themes/dark.json:
{
"color": {
"background": { "value": "#0f0f0f" },
"foreground": { "value": "#ffffff" }
}
}Tailwind Theme version 4
Semantic tokens (the ones overridden by the dark theme) are declared as plain CSS variables --<prefix>-<key>-<name> (default prefix is theme) in :root with dark overrides on the same names, and mapped into the theme via @theme inline. Utilities compile to var(--<prefix>-<key>-<name>) directly, so the dark theme works on any DOM level (data-theme="dark" on a nested container) and with any Tailwind prefix (@import 'tailwindcss' prefix(tw)). Non-semantic tokens stay in the regular @theme block.
Theme switching works the same way in both versions:
- no attribute — follows the system
prefers-color-scheme; data-theme="dark"— forces the dark theme on the element and its subtree;data-theme="light"— forces the light theme: on<html>it overrides a dark system scheme, on a nested element it creates a light container inside a dark page.
:root {
--theme-color-background: #ffffff;
--theme-color-foreground: #0f0f0f;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme='light']) {
--theme-color-background: #0f0f0f;
--theme-color-foreground: #ffffff;
}
}
[data-theme='dark'] {
--theme-color-background: #0f0f0f;
--theme-color-foreground: #ffffff;
}
[data-theme='light'] {
--theme-color-background: #ffffff;
--theme-color-foreground: #0f0f0f;
}
@theme {
--*: initial;
--color-*: initial;
}
@theme inline {
--color-background: var(--theme-color-background);
--color-foreground: var(--theme-color-foreground);
}Tailwind Theme version 3
theme.js with semantic token values replaced by var() references:
module.exports = {
colors: {
background: 'var(--color-background)',
foreground: 'var(--color-foreground)',
},
};theme.css generated alongside theme.js:
:root {
--color-background: #ffffff;
--color-foreground: #0f0f0f;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme='light']) {
--color-background: #0f0f0f;
--color-foreground: #ffffff;
}
}
[data-theme='dark'] {
--color-background: #0f0f0f;
--color-foreground: #ffffff;
}
[data-theme='light'] {
--color-background: #ffffff;
--color-foreground: #0f0f0f;
}Usage in a Tailwind theme version 4
@import 'tailwindcss';
@import './styles/tailwind/theme.css';Example of typography mixins
Config
{
...
"themeAliases": {
...
"text": "font/size",
...
}
}Design-tokens
{
"font": {
"size": {
"12": { "value": "{size.12}" },
"16": { "value": "{size.16}" },
"20": { "value": "{size.20}" }
},
"h64": {
"font-size": {
"value": "64px",
"mixin": "h64"
},
"line-height": {
"value": "1.25",
"mixin": "h64"
},
"font-weight": {
"value": "700",
"mixin": "h64"
}
}
}
}Tailwind Theme
@theme {
--text-12: 12px;
--text-16: 16px;
--text-20: 20px;
--text-h64: 64px;
--text-h64--line-height: 1.25;
--text-h64--font-weight: 700;
}Example of media query
Config
{
...
"themeAliases": {
...
"breakpoint": "screen",
...
}
}Design-tokens
{
"screen": {
"xl": {
"min": { "value": "1441px" }
},
"lg": {
"max": { "value": "1440px" },
"min": { "value": "921px" }
}
}
}Tailwind Theme
@theme {
--breakpoint-xl: 1441px;
--breakpoint-lg-max: 1440px;
--breakpoint-lg-min: 921px;
}Example of animation
Config
{
...
"themeAliases": {
...
"animation": "animation",
"keyframes": "keyframes"
}
}Design-tokens
{
"animation": {
"show": {
"value": "show 300ms ease-in forwards"
}
},
"keyframes": {
"show": {
"from": {
"opacity": {
"value": 0,
"mixin": "show"
}
},
"to": {
"opacity": {
"value": 1,
"mixin": "show"
}
}
}
}
}Tailwind Theme
@theme {
--animation-show: show 300ms ease-in forwards;
@keyframes show {
from: {
opacity: 0;
}
to: {
opacity: 1;
}
}
}Usage in a Tailwind theme version 3
const theme = require('./styles/tailwind');
module.exports = {
...
theme: {
...theme,
extend: {
...theme.extend,
},
},
...
};Example of typography mixins
Config
{
...
"themeAliases": {
...
"fontSize": "font/size",
...
}
}Design-tokens
{
"font": {
"size": {
"12": { "value": "{size.12}" },
"16": { "value": "{size.16}" },
"20": { "value": "{size.20}" }
},
"h64": {
"font-size": {
"value": "64px",
"mixin": "h64"
},
"line-height": {
"value": "1.25",
"mixin": "h64"
},
"font-weight": {
"value": "700",
"mixin": "h64"
}
}
}
}Tailwind Theme
module.exports = {
fontSize: {
12: '12px',
16: '16px',
20: '20px',
h64: ['64px', { lineHeight: 1.25, fontWeight: 700 }],
},
};Example of media query
Config
{
...
"themeAliases": {
...
"screens": "screen",
...
}
}Design-tokens
{
"screen": {
"xl": {
"min": { "value": "1441px" }
},
"lg": {
"max": { "value": "1440px" },
"min": { "value": "921px" }
}
}
}Tailwind Theme
module.exports = {
screens: {
xl: { min: '1441px' },
lg: { max: '1440px', min: '921px' },
},
};Example of animation
Config
{
...
"themeAliases": {
...
"extend": {
"animation": "animation",
"keyframes": "keyframes"
}
}
}Design-tokens
{
"animation": {
"show": {
"value": "show 300ms ease-in forwards"
}
},
"keyframes": {
"show": {
"from": {
"opacity": {
"value": 0,
"mixin": "show"
}
},
"to": {
"opacity": {
"value": 1,
"mixin": "show"
}
}
}
}
}Tailwind Theme
module.exports = {
extend: {
animation: {
show: 'show 300ms ease-in forwards',
},
keyframes: {
show: {
from: {
opacity: 0,
},
to: {
opacity: 1,
},
},
},
},
};