Defining styles
StyleX uses an expressive JavaScript API that is similar to working with inline styles in React DOM, or styles in React Native.
Constraints
Since StyleX depends on ahead-of-time compilation, it is important for all your styles to be statically analyzable. This means that every "Raw Style Object" must only contain:
- Plain Object Literals
- String Literals
- Number Literals
- Array Literals
null
orundefined
- Constants, simple expressions, and built-in methods (e.g.,
.toString()
) that resolve to one of the above. - And arrow functions for dynamic styles
The following are not allowed:
- Function calls (except StyleX functions)
- Values imported from other modules (except for CSS Variables created using
StyleX from a
.stylex.js
file.)
Creating styles
Styles must be created with the stylex.create
function. You can define one or
more "namespaces", or objects of styles. In the example below, there are 2
"namespaces" - one called base
and the other highlighted
. The names are
arbitrary and represent the constant used to capture the result of the
create()
function call.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
base: {
fontSize: 16,
lineHeight: 1.5,
color: 'rgb(60,60,60)',
},
highlighted: {
color: 'rebeccapurple',
},
});
Pseudo-classes
Pseudo-classes represent different states of an element. In StyleX, declarations
for pseudo-classes are nested within properties. For example, let's say we have
a button that currently has a lightblue
background.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
button: {
backgroundColor: 'lightblue',
},
});
If we want to add pseudo-classes to change the background color for different
states, we replace the lightblue
string literal with an object of
pseudo-states.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
button: {
backgroundColor: {
default: 'lightblue',
':hover': 'blue',
':active': 'darkblue',
},
},
});
Pseudo-elements
We recommend avoiding pseudo-elements when possible and relying on actual HTML
elements instead, i.e., replace ::before
and ::after
with elements like
div
or span
. This helps reduce the size of your CSS bundle.
Pseudo-elements are a way of targeting shadow DOM elements contained within the
native HTML elements provided by user agents. For example, ::placeholder
references the element that contains placeholder text within an input
or
textarea
element. To target pseudo-elements in StyleX, they must be defined as
a top-level key within a namespace.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
input: {
// pseudo-element
'::placeholder': {
color: '#999',
},
color: {
default: '#333',
// pseudo-class
':invalid': 'red',
},
},
});
Media queries (and other @
rules)
Media Queries can, similarly, be as "conditions" within style values.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
base: {
width: {
default: 800,
'@media (max-width: 800px)': '100%',
'@media (min-width: 1540px)': 1366,
},
},
});
Combining conditions
Your Style Values can be nested more than one level deep when you need to combine Media Queries and Pseudo Selectors
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
button: {
color: {
default: 'var(--blue-link)',
':hover': {
default: null,
'@media (hover: hover)': 'scale(1.1)',
},
':active': 'scale(0.9)',
},
},
});
The default
case is required when authoring conditional styles. If you don't
want any style to be applied in the default case, you can use null
as the
value.
Using null
for a non-default
condition has no effect and should be
considered invalid.
Fallback styles
There are situations in StyleX where, when you need fallback styles for browsers that don't support a certain new style property.
In CSS you may do something like this:
.header {
position: fixed;
position: -webkit-sticky;
position: sticky;
}
This kind of syntax is not possible when using JavaScript objects. So in StyleX
you can use the firstThatWorks
function to achieve the same thing.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
header: {
position: stylex.firstThatWorks('sticky', '-webkit-sticky', 'fixed'),
},
});
Keyframe animations
You can use the stylex.keyframes()
function to define keyframe animations.
import * as stylex from '@stylexjs/stylex';
const fadeIn = stylex.keyframes({
from: {opacity: 0},
to: {opacity: 1},
});
const styles = stylex.create({
base: {
animationName: fadeIn,
animationDuration: '1s',
},
});
Dynamic styles
Dynamic styles are an advanced feature and should be used sparingly. For the majority of use-cases, conditional styles should be sufficient.
StyleX generates all styles at compile-time which means you need to know all those styles ahead of time as well. But sometimes you just don't know what you will need until runtime.
For such situations, you can define your styles as a function instead of an object and pass in the dynamic components of the needed styles as parameters.
NOTE: The function body must be an object literal. You cannot use a function body with multiple statements.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
// Function arguments must be simple identifiers
// -- No destructuring or default values
bar: (height) => ({
height,
// The function body must be an object literal
// -- { return {} } is not allowed
}),
});
function MyComponent() {
// The value of `height` cannot be known at compile time.
const [height, setHeight] = useState(10);
return <div {...stylex.props(styles.bar(height))} />;
}
Behind the scenes, StyleX will generate static styles that depend on a CSS variable and set the value of that variable at runtime. This means, that any part of your styles can be dynamic, including within Media Queries and pseudo-classes.