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, {});
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
VarGroup
s 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.
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',
});
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.