Style Composition
Style composition is a special feature of vanilla-extract that makes it easy to get maximum re-use from your styles. It allows you to pass an array of class names and/or styles but continue to treat them as if they are a single class name.
import { style } from '@vanilla-extract/css';
const base = style({ padding: 12 });
const primary = style([base, { background: 'blue' }]);
const secondary = style([base, { background: 'aqua' }]);
.styles_base__1hiof570 {
padding: 12px;
}
.styles_primary__1hiof571 {
background: blue;
}
.styles_secondary__1hiof572 {
background: aqua;
}
Let’s look at how this works in practice.
When you create a style you receive a class name back in return.
import { style } from '@vanilla-extract/css';
// base = 'styles_base__8uideo0'
const base = style({ padding: 12 });
.styles_base__1hiof570 {
padding: 12px;
}
However, when using style composition you will receive multiple classes in a single string, separated by a single space character, often referred to as a classlist.
import { style } from '@vanilla-extract/css';
// base = 'styles_base__8uideo0'
const base = style({ padding: 12 });
// primary = 'styles_base__8uideo0 styles_primary__8uideo1'
const primary = style([base, { background: 'blue' }]);
.styles_base__1hiof570 {
padding: 12px;
}
.styles_primary__1hiof571 {
background: blue;
}
This doesn’t affect usage when assigning to the class property on DOM elements as they already accept a classlist. However, what if we want to use our style inside another styles selector?
import { style } from '@vanilla-extract/css';
const base = style({ padding: 12 });
const primary = style([base, { background: 'blue' }]);
const text = style({
selectors: {
[`${primary} &`]: {
color: 'white'
}
}
});
.styles_base__1hiof570 {
padding: 12px;
}
.styles_primary__1hiof571 {
background: blue;
}
.styles_primary__1hiof571 .styles_text__1hiof572 {
color: white;
}
When selectors are processed internally, the composed classes are removed, only leaving behind a single unique identifier class. This allows you to treat them as if they were a single class within vanilla-extract selectors.
To ensure that this behaviour works as expected, when multiple pre-existing classes are composed, a new identifier is created and added to the classlist.
import { style, globalStyle } from '@vanilla-extract/css';
const background = style({ background: 'mintcream' });
const padding = style({ padding: 12 });
// container = 'styles_container__8uideo2'
export const container = style([background, padding]);
globalStyle(`${container} *`, {
boxSizing: 'border-box'
});
.styles_background__1hiof570 {
background: mintcream;
}
.styles_padding__1hiof571 {
padding: 12px;
}
.styles_container__1hiof572 * {
box-sizing: border-box;
}