babel-plugin-theme-ui
babel plugin transformations for theme-ui themes.
yarn add babel-plugin-theme-ui --dev
You can configure the plugin in your webpack configuration as a babel-loader plugin see examples
When this option is set to false, the plugin will not transform color properties to use css variables ie var(--theme-ui-colors-primary)
a list of the color property names to be transformed to css variables. We are using internally micromatch - a glob matching for javascript/node.js and you can use matching patterns for the color properties.
a list of the theme section not the be transformed into using css variables.
if you set this option to true, the plugin will also transform the native
color names of theme-ui - such as bg
. This can offset the color lookups at build-time rather than run-time.
Currently the following property names are treated as color
style names:
"color",
"backgroundColor",
"borderColor",
"caretColor",
"columnRuleColor",
"borderTopColor",
"borderBottomColor",
"borderLeftColor",
"borderRightColor",
"outlineColor",
"fill",
"stroke",
"bg",
spaceFormats: Record<string, string | function (value: any) => string> (default { space: value => "${value}px"
,})
you can use this option and apply custom formatting to the transformed values - by default the space
values are transformed to strings by adding px
at the end.
const babelThemeUI = require('babel-plugin-theme-ui');
module: {
rules: [
{
test: /theme.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
plugins: [
[
babelThemeUI,
{
transformNativeColors: true,
useCustomProperties: false,
colorNames: ['--bg-*', '--color-*'],
rootNames: ['root', 'body'],
}
]
]
}
},
],
},
const path = require("path");
const babelThemeUI = require('babel-plugin-theme-ui');
module: {
rules: [
{
test: /index.js$/,
exclude: /node_modules/,
include: path.resolve(__dirname, "src/gatsby-plugin-theme-ui"),
loader: "babel-loader",
options: {
plugins: [
[
babelThemeUI,
{
colorNames: ["--bg-*", "--color-*"],
},
],
],
},
},
],
},
// next.config.js
const babelThemeUI = require('babel-plugin-theme-ui');
module.exports = {
webpack(config, options) {
config.module.rules.push({
test: /theme.ts$/,
use: [
options.defaultLoaders.babel,
{
loader: 'babel-loader',
options: {
presets: [['next/babel']],
plugins: [
[
babelThemeUI,
{
transformNativeColors: true,
useCustomProperties: false,
colorNames: ['--bg-*', '--color-*'],
rootNames: ['root', 'body'],
}
]
]
}
},
],
})
}
}
// .storybook/wepback.config.js
const babelThemeUI = require('babel-plugin-theme-ui').default
module.exports = async ({ config }) => {
config.module.rules.push({
test: /theme.ts$/,
use: [
{
loader: 'babel-loader',
options: {
presets: [['next/babel']],
plugins: [
[
babelThemeUI,
{
transformNativeColors: true,
useCustomProperties: false,
colorNames: ['--bg-*', '--color-*'],
rootNames: ['root', 'body'],
}
]
]
}
},
],
})
}
const babelThemeUI = require('babel-plugin-theme-ui');
module: {
rules: [
{
test: /theme.ts$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [['typescript']],
plugins: [
[
babelThemeUI,
{
transformNativeColors: true,
useCustomProperties: false,
colorNames: ['--bg-*', '--color-*'],
rootNames: ['root', 'body'],
}
]
]
}
},
],
},
secondary
and green
are child nodes of the same parent (colors
):
export const theme = {
colors: {
green:{
30: '#00aa00',
},
secondary: 'green.30'
},
};
will be transformed to
export const theme = {
colors: {
green:{
30: '#00aa00',
},
secondary: '#00aa00'
},
};
in the following example the lookup is in a global scope of the theme colors
export const theme = {
colors: {
primary: '#ffffff',
},
input: {
bg: 'primary'
},
};
will be transformed to
export const theme = {
colors: {
primary: '#ffffff',
},
input: {
bg: 'var(--theme-ui-colors-primary)',
},
};
to avoid repetitive styles for multiple theme keys:
export const theme = {
colors: {
primary: 'tomato',
},
input: {
bg: 'primary',
'--bg-random': 'primary',
border: 'solid 1px black',
},
styles: {
select: 'input',
},
};
will be transformed to
export const theme = {
colors: {
primary: "tomato",
},
input: {
bg: "primary",
"--bg-random": "var(--theme-ui-colors-primary)",
border: "solid 1px black",
},
styles: {
select: {
bg: "primary",
"--bg-random": "var(--theme-ui-colors-primary)",
border: "solid 1px black",
},
},
};
to get shortcuts into array keys in the theme, such as spaces
and fontSizes
export const theme = {
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
button: {
borderRadius: 'space.2',
},
};
will be transformed to
export const theme = {
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
button: {
borderRadius: "8px",
},
};
some of the theme-ui values are arrays - to be used based on the current screen resolution
export const theme = {
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
input: {
'--space-gap': ["space.2", "14px", "space.3", "space.4"],
},
};
will be transformed to
export const theme = {
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
input: {
"--space-gap": ["8px", "14px", "16px", "32px"],
},
};
notice above that the space.2
key is replaced with the second value in the space array, while the 14px
is left intact since it is not a valid theme key
Custom scales can be created to supplement those already existing.
Simply create a new scale, then reference it in a variant
speed: ["0.35s", "0.5s", "0.75s"],
ease: {
in: "ease-in",
out: "ease-out",
inOut: "ease-in-out",
},
a: {
color: "primary",
"--speed": "speed.1",
"--ease": "ease.out",
transition: "color var(--speed, 0.35s) var(--ease, ease)"
},
When your theme definition grows, it is common to separate the scales into their on objects that will get merged into the theme object
const scales = {
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
}
const layout = {
'--margin': 'space.3',
'--bg-random': 'primary',
ease: 'speed.2'
}
const font = {
'--margin': 'space.3',
'--color-some': 'primary',
ease: 'speed.0'
}
export default {
...scales,
speed: ["0.35s", "0.5s", "0.75"],
colors: {
primary: '#333',
secondary: '#503'
},
styles: {
h1: layout,
h2: {
...layout,
'--color-more': 'secondary',
},
h3: {
...font,
},
a: {
'--test': 'space.4',
},
},
}
will be transformed to
const scales = {
space: [0, 4, 8, 16, 32, 64, 128, 256, 512],
};
const layout = {
"--margin": "16px",
"--bg-random": "var(--theme-ui-colors-primary)",
ease: "0.75",
};
const font = {
"--margin": "16px",
"--color-some": "var(--theme-ui-colors-primary)",
ease: "0.35s",
};
export default {
...scales,
speed: ["0.35s", "0.5s", "0.75"],
colors: {
primary: "#333",
secondary: "#503",
},
styles: {
h1: layout,
h2: { ...layout, "--color-more": "var(--theme-ui-colors-secondary)" },
h3: { ...font },
a: {
"--test": "32px",
},
},
};