-
Heyo everyone, We’re starting to introduce customization capabilities into our design system, with a small, focused goal: allowing users to choose their primary color. Background Currently, we have a library of tokens built with defineVars, where we use readable string keys as the names, as requested by our design team. export const colorPrimitives = {
"--s-color-neutral-0": "#ffffff",
"--s-color-neutral-100": "#f8f8f9",
// ...
}; We also define semantic tokens that point to core tokens to provide an abstraction layer: export const colorSemantic = {
"--s-color-primary": "--s-color-peri-500",
}; export const coreTokens = defineVars({
...colorPrimitives,
...colorSemantic,
... The Challenge We want to enable users to dynamically change the primary color at runtime (e.g., based on API data or user preference). I’ve looked into using createTheme, but it seems to be intended for static values known at build time. Since our customization might come from an API or user settings, this approach doesn’t seem feasible. One potential solution I’ve considered is directly updating the CSS variables at the html or body tag level. Since we use named variables rather than hashed ones, this might be manageable. However, it feels a bit off given StyleX’s default behavior of hashing variable names, and I wonder if there’s a more “StyleX-native” way to handle this. Also, I’d like to avoid using inline style attributes. Question Has anyone tackled dynamic theme customization with StyleX, especially where the colors are not known until runtime? Are there best practices or recommended approaches for this kind of use case? Any guidance or examples would be greatly appreciated! Thanks! |
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 10 replies
-
The only solution I can think of, if you’re using the default StyleX hashed variable names, is that you would point your hashed variable to a named variable ( |
Beta Was this translation helpful? Give feedback.
-
Just hoping someone could confirm I am not missing something more fundamental about how theming works with StyleX. Thank you! |
Beta Was this translation helpful? Give feedback.
-
I don't remember 100% how I solved this previously but it's something like the following if I remember correctly: // Define Theme type
type Theme = {
Foo: string,
...
}
// Define theme implentation
const styles = stylex.create({
theme: (theme: Theme) => ({
backgroundColor: theme.Foo,
color: ...,
}),
});
function Component(props: ComponentProps) {
// Initialize theme
const [runtimeObject, setRuntimeObject] = useState(...)
// Mutate theme
useEffect(() => {
...
}, [...])
return (
<div {...stylex.props(styles.theme(runtimeObject))}>
...
</div>
);
} I also went super with Video 1: https://www.youtube.com/watch?v=GXIWZOV_QvQ That being said, if memory serves, use something like the |
Beta Was this translation helpful? Give feedback.
-
Please don't do this: export const colorSemantic = {
"--s-color-primary": "--s-color-peri-500",
}; Pointing one variable to another variable is inefficient and doesn't work the way people expect in CSS. Re: Dynamic themingThe simplest way to do this with StyleX is to use the variables as keys within const styles = stylex.create({
dynamicTheme: (theme: Theme) => ({
[coreTokens["--s-color-primary"]]: theme.colorPrimary,
...
}),
}); StyleX variables can be used as both keys and values within |
Beta Was this translation helpful? Give feedback.
-
Going with the dynamic approach with inline style attribute for now. Originally thought I could avoid it, but its fine for now (company Content Security Policy really want to get rid of style attributes, but they are so ubiquitous) I'm still curious about the work that has been mentioned in some other discussions about Reactive Variables in the future. If useful for anyone else I will share some of my code. I am curious if you could add something like this to the recipes in the StyleX documentation. The ability to do this wasn't something I would have known by looking there. Thanks for all the help @nmn import * as React from 'react';
import * as stylex from '@stylexjs/stylex';
import { coreTokens } from '@acme/stitch-tokens/coreTokens.stylex';
// Define theme type (for documentation purposes in JSX file)
/**
* @typedef {Object} StitchTheme
* @property {string} primary - Primary brand color
* @property {string} [secondary] - Secondary brand color (optional)
* @property {string} [buttonPrimary] - Override for primary buttons (optional)
*/
// Dynamic theme styles following the maintainer's pattern
export const dynamicThemeStyles = stylex.create({
apply: (theme) => ({
// Base tokens
[coreTokens["--s-color-primary"]]: theme.primary,
[coreTokens["--s-color-secondary"]]: theme.secondary || '#381360',
// Background colors
[coreTokens["--s-color-background-primary"]]: theme.primary,
[coreTokens["--s-color-background-primary-hovered"]]: `color-mix(in srgb, ${theme.primary}, black 10%)`,
[coreTokens["--s-color-background-primary-pressed"]]: `color-mix(in srgb, ${theme.primary}, black 30%)`,
// Border colors
[coreTokens["--s-color-border-focused"]]: theme.primary,
[coreTokens["--s-color-border-selected"]]: theme.primary,
// Button colors
[coreTokens["--s-button-primary-color-background"]]: theme.buttonPrimary || theme.primary,
[coreTokens["--s-button-primary-color-background-hovered"]]: `color-mix(in srgb, ${theme.buttonPrimary || theme.primary}, black 10%)`,
[coreTokens["--s-button-primary-color-background-pressed"]]: `color-mix(in srgb, ${theme.buttonPrimary || theme.primary}, black 30%)`,
}),
});
// ThemeProvider Component
export function ThemeProvider(props) {
const { children, theme = { primary: '#5165fe' } } = props;
return (
<div {...stylex.props(dynamicThemeStyles.apply(theme))}>
{children}
</div>
);
} // Basic theming example
import { dynamicThemeStyles } from '@acme/stitch-extension';
import * as stylex from '@stylexjs/stylex';
function App() {
// Define a theme with a custom primary color
const theme = {
primary: '#00a550', // Green color
};
return (
<div {...stylex.props(dynamicThemeStyles.apply(theme))}>
<Button variant="primary">Primary Button</Button>
<Checkbox isSelected>Checkbox example</Checkbox>
<TextField label="Text Field Example" />
</div>
);
} |
Beta Was this translation helpful? Give feedback.
Going with the dynamic approach with inline style attribute for now. Originally thought I could avoid it, but its fine for now (company Content Security Policy really want to get rid of style attributes, but they are so ubiquitous)
I'm still curious about the work that has been mentioned in some other discussions about Reactive Variables in the future.
If useful for anyone else I will share some of my code. I am curious if you could add something like this to the recipes in the StyleX documentation. The ability to do this wasn't something I would have known by looking there.
Thanks for all the help @nmn