Expose theme values as CSS Variables
Right now we can't use theme values when styling native HTML elements. We have to either
- Wrap them in custom components
<H1>,<H2>, etc - Use the
sxprop
I'd like to extend ThemeProvider with the ability to expose theme values as CSS Variables so that in a stylesheet we could do something like:
h1 {
margin: var(--space-3);
font-size: var(--font-sizes-3);
}
h2 {
margin: var(--space-2);
font-size: var(--font-sizes-2);
}
I've already done this (just for the colors property as a proof of concept), here's the code:
import React, { useRef, useEffect } from 'react';
import { ThemeProvider, ThemeProviderProps, Theme, useThemeUI } from 'theme-ui';
export const ThemeAdapter = (props: ThemeProviderProps<Theme>) => {
const ref = useRef(null);
const { theme: outerTheme } = useThemeUI();
useEffect(() => {
const theme =
typeof props.theme === 'function' ? props.theme(outerTheme) : props.theme;
Object.entries(theme?.colors || {}).forEach(([key, value]) => {
ref.current.style.setProperty(`--colors-${key}`, value);
});
});
return (
<div ref={ref} className='theme-ui-adapter'>
<ThemeProvider {...props} />
</div>
);
};
Thus, any elements inside the <div className="theme-ui-adapter"> can make use of the CSS Variables. Also, because of the way scope works, we have theme/sub-theme functionality by default.
You might be interested in this package: https://github.com/system-ui/theme-ui/tree/master/packages/custom-properties -- it's missing a few nice-to-have features, so PRs are welcome :)
Yep, seen it. Could be used to create the name/value pairs, but it doesn't fix the need for adjusting code inside ThemeProvider (as in the snippet above).
Or maybe, we could export a HOC from there, and use it something like
import { ThemeProvider } from 'theme-ui`;
import { withCustomProperties } from '@theme-ui/custom-properties';
export const ThemeAdapter = withCustomProperties(ThemeProvider);
What do you think?
PS: I'd be happy to do the PRs, but first "point me in the right direction" as it's said :D
I don't think this sort of functionality should be part of the core packages, but I think you could achieve what you're looking for in the @theme-ui/custom-properties package as an additional export, if you want to look into a PR there then go for it!
Great! I'll work on it as soon as possible. Thanks for the input
I believe our recent work on color modes has implemented this for colors—since we now use a wrapping div for ThemeProvider, any element inside the ThemeProvider component can consume the colors:

Sweet! 👍
@lachlanjc is there anything special you have to do to get those variables to show up? I'm using @theme-ui/core version 0.13.1 and they aren't showing up for me.
Switching to the "all-in-one" theme-ui package makes them show up, but I'd rather be able to use just @theme-ui/core.
Ah, I believe that's the issue. Those custom properties are part of the color-modes package, which isn't included in core. What's your use case?
Use case is just trying to keep the end result of my app small 😉
I ended up just switching to theme-ui from @theme-ui/core
That makes sense! I was wondering why you wanted these custom properties though—I've personally never used them, since if I'm using Theme UI on a site typically all my styling is going through it
The main reason I need the custom properties is for things like linear-gradient.
i.e. if I want to do...
backgroundImage: "linear-gradient(to top, var(--theme-ui-colors-buttonPrimary1), var(--theme-ui-colors-buttonPrimary2))",
It seems like theme-ui doesn't work with something like linear-gradient(to top, buttonPrimary1, buttonPrimary2).
In another project, we added theme-ui on top of a bunch of existing SCSS files. We reference the --theme-ui-colors- variables a lot in the SCSS.
Is there still a usecase/desire for non-color theme values to be accessible via custom properties?