Skip to main content

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 or undefined
  • 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

Avoid unnecessary 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)',
},
},
});
info

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

Use Sparingly

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.