styled-components / xstyled

A utility-first CSS-in-JS framework built for React. 💅👩‍🎤⚡️
https://xstyled.dev
MIT License
2.27k stars 106 forks source link

How to refer to new keys in the theme? #307

Closed ion-willo closed 2 years ago

ion-willo commented 2 years ago

Hi,

We have a situation where we declare our own keys for some colours, for instance:

  colors: {
    ...defaultTheme.colors,
    advert: '#F3F3F3',

and then later in the same theme object, I would like to use the advert colour, for instance:

  MyComponent: {
    active: {
      backgroundColor: 'advert'
    },
    default: {
      backgroundColor: 'red-500-a50'
    }
  }

I try to access it like this in the component:

export const MyComponent = styled.div(
  ({ active }) => css`
    ${active ? th('MyComponent.active') : th('MyComponent.default')}
    ${system}
  `
)

The default colour will resolve, but the active one will not. Is there something else I need to do, to make this work?

Regards,

Willo

agriffis commented 2 years ago

The default colour will resolve

Are you sure?

https://codesandbox.io/s/xstyled-v3-ht4gt?file=/src/App.js

ion-willo commented 2 years ago

You're right. Turns out the colour I used in the real component happened to use a standard named colour and I assumed it was a themed one.

I'm now thoroughly confused. How should I be doing this differently?

agriffis commented 2 years ago

xstyled does magic replacements in two cases: system props and css template literal.

The first case is <x.div backgroundColor="advert" /> and the second case is css`background-color: advert;`

So here are a couple options for you:

  1. Build the colors object before the theme object, and then refer to it:

    const colors = {
      ...defaultTheme.colors,
      advert: '#F3F3F3',
    }
    
    const theme = {
      ...defaultTheme,
      colors,
      MyComponent: {
        active: {
          backgroundColor: colors.advert,
        },
        default: {
          backgroundColor: colors['colors.red-500-a50'],
        },
      },
    }
  2. Or embed css template literals in your theme:

    const theme = {
      ...defaultTheme,
      colors: {
        ...defaultTheme.colors,
        advert: '#F3F3F3',
      },
      MyComponent: {
        active: css`
          background-color: advert;
        `,
        default: css`
          background-color: red-500-a50;
        `,
      },
    }

Personally I'd recommend the former, because the latter prevents reuse of the component theme, for example you can't refer to theme.MyComponent.default.backgroundColor. However if that constraint doesn't bother you, the latter approach is fine too.

ion-willo commented 2 years ago

Awesome! Thanks @agriffis