# How StyleX is Integrated into Astryx Components: A Complete Technical Guide

> Learn how Astryx integrates StyleX. Discover importing, defining styles with stylex.create(), and applying them using stylex.props() for efficient component styling.

- Repository: [Meta/astryx](https://github.com/facebook/astryx)
- Tags: how-to-guide
- Published: 2026-07-15

---

**Astryx integrates StyleX by importing the library into component files, defining static style objects with `stylex.create()`, and applying them at render time using `stylex.props()` merged with design-system utilities like `mergeProps()` and `themeProps()`.**

The Astryx component library leverages **StyleX** as its zero-runtime CSS-in-JS engine to generate static, type-safe styles. This integration pattern appears consistently across the facebook/astryx repository, enabling components to consume shared design tokens while supporting dynamic runtime overrides through CSS variables.

## Setting Up StyleX Imports in Component Files

Every styled component in Astryx begins by importing the StyleX library. In [`packages/lab/src/SVGIcon/SVGIcon.tsx`](https://github.com/facebook/astryx/blob/main/packages/lab/src/SVGIcon/SVGIcon.tsx), the pattern starts with:

```tsx
import * as stylex from '@stylexjs/stylex';

```

This import provides access to the core APIs including `stylex.create`, `stylex.props`, and `stylex.defineVars`. Components then import design tokens from the centralized theme definition to ensure consistency with the broader design system.

## Defining Design Tokens with stylex.defineVars

Centralized theme values live in [`packages/core/src/theme/tokens.stylex.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/theme/tokens.stylex.ts). Here, Astryx establishes **design tokens** using `stylex.defineVars` to create typed CSS custom properties:

```tsx
import {colorVars} from '@astryxdesign/core/theme/tokens.stylex';

// Referencing tokens in component logic
const iconColor = colorVars['--color-icon-primary'];

```

These variables propagate throughout the component tree, allowing a single source of truth for colors, spacing, and typography. When StyleX compiles, these definitions generate the actual CSS custom properties while maintaining TypeScript autocomplete support.

## Creating Component Styles Using stylex.create

Component-specific styles are declared using **`stylex.create`**, which returns an object mapping keys to generated class names. The implementation in [`SVGIcon.tsx`](https://github.com/facebook/astryx/blob/main/SVGIcon.tsx) demonstrates this pattern:

```tsx
const styles = stylex.create({
  root: { 
    display: 'inline-flex', 
    width: iconVars['--icon-size'] 
  },
});

const colorStyles = stylex.create({
  primary: { 
    color: colorVars['--color-icon-primary'] 
  },
  secondary: { 
    color: colorVars['--color-icon-secondary'] 
  },
});

```

Each property object describes static CSS rules. StyleX extracts these at build time to generate atomic CSS classes, ensuring zero runtime overhead for style calculation.

## Applying Styles with stylex.props and mergeProps

At render time, components transform StyleX objects into React-compatible props using **`stylex.props`**. Astryx combines this with **`mergeProps`** from `@astryxdesign/core/utils` to unify design-system metadata, StyleX classes, and consumer-provided props:

```tsx
import {mergeProps} from '@astryxdesign/core/utils';
import {themeProps} from '@astryxdesign/core/utils';

function Button({variant = 'primary', ...rest}) {
  return (
    <button
      {...mergeProps(
        themeProps('button', {variant}),
        stylex.props(buttonStyles.base, buttonStyles[variant]),
      )}
      {...rest}
    >
      Click me
    </button>
  );
}

```

The `themeProps` utility injects data attributes like `data-variant` and `data-size` for theming hooks, while `stylex.props` returns a `{ className, style }` object that `mergeProps` intelligently combines without className collisions.

## Handling Dynamic Values and CSS Variables

While StyleX generates static classes, Astryx supports **runtime overrides** by extracting raw CSS variable names from tokens. The `SVGIcon` component demonstrates this when handling custom `strokeWidth` values:

```tsx
function SVGIcon({strokeWidth, ...props}) {
  const strokeVar = (iconVars['--icon-stroke-width'] as string).replace(
    /^var\((.+)\)$/,
    '$1',
  );

  const override = strokeWidth
    ? {[strokeVar]: String(strokeWidth)}
    : undefined;

  return (
    <svg
      {...stylex.props(iconStyles.root, colorStyles[props.color])}
      style={override}
      // ...other props
    />
  );
}

```

This technique preserves the static class-based architecture while allowing per-instance customization through inline styles that override CSS variables.

## Advanced Patterns: Markers and Conditional States

For complex selectors like hover states, focus rings, or ancestor-dependent styling, Astryx uses **StyleX markers** and conditional APIs. The Table component in [`packages/core/src/Table/table.stylex.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/Table/table.stylex.ts) implements this with `stylex.defineMarker` and `stylex.when.ancestor`:

```tsx
const tableRowMarker = stylex.defineMarker();

const rowStyles = stylex.create({
  row: {
    borderBottom: '1px solid',
    borderColor: colorVars['--color-border'],
  },
  lastRow: {
    borderBottom: 'none',
  },
});

// Applying conditional styles based on ancestor state
stylex.when.ancestor(':last-child', tableRowMarker)

```

These utilities generate scoped, specific CSS selectors without leaking state across component boundaries or requiring runtime JavaScript for state detection.

## Animation and Utility Functions

Astryx extends StyleX integration to animations and fallback handling. In [`packages/core/src/hooks/useEntryAnimation.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/hooks/useEntryAnimation.ts), the library defines keyframes:

```tsx
const fadeIn = stylex.keyframes({
  from: { opacity: 0 },
  to: { opacity: 1 },
});

const styles = stylex.create({
  animated: {
    animationName: fadeIn,
    animationDuration: '300ms',
  },
});

```

The **`stylex.firstThatWorks`** utility provides CSS fallbacks for properties like `display`, ensuring cross-browser compatibility while maintaining the static extraction model.

## Summary

- **StyleX is imported** as `* as stylex from '@stylexjs/stylex'` in every component requiring styles, establishing the foundation for zero-runtime CSS generation.
- **Design tokens** are centralized in [`packages/core/src/theme/tokens.stylex.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/theme/tokens.stylex.ts) using `stylex.defineVars`, enabling type-safe access to theme values via CSS variables.
- **Style objects** are created with `stylex.create()`, defining static rules that compile to atomic CSS classes at build time.
- **Style application** occurs through `stylex.props()`, which merges multiple style objects and is combined with `mergeProps()` and `themeProps()` to integrate design-system metadata.
- **Dynamic overrides** are achieved by extracting CSS variable names from tokens and applying them via inline styles, allowing runtime customization without sacrificing static extraction.
- **Conditional states** utilize `stylex.defineMarker` and `stylex.when.*` APIs to handle pseudo-selectors and ancestor-based styling with scoped, compile-time generated CSS.

## Frequently Asked Questions

### What is StyleX and why does Astryx use it instead of other CSS-in-JS libraries?

**StyleX is a zero-runtime CSS-in-JS library developed by Meta that generates static CSS files at build time.** Astryx uses StyleX because it provides type-safe style objects, atomic CSS generation for optimal bundle sizes, and full compatibility with server-side rendering without requiring runtime style injection. Unlike traditional CSS-in-JS solutions that execute JavaScript in the browser to compute styles, StyleX extracts all CSS during compilation, resulting in better performance and no hydration mismatches.

### How can I override Astryx component styles at runtime if StyleX generates static CSS?

**Override specific CSS variables extracted from design tokens.** Astryx components expose customizable properties through CSS variables defined in [`tokens.stylex.ts`](https://github.com/facebook/astryx/blob/main/tokens.stylex.ts). By extracting the raw variable name from a token (removing the `var()` wrapper) and applying it to the element's `style` prop, you can modify specific values like colors or stroke widths while keeping the static class names intact. This pattern appears in [`SVGIcon.tsx`](https://github.com/facebook/astryx/blob/main/SVGIcon.tsx) where the `strokeWidth` prop dynamically updates the `--icon-stroke-width` variable.

### What is the difference between stylex.create and stylex.defineVars in Astryx?

**`stylex.create` defines component-specific style objects that map to CSS class names, while `stylex.defineVars` creates design tokens that compile to CSS custom properties.** Use `stylex.create` in component files to define layouts, spacing, and component-specific aesthetics. Use `stylex.defineVars` in theme files like [`packages/core/src/theme/tokens.stylex.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/theme/tokens.stylex.ts) to establish reusable values (colors, spacing scales) that multiple components can reference and override at the theme level.

### How does Astryx handle hover, focus, and responsive states with StyleX?

**Astryx uses `stylex.defineMarker` combined with `stylex.when.*` APIs to handle conditional states.** Instead of inline event handlers or runtime state classes, Astryx defines markers that StyleX uses to generate specific CSS selectors at compile time. For example, `stylex.when.ancestor(':last-child', tableRowMarker)` generates CSS that applies styles when a row is the last child of its parent. This approach maintains the zero-runtime guarantee while supporting complex pseudo-selectors and media queries through static CSS generation.