Skip to main content

Release 0.9.3

· 5 min read
Naman Goel

StyleX v0.9.3 is now available with some big improvements and bug-fixes.

Improvements to Theming APIs

There are some big improvements to the predictability and reliability of our theming APIs — stylex.defineVars and stylex.createTheme.

Breaking Change: Themes are now exclusive

When you create a VarGroup with stylex.defineVars, you are able to theme any subset of the variables within using the stylex.createTheme API. These themes can then be applied like any other StyleX styles using stylex.props (or stylex.attrs). If you try to apply multiple themes for the same VarGroup, on the same element, the last applied theme wins, just as you might expect.

However, previously, if you instead applied one theme on a parent element, and another theme on a child element, the themes would end up being merged.

// tokens.stylex.ts
import * as stylex from '@stylexjs/stylex';

export const varGroup = stylex.defineVars({
primary: 'black',
secondary: 'grey',
});
import * as stylex from '@stylexjs/stylex';
import {varGroup} from './tokens.stylex.ts';

const red = stylex.createTheme(varGroup, {
primary: 'red',
});

const blue = stylex.createTheme(varGroup, {
secondary: 'blue',
});

const styles = stylex.create({
primary: {color: varGroup.primary},
secondary: {color: varGroup.secondary},
});

function App() {
return (
<div {...stylex.props(red)}>
<div {...stylex.props(blue)}>
<span {...stylex.props(styles.primary)}>Hello </span>
<span {...stylex.props(styles.secondary)}>World!</span>
</div>
</div>
);
}

Previously this would have resulted in the text "Hello World!" being styled with a red primary color and a blue secondary color. Now, the text will be styled with a black primary color and a blue secondary color.

You can think of themes conceptually as re-applying the default values for any variables that are not explicitly overridden by the theme. This change simplifies the mental model for how themes work, and has the added benefit of making it easy to create "reset" themes:

const reset = stylex.createTheme(varGroup, {});
tip

You can define this "reset" theme multiple times within your app and they will all be de-duplicated by the compiler. We encourage you to "repeat yourself"!

rootDir is now optional!

Previously, when configuring the StyleX Babel plugin, you had to explicitly specify a rootDir value. Internally, this path was used to generate a canonical file path for every .stylex.js file in your project.

However, this was not only cumbersome, but it also resulted in errors when importing VarGroups from node_modules. Different package managers deal with packages differently, and this can be particularly consequential for mono-repos.

Now, the rootDir option is optional, and StyleX will use the nearest package.json file to determine the canonical path, automatically. This should make theming APIs work more reliably.

note

When determining the canonical path, StyleX will use the name field from the nearest package.json file and the relative path to the .stylex.js file. We intentionally ignore the version number.

This means that your project happens to contain multiple versions of the same package, StyleX will only generate a single set of variables for them. This will usually be the desired behavior, but you may see some unexpected results if the variables within the two versions are different.

We will be making further improvements to minimize any such edge-cases.

More reliable ESM resolution

The StyleX Babel plugin now uses the esm-resolve package to resolve ESM imports. This should fix most situations where the compiler would fail to resolve VarGroup imports in result in the compilation of stylex.create to fail.

Thanks hipstersmoothie!

Dynamic style improvements

Dynamic Styles within StyleX have been improved to be more reliable and efficient. Previously, if the dynamic value of a style resolved to null at runtime, StyleX would represent that with the revert keyword in CSS. This did not always work as expected, ran into certain browser bugs and resulted in styles that were unnecessarily bloated.

In v0.9.3, null values for Dynamic styles work exactly the same as using null as a static value within stylex.create. This means any previously applied value for the given property will be removed and no className will be applied for that property.

@stylexjs/dev-runtime overhaul

The @stylexjs/dev-runtime package is a development-only package that lets you use a much slower version of StyleX that runs entirely at runtime. Previously, it worked by patching the main @stylexjs/stylex package at runtime. However, this did not always work reliably.

Breaking Change: The @stylexjs/dev-runtime package now returns the StyleX API.

import makeStyleX from '@stylexjs/dev-runtime';

const stylex = makeStyleX({
// configuration options
classNamePrefix: 'x',
dev: true,
test: false,
});

const styles = stylex.create({
color: 'red',
});
danger

The @stylexjs/dev-runtime only exists as a convenience for development purposes. It does not completely match the behavior of the StyleX compiler and will always lack certain features.

DO NOT use it in production.

Improved handling of nested pseudo-elements and pseudo-classes

Fixed a bug where using Pseudo Classes (such as :hover) within Pseudo Elements (such as ::before) (or vice-versa) would sometimes result in surprising behavior. StyleX now handles such cases, with an arbitrary level of nesting, correctly.

Miscellaneous

  • Added support for additional Pseudo Elements and Pseudo Classes to our ESLint rule and type definitions.
  • Slightly better compiler error messages.