# How to Customize Theme Colors and Tokens in the Astryx Design System

> Customize Astryx design system theme colors and tokens using ThemeProvider or the xds theme add CLI command. Learn how to efficiently manage your Astryx project's visual identity.

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

---

**You customize theme colors and tokens in Astryx by wrapping your application in a `ThemeProvider` that accepts a tokens object mapping CSS custom properties to values, or by generating a new theme via the `xds theme add` CLI command.**

Astryx is Meta's open-source design system built on StyleX that uses a token-driven architecture for theming. Whether you need to override a few colors at runtime or create an entirely new brand theme, the system provides both programmatic APIs and CLI tooling to customize theme colors and tokens without modifying component source code.

## Understanding the Token Architecture

Astryx themes are built on CSS custom properties (design tokens) defined in TypeScript declaration files. Each theme lives in `packages/themes/<theme-name>/theme.css.d.ts` and exports a complete map of available tokens.

For example, the y2k theme defines its contract in [`packages/themes/y2k/theme.css.d.ts`](https://github.com/facebook/astryx/blob/main/packages/themes/y2k/theme.css.d.ts). This file lists every available CSS variable, such as `--color-primary`, `--radius-sm`, and `--spacing-lg`, that components can consume. The actual values are injected at runtime by the `ThemeProvider` component exported from `@astryxdesign/core`.

The utility function `themeProps()` in [`packages/core/src/utils/themeProps.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/utils/themeProps.ts) generates the stable `astryx-<component>` class names and mirrors visual props as `data-*` attributes, ensuring components maintain consistent styling hooks regardless of the active theme.

## Overriding Tokens at Runtime with ThemeProvider

To customize theme colors without creating a new theme package, import the `ThemeProvider` from `@astryxdesign/core` and pass a tokens object that overrides specific CSS variables.

```tsx
import { ThemeProvider } from '@astryxdesign/core';

const customTokens = {
  '--color-primary': '#0066ff',
  '--color-background': '#f4f7fb',
  '--radius-sm': '4px',
};

function App() {
  return (
    <ThemeProvider tokens={customTokens}>
      {/* Your Astryx components here */}
    </ThemeProvider>
  );
}

```

When the provider mounts, it injects a `<style>` block defining these custom properties on the root element. Every component referencing `var(--color-primary)` automatically picks up the new value. The provider merges your custom tokens with the base theme defaults, so you only need to specify values you want to change.

## Creating a New Theme with the CLI

For complete theme customization, use the Astryx CLI to scaffold a new theme package. The CLI documentation in `packages/cli/docs/theme.doc.mjs` defines the `xds theme` commands.

Run the following to generate a fresh theme scaffold:

```bash
xds theme add my-brand

```

This creates:

- [`packages/themes/my-brand/theme.css.d.ts`](https://github.com/facebook/astryx/blob/main/packages/themes/my-brand/theme.css.d.ts) – A TypeScript definition file listing all available tokens
- A starter README describing the palette structure

Edit the generated [`.d.ts`](https://github.com/facebook/astryx/blob/main/.d.ts) file to set your default token values:

```ts
/* packages/themes/my-brand/theme.css.d.ts */
export const vars = {
  '--color-primary': '#ff5733',
  '--color-secondary': '#33c1ff',
  '--spacing-lg': '24px',
};

```

Import these tokens into your application and pass them to `ThemeProvider` to activate your custom theme.

## How Components Consume Tokens

Astryx components consume tokens through StyleX stylesheets that reference CSS variables. For example, the Button component in [`packages/core/src/Button/Button.stylex.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/Button/Button.stylex.ts) defines its base styles as:

```ts
import { stylex } from '@stylex/css';

export const button = stylex.create({
  base: {
    backgroundColor: 'var(--color-primary)',
    borderRadius: 'var(--radius-sm)',
  },
});

```

Because components use `var(--token-name)` syntax, changing the theme at the provider level instantly updates the visual appearance without requiring code changes in individual components. The `themeProps()` utility ensures each component receives the correct `astryx-*` class name that scopes these variable references.

## Dynamic Theme Updates with useTheme

For runtime theme customization, such as dark mode toggles or customer-specific branding, use the `useTheme` hook. This hook, demonstrated in [`apps/sandbox/src/components/themePreview/themeOverrides.ts`](https://github.com/facebook/astryx/blob/main/apps/sandbox/src/components/themePreview/themeOverrides.ts), provides access to the nearest `ThemeProvider`'s state.

```tsx
import { useTheme } from '@astryxdesign/core';

function DarkModeToggle() {
  const { setTokens } = useTheme();

  const enableDark = () => {
    setTokens({
      '--color-background': '#1a1a1a',
      '--color-text': '#eeeeee',
    });
  };

  return <button onClick={enableDark}>Dark mode</button>;
}

```

The `setTokens` function performs a shallow merge with existing tokens, allowing you to update specific values while preserving the rest of the theme. This approach is ideal for A/B testing, user preference storage, or seasonal theme variations.

## Summary

- **Theme tokens are CSS custom properties** defined in `packages/themes/<theme>/theme.css.d.ts` files that provide type-safe contracts for available values.
- **Runtime customization** uses the `ThemeProvider` component from `@astryxdesign/core`, which accepts a tokens object and injects CSS variables into the document root.
- **New theme creation** is handled via the `xds theme add <name>` CLI command, which scaffolds the necessary files in `packages/themes/`.
- **Dynamic updates** are possible through the `useTheme` hook, which exposes a `setTokens` method for runtime mutations.
- **Component integration** happens automatically through StyleX stylesheets referencing `var(--token-name)`, requiring no changes to component logic when themes change.

## Frequently Asked Questions

### How do I switch between light and dark modes in Astryx?

Use the `useTheme` hook to dynamically update tokens based on user preference. Call `setTokens()` with your dark mode values (such as `'--color-background': '#1a1a1a'`) when the user toggles the mode. Store the preference in state or localStorage and apply it via `ThemeProvider` on initial load.

### Can I override just one color without replacing the entire theme?

Yes. The `ThemeProvider` merges your provided tokens object with the base theme defaults. Pass only the specific tokens you want to override, such as `{ '--color-primary': '#custom-color' }`, and all other tokens will retain their original values from the active theme.

### Where are theme token definitions stored in the source code?

Token definitions are stored in `packages/themes/<theme-name>/theme.css.d.ts` files. For example, the y2k theme defines all its available CSS custom properties in [`packages/themes/y2k/theme.css.d.ts`](https://github.com/facebook/astryx/blob/main/packages/themes/y2k/theme.css.d.ts). These TypeScript files serve as the source of truth for what tokens a theme provides and their default values.

### What is the difference between themeProps() and ThemeProvider?

`themeProps()` is a utility function in [`packages/core/src/utils/themeProps.ts`](https://github.com/facebook/astryx/blob/main/packages/core/src/utils/themeProps.ts) that generates component class names and data attributes, while `ThemeProvider` is a React component that manages the actual CSS custom property values at runtime. The provider injects the values, and `themeProps()` ensures components have the correct styling hooks to consume them.