theme-ui icon indicating copy to clipboard operation
theme-ui copied to clipboard

Expose theme values as CSS Variables

Open iampava opened this issue 5 years ago • 12 comments

Right now we can't use theme values when styling native HTML elements. We have to either

  1. Wrap them in custom components <H1>, <H2>, etc
  2. Use the sx prop

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.

iampava avatar Jun 04 '20 11:06 iampava

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 :)

jxnblk avatar Jun 04 '20 14:06 jxnblk

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

iampava avatar Jun 04 '20 14:06 iampava

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!

jxnblk avatar Jun 04 '20 14:06 jxnblk

Great! I'll work on it as soon as possible. Thanks for the input

iampava avatar Jun 04 '20 14:06 iampava

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: image

lachlanjc avatar Oct 27 '21 20:10 lachlanjc

Sweet! 👍

iampava avatar Nov 04 '21 14:11 iampava

@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.

TranquilMarmot avatar Jan 15 '22 23:01 TranquilMarmot

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?

lachlanjc avatar Jan 16 '22 07:01 lachlanjc

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

TranquilMarmot avatar Jan 18 '22 23:01 TranquilMarmot

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

lachlanjc avatar Jan 19 '22 02:01 lachlanjc

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.

TranquilMarmot avatar Jan 19 '22 07:01 TranquilMarmot

Is there still a usecase/desire for non-color theme values to be accessible via custom properties?

lachlanjc avatar Nov 20 '22 00:11 lachlanjc