Skip to content

feat: rework base theming architecture - #21

Merged
mellyeliu merged 2 commits into
mainfrom
theme-test
Jan 24, 2026
Merged

mellyeliu merged 2 commits into
mainfrom
theme-test

Conversation

@mellyeliu

@mellyeliu mellyeliu commented Jan 22, 2026

Copy link
Copy Markdown
Member

Context

Reworking the general theming infrastructure from #16

The theming flow looks something like this:

  • All raw hex/rgb/static values for colors, spacing, etc are stored in defineConsts calls. defineConsts transpiles to a plain JS object that is inlined at build time, generates no CSS, and its values can be imported and used within stylex.create or stylex.defineVars files as needed.
    • Alternatively, we can still use raw JS objects if we never need to use these in create calls and we don't care about repeating across files. But it'll get messy
  • defineVars uses the defineConsts values and -- keys, which expose the variable name and allow users to modify them as CSS variables anywhere.
export const colorRaw = stylex.defineConsts({
    '--xdsAccent': colorTokens.accent,
    '--xdsSurface': colorTokens.surface,
    // ... map all tokens
  },
});

export const colorTokens = stylex.defineVars({
   '--xds-accent': colorRaw['--xdsAccent']
   '--xds-surface': colorRaw['--xdsSurface']
});

export const neutralColors = stylex.createTheme(colorTokens, {overrides})

// Not settled on the shape of the export here or the keys we want to expose, but we can iterate
export themeTokens = {
   colors: colorRaw,
   ...
}

There are two primary issues to using create/props instead of defineVars/createTheme in #16

1, Losing the VarGroup guarantee that each theme sets all variables (and unset keys are reset)
2. It creates a single class to set all variables and not one class per variable. (performance critical)

Blockers/Todos

  • Replace camelCase keys with -- in defineConsts?
  • Reuse base token values across tokens + defaultTheme + neutralTheme
  • Refactor, clean types, update docs

One option is to also use -- keys in defineConsts as well instead of the camelCased key for ease of use. Currently we disallow such keys in defineConsts for relatively arbitrary (safety/obfuscation) reasons but opening facebook/stylex#1460 as an option to fix this

We could have a system that maps cleanly from defineVars -> defineCosts (one camel cased, another --)

Testing

Storybook theming works

Screen.Recording.2026-01-23.at.9.28.25.PM.mov

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Jan 22, 2026

StyleX has limited support for combined pseudo-selectors like `:hover::after` or `:active::after`.

**Problem**: Tried using `::after` pseudo-element for hover/active overlay effects:

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this does in fact work within StyleX, although it's a bit hacky

Comment thread packages/core/src/theme/defaultTheme.stylex.ts Outdated
Comment thread packages/core/src/theme/tokens.stylex.ts Outdated
Comment thread packages/core/src/theme/tokens.stylex.ts Outdated
Comment thread packages/core/src/theme/neutralTheme.stylex.ts
@mellyeliu
mellyeliu force-pushed the theme-test branch 2 times, most recently from 9f7791f to da251c8 Compare January 24, 2026 00:02
@mellyeliu
mellyeliu marked this pull request as ready for review January 24, 2026 00:04
@mellyeliu
mellyeliu marked this pull request as draft January 24, 2026 00:04
- Split rawTokens into separate *Raw objects (colorRaw, spacingRaw, etc.)
- Use `as const satisfies Record<*VarName, string>` for type safety
- Add Base*Raw type exports for cleaner createTheme casting
- Replace `as any` with `as unknown as Base*Raw` in theme files
- Export Base*Raw types from theme index for external use
- Update component styles to use theme tokens
- Update storybook stories for consistency
- Clean up layer, layout, and container components
@mellyeliu

Copy link
Copy Markdown
Member Author

As discussed with @cixzhang, went with a raw vars object exposing hex values -> passed to defineVars -> themed using `createTheme

Split docs changes into #50 as the PR was getting unwieldy

@mellyeliu mellyeliu changed the title [wip] feat: rework base theming architecture feat: rework base theming architecture Jan 24, 2026

@cixzhang cixzhang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Thanks for updating this and making the theming system better!

I guess we didn't want to prefix with --xds? Maybe something we can revisit later or perform prefixing using a plugin if we end up white gloving this system. I do like the conciseness.

@mellyeliu

Copy link
Copy Markdown
Member Author

Yeah, I mainly left out the prefix for now in case the naming discussions weren't stabilized. We can always update or tweak it later!

@mellyeliu
mellyeliu merged commit 9731b7e into main Jan 24, 2026
2 checks passed
@mellyeliu
mellyeliu deleted the theme-test branch January 24, 2026 02:33
czarandy pushed a commit that referenced this pull request Jan 26, 2026
* feat: rework base theming architecture with typed createTheme

- Split rawTokens into separate *Raw objects (colorRaw, spacingRaw, etc.)
- Use `as const satisfies Record<*VarName, string>` for type safety
- Add Base*Raw type exports for cleaner createTheme casting
- Replace `as any` with `as unknown as Base*Raw` in theme files
- Export Base*Raw types from theme index for external use

* refactor: clean up component styles and stories

- Update component styles to use theme tokens
- Update storybook stories for consistency
- Clean up layer, layout, and container components
cixzhang pushed a commit that referenced this pull request Apr 26, 2026
* feat: rework base theming architecture with typed createTheme

- Split rawTokens into separate *Raw objects (colorRaw, spacingRaw, etc.)
- Use `as const satisfies Record<*VarName, string>` for type safety
- Add Base*Raw type exports for cleaner createTheme casting
- Replace `as any` with `as unknown as Base*Raw` in theme files
- Export Base*Raw types from theme index for external use

* refactor: clean up component styles and stories

- Update component styles to use theme tokens
- Update storybook stories for consistency
- Clean up layer, layout, and container components
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants