mixin-dictionary
v1.3.0
Published
Creating mixins from design tokens for LESS and SCSS.
Downloads
122
Maintainers
Readme
Mixin Dictionary
Mixin Dictionary is a package based on Style Dictionary that allows creating mixins from design tokens for LESS and SCSS, with theme support (light/dark) for CSS, LESS, and SCSS.
Installation
$ npm install mixin-dictionary --save-dev
# or
$ yarn add mixin-dictionary --devUsage
$ mixin-dictionary| Flag | Short Flag | Description | | ----------------- | ---------- | ------------------------------------------------ | | --config [path] | -c | Set the config file to use. Must be a .json file |
CSS
CSS variables are generated in :root. Mixins are not supported for CSS. Theme support works via CSS custom properties — see Theme support.
Example
As an example of usage, you can look at the pbstyles style library.
config.json
{
"platforms": ["css", "less", "scss"],
"source": ["tokens/**/*.json"],
"output": "./styles",
"mediaAliases": ["screen", "breakpoint"],
"keyframesAliases": ["keyframes"]
}| Property | Type | Default | Description |
| :--------------- | :----- | :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| platforms | Array | ["css", "less", "scss"] | Sets of platform files to be built. |
| source | Array | ["tokens/**/*.json"] | An array of file path globs to design token files. Exactly like Style Dictionary. |
| output | String | "./styles" | Base path to build the files. |
| mediaAliases | Array | ["screen", "breakpoint"] | Aliases for media queries category. |
| keyframesAliases | Array | ["keyframes"] | Aliases for keyframes animations category. |
| themes | Object | null | Optional. Light and dark theme token files. |
Theme support
Add an optional themes object to your config to enable light/dark theme output. If omitted, behavior is identical to previous versions — full backward compatibility.
config.json with themes
{
"platforms": ["css", "less", "scss"],
"source": ["tokens/*.json"],
"themes": {
"light": ["tokens/themes/light.json"],
"dark": ["tokens/themes/dark.json"]
},
"output": "./styles",
"mediaAliases": ["screen", "breakpoint"],
"keyframesAliases": ["keyframes"]
}| Property | Type | Description |
| :----------- | :--------- | :------------------------------------- |
| themes.light | string[] | File paths to light theme token files. |
| themes.dark | string[] | File paths to dark theme token files. |
Note: when using
themes, make suresourcedoes not include the theme files themselves — use a specific glob liketokens/*.jsoninstead oftokens/**/*.json. Theme files are passed separately viathemes.lightandthemes.darkto avoid token collisions.
How it works
The tool runs Style Dictionary twice — once for the light theme, once for the dark theme — and combines the results:
- Light build —
source+themes.light→ generates all platform files and mixins - Dark build —
source+themes.dark→ generates only the dark override blocks
CSS
All tokens in :root, dark overrides via both @media and [data-theme='dark']:
:root {
--color-black: #000000;
--color-basic-0: #ffffff;
/* ... all tokens ... */
}
@media (prefers-color-scheme: dark) {
:root {
--color-basic-0: #0f172a;
/* ... semantic overrides only ... */
}
}
[data-theme='dark'] {
--color-basic-0: #0f172a;
/* ... semantic overrides only ... */
}LESS
:root {
--color-basic-0: #ffffff;
/* ... semantic tokens only ... */
}
@media (prefers-color-scheme: dark) {
:root {
--color-basic-0: #0f172a;
}
}
[data-theme='dark'] {
--color-basic-0: #0f172a;
}
/* Semantic tokens reference CSS custom properties for runtime switching */
@color-basic-0: var(--color-basic-0);
/* Non-semantic tokens keep actual values */
@color-black: #000000;SCSS
:root {
--color-basic-0: #ffffff;
}
@media (prefers-color-scheme: dark) {
:root {
--color-basic-0: #0f172a;
}
}
[data-theme='dark'] {
--color-basic-0: #0f172a;
}
$color-basic-0: var(--color-basic-0);
$color-black: #000000;Example of a mixin
{
"font": {
"h64": {
"font-size": {
"value": "64px",
"mixin": "h64"
},
"line-height": {
"value": "1.25",
"mixin": "h64"
},
"font-weight": {
"value": "700",
"mixin": "h64"
}
}
}
}SCSS
$font-h64-font-size: 64px;
$font-h64-line-height: 1.25;
$font-h64-font-weight: 700;
@mixin h64 {
font-size: $font-h64-font-size;
line-height: $font-h64-line-height;
font-weight: $font-h64-font-weight;
}LESS
@font-h64-font-size: 64px;
@font-h64-line-height: 1.25;
@font-h64-font-weight: 700;
.h64() {
font-size: @font-h64-font-size;
line-height: @font-h64-line-height;
font-weight: @font-h64-font-weight;
}Example of a keyframes mixin
{
"keyframes": {
"fade": {
"from": {
"value": "opacity: 0;",
"mixin": "fade"
},
"to": {
"value": "opacity: 1;",
"mixin": "fade"
}
}
}
}SCSS
$keyframes-fade-from: opacity: 0;
$keyframes-fade-to: opacity: 1;
@mixin fade {
@include keyframes(fade) {
from { #{$keyframes-fade-from} }
to { #{$keyframes-fade-to} }
}
}LESS
@keyframes-fade-from: opacity: 0;
@keyframes-fade-to: opacity: 1;
.fade() {
.keyframes(fade, {
from { @keyframes-fade-from; }
to { @keyframes-fade-to; }
});
}Example of a media query mixin
{
"screen": {
"lg": {
"max": {
"value": "1440px",
"mixin": "lg"
},
"min": {
"value": "921px",
"mixin": "lg"
}
}
}
}SCSS
$screen-lg-max: 1440px;
$screen-lg-min: 921px;
@mixin lg {
@media all and (max-width: $screen-lg-max) and (min-width: $screen-lg-min) {
@content;
}
}LESS
@screen-lg-max: 1440px;
@screen-lg-min: 921px;
.lg(@content) {
@media all and (max-width: @screen-lg-max) and (min-width: @screen-lg-min) {
@content;
}
}