Theming not working as intended
- Dominant language
- JavaScript
- Stars
- 10.3k
- Forks
- 481
- Avg merge
- 3d 8h
- Merged PRs (30d)
- 13
Description
### Describe the issue
I have an issue where themes are not getting applied correctly and the CSS variables are reverting to the original variable value (not the correct themed version).
I have a CSS variable for UI scale. It is used in “spacing” tokens to scale their size up and down based on the overall UI scale. I created different themes to represent the preset UI scales.
```tsx
import { createTheme, defineVars } from "@stylexjs/stylex";
export const uiScale = defineVars({
"--ui-scale": "1",
});
const large = createTheme(uiScale, {
"--ui-scale": "1.1",
});
const small = createTheme(uiScale, {
"--ui-scale": "0.9",
});
export const uiScaleThemes = {
large,
small,
};
export type UIScaleThemes = keyof typeof uiScaleThemes;
```
Here’s an example of the spacing tokens:
```tsx
export const space = defineVars({
"--oat-space-1": `calc(4px * ${uiScale["--ui-scale"]})`,
});
```
This works ok with the initial value, but when I try to set any themes to change the value, it doesn’t work. The spacing variable stays at it’s original value.
Here’s an example of applying the themes - I just pass in the theme into the StyleX `props()` function. This component wraps the entire app:
```tsx
export function ThemeProviderR2({
theme: userTheme,
uiScale,
children,
}: React.PropsWithChildren) {
const { theme: storeTheme } = useThemeStore();
const theme = userTheme ?? storeTheme;
const uiScaleTheme =
uiScale && uiScale in uiScaleThemes ? uiScaleThemes[uiScale] : undefined;
const sx = props(theme == "dark" && darkTheme, uiScaleTheme);
return (
{children}
);
}
```
In my browser’s DevTools (tested both in Chrome and Firefox), I can see that the theme is applied correctly and overriding the variable. The new variable value is shown active, while the old variable is scratched out. And when I hover over the UI scale variable inside Firefox the `--oat-space-1` variable, I can see the overridden value. In Chrome I see it references the original value — but it still shows the original scratched out like Firefox.
But for some reason, the browser doesn’t render using the theme variable. It renders using the original variable. If I go into DevTools and change the value of the original - now scratched out UI space var, the component updates as expected.
I did a sanity check with a regular DOM element and inline styles with the same setup, and it worked fine. So it seems likely to be a specificity issue with StyleX.
```tsx
Target Text: Scale should be 5
```
I even tried throwing a `!important` on the override style in DevTools to see if it’s force it to take over, but that had no effect. Also tried using the `@property` definition to enforce it to update more (in case it was a cached computation) but that had no effect either.
Here’s an example of the generated CSS:
```css
@layer priority1 {
.x1ktcudu.x1ktcudu, .x1ktcudu.x1ktcudu:root {
--ui-scale: 2 !important;
}
}
/* The original style - has a "strikethrough" in DevTools */
@layer priority1 {
:root, .x1a594gj {
--ui-scale: 1;
}
}
```
and the DOM for reference:
```tsx
const greeting = 'Hello, World!';
```
### Expected behavior
Theme should apply and override correctly, and apply correctly to nested children. I shouldn't have to wrap each individual component with a theme override, it should respect/replicate platform behavior where parent CSS variable override is inherited.
### Steps to reproduce
I'm on StyleX version ^0.17.4 and React v19.
You can probably copy my code above to reproduce, but I can throw up a quick fork for reference if you need something to run and test.
### Test case
_No response_
### Additional comments
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.