| name | stylex |
| description | Write StyleX styles correctly — longhand properties, nested pseudo-classes/media queries, no shorthands |
StyleX Authoring Guide
Writing styles
Styles must be created using stylex.create(). Define styles as an object with namespaces containing CSS properties.
import * as stylex from '@stylexjs/stylex';
const styles = stylex.create({
container: {
display: 'flex',
alignItems: 'center',
padding: 16,
},
title: {
fontSize: 24,
fontWeight: 'bold',
color: 'navy',
},
});
CRITICAL RULES:
- Use longhand properties only. Multi-value shorthands like
border, margin, padding (with multiple values), background, flex, overflow DO NOT WORK.
- Use
null to unset properties.
- Length properties are in pixels by default (numbers without units).
Shorthand → Longhand Conversions
These shorthands DO NOT WORK in StyleX. Always expand them:
border: "1px solid var(--border-primary)",
borderWidth: 1,
borderStyle: "solid",
borderColor: "var(--border-primary)",
borderLeft: "3px solid red",
borderLeftWidth: 3,
borderLeftStyle: "solid",
borderLeftColor: "red",
margin: "8px 16px",
padding: "0.75rem 1.5rem",
marginTop: "8px",
marginRight: "16px",
marginBottom: "8px",
marginLeft: "16px",
paddingTop: "0.75rem",
paddingRight: "1.5rem",
paddingBottom: "0.75rem",
paddingLeft: "1.5rem",
paddingX: "1rem",
paddingY: "2rem",
marginX: "auto",
paddingLeft: "1rem",
paddingRight: "1rem",
paddingTop: "2rem",
paddingBottom: "2rem",
marginLeft: "auto",
marginRight: "auto",
background: "linear-gradient(to right, red, blue)",
backgroundImage: "linear-gradient(to right, red, blue)",
flex: "1 0 auto",
flexGrow: 1,
flexShrink: 0,
flexBasis: "auto",
overflow: "hidden auto",
overflowX: "hidden",
overflowY: "auto",
padding: 16,
margin: 0,
borderRadius: 8,
overflow: "hidden",
Allowed single-value shorthands
These work because they set a single value:
padding: 16 (all sides same value)
margin: 0 (all sides same value)
borderRadius: 8 (all corners same value)
overflow: "hidden" (both axes same value)
gap: 8 (both row and column gap)
Applying styles
Convert StyleX style objects to props using stylex.props():
function Component() {
return (
<div {...stylex.props(styles.container)}>
<h1 {...stylex.props(styles.title)}>Hello</h1>
</div>
);
}
Merging styles
Pass multiple styles to merge them. The last style wins for conflicting properties:
<div {...stylex.props(styles.base, styles.highlighted)} />
<div {...stylex.props([styles.base, styles.highlighted])} />
Conditional styles
<div
{...stylex.props(
styles.base,
isActive && styles.active,
isDisabled && styles.disabled,
variant === 'primary' ? styles.primary : styles.secondary,
)}
/>
Passing styles as props
import type { StyleXStyles } from '@stylexjs/stylex';
type Props = {
children: React.ReactNode;
style?: StyleXStyles;
};
function Card({ children, style }: Props) {
return <div {...stylex.props(styles.card, style)}>{children}</div>;
}
Pseudo-classes and pseudo-elements
Nest inside property values — NEVER at the top level:
const styles = stylex.create({
button: {
':hover': {
backgroundColor: 'blue',
},
},
});
const styles = stylex.create({
button: {
backgroundColor: {
default: 'lightblue',
':hover': 'blue',
':active': 'darkblue',
':focus-visible': 'royalblue',
':disabled': 'gray',
},
cursor: {
default: 'pointer',
':disabled': 'not-allowed',
},
},
});
Pseudo-elements as top-level keys within a namespace:
const styles = stylex.create({
input: {
color: 'black',
'::placeholder': {
color: 'gray',
},
},
});
Media queries
Nest inside property values — NEVER at the top level:
const styles = stylex.create({
container: {
'@media (min-width: 768px)': {
padding: 16,
},
},
});
const styles = stylex.create({
container: {
padding: {
default: 8,
'@media (min-width: 768px)': 16,
},
},
});
The default key is required when using nested conditions.
Dynamic styles
Use arrow functions for runtime values:
const styles = stylex.create({
bar: (width: number) => ({
width,
}),
positioned: (x: number, y: number) => ({
transform: `translate(${x}px, ${y}px)`,
}),
});
<div {...stylex.props(styles.bar(100))} />
Keyframe animations
const fadeIn = stylex.keyframes({
from: { opacity: 0 },
to: { opacity: 1 },
});
const styles = stylex.create({
animated: {
animationName: fadeIn,
animationDuration: '0.3s',
animationTimingFunction: 'ease-out',
},
});
Variables and Constants
Use stylex.defineVars() for themed values, stylex.defineConsts() for static values. Must be in .stylex.ts files with named exports only.
export const colors = stylex.defineVars({
primary: 'blue',
background: 'white',
});
export const breakpoints = stylex.defineConsts({
small: '@media (max-width: 600px)',
large: '@media (min-width: 1025px)',
});
Common antipatterns
- Don't use multi-value shorthands —
border, margin: "8px 16px", padding: "0 1rem", background, flex: "1 0 auto" all fail silently
- Don't use
paddingX/paddingY/marginX/marginY — these are NOT valid CSS or StyleX properties and produce 0px silently
- Don't nest pseudo-classes/media queries at top level — they must be inside property values
- Don't import non-StyleX values into
stylex.create() — use defineVars/defineConsts instead
- Don't mix
className/style props with stylex.props()
- Don't use
:focus — use ':focus-visible' for keyboard focus styling (better accessibility)