Migrating to v2
v2.0.0 changes three behaviors and adds one required peer dependency. Most codebases only need the install step.
Install the new peer dependency
@emotion/css is now required. It backs className() and classNames, and it is imported unconditionally — so it is needed even if you only ever use the css prop.
- pnpm add emotion-variants @emotion/react
+ pnpm add emotion-variants @emotion/react @emotion/cssundefined now falls back to defaultVariants
In v1 the config and props were merged with object spread, so an explicit undefined erased the default. v2 resolves each key with ??.
const button = ev({
variants: {
size: {
small: {},
large: {},
},
},
defaultVariants: {
size: 'small',
},
});
button({ size: undefined });
// v1: no size style at all
// v2: 'small'What to remove. Any workaround that stripped undefined before calling, or that duplicated the default at the prop boundary:
function Button({ size }: Props) {
- const variants = size !== undefined ? { size } : {};
- return <button css={button(variants)}>Click</button>;
+ return <button css={button({ size })}>Click</button>;
}- function Button({ size = 'small' }: Props) {
+ function Button({ size }: Props) {
return <button css={button({ size })}>Click</button>;
}false and 0 are unaffected — they are real variant values and were never replaced by the default.
The call always returns an array
v1 returned Interpolation<unknown>, which was a bare SerializedStyles object when exactly one style matched. v2 always returns SerializedStyles[].
- (variants?: EvVariants<T>): Interpolation<unknown>;
+ (variants?: EvVariants<T>): SerializedStyles[];The css prop accepts both, so css={button(...)} needs no change. Code that inspected the result does:
- const styles = button({ size: 'large' });
- const list = Array.isArray(styles) ? styles : [styles];
+ const list = button({ size: 'large' });classNames returns real class names
In v1 every entry was the string "[object Object]" — String() applied to a SerializedStyles. v2 injects each style through @emotion/css and returns the generated class.
button.classNames.variants.size.small;
// v1: '[object Object]'
// v2: 'css-def456'Nothing is injected until you first read classNames, and the result is memoized, so css-prop-only code pays nothing.
If you worked around the old behavior by building class names yourself, delete that code. Note that classNames still covers base and single variant values only — for compound variants use className().
New: className(variants)
v2 adds a method returning one class for the whole combination, including compound variants. Useful for className props and non-React code.
<button className={button.className({ size: 'large', color: 'primary' })}>Click me</button>;New: EvClassNames type
EvClassNames<T> is now exported. See Types.