Theme-ui: Describe your styling stack/best practices/how you use theme-UI

Created on 21 May 2020  路  9Comments  路  Source: system-ui/theme-ui

This is for all the adopters of theme-UI. It would be fantastic to have a collection of how people use this tool in their project and together with which other tools. It obviously covers a real need since it has so much success. Let's see how people use this.

I'll start:

We're planning a refactoring to our project and are exploring different options of using theme-ui together with a common.scss file that holds a set of utility classes that don't fit inside a theme definition.

Most helpful comment

Hi guys,
I used ThemeUI on various different projects, I built a Design System based on the "styled-system props way", then I built various websites using the JSX pragma with the sx prop and also websites without the JSX pragma. So here is a quick review of my experience:

styled-system props way

I think it's great to build primitive components (pretty much what Rebass does) for something like a Design System and for components that are used for layouting only. But the problem of this syntax is that you are basically creating a new styling API: your developers will have to learn what props are supported or not by each component. Also if you just allow every single CSS property as a component prop, you can introduce props naming clash...
I think this is a great approach if you want to force a limitation of usage of your components (so yeah again, for a Design System), for example a Button has a color prop because it has styling limitations (you don't want your developer to override its font family for example, but only a set of accepted/theme-aware prop). The styled-system props style makes this super clear.

JSX pragma + sx prop everywhere

It's great as you can directly use the sx prop on any component. However I experienced 2 issues with this workflow:

  • Sometimes I was forgetting to add the JSX pragma on my new component, then I was loosing 10min trying to understand what was going on (happens more often than you might think!). It's also weird for newcomers to understand/get used to.
  • The way styles are merged together when doing composition of components might be hard to predict. I had various issues with using the sx prop on top of a custom component that was already internally using it, etc.

Without JSX pragma

This is "my favourite way" to use ThemeUI:

  • I have a unique Box primitive component (can be the one from rebass).
  • I do not use the JSX pragma at all.
  • Every components I build are using my primitive Box component.
  • I style everything using the sx prop, this prop is a normal React prop that is just passed down to the primitive Box component, that does the "magic ThemeUI stuff":
    const Button = ({ sx, ...otherProps }) => <Box as="button" sx={{ borderRadius: 2, ...sx }} {...otherProps}  />

This way this is pretty easy to predict how your styles will be merged (it's just top > down).
Also @cameronwlewis you can adopt a similar style as when using Styled-Components even using the sx prop actually, it doesn't necesarilly makes things ugly (even if I have to admit you tend to put everything inline directly in your JSX and that can grow pretty badly).

   const StyledContainer = props => <Container sx={{ p: 4 }} {...props}  />

   render() {
      <StyledContainer>
          <div>your content</div>
      </StyledContainer>
  }

Hope that helps,

All 9 comments

Hey @jxnblk,

I'll jump in here to expand on @mihaisavezi's comment (we're colleagues) and detail how we're thinking of using it. We'd really really appreciate your insights. Also, I'll try and be as short as possible (I hate long texts just like the next person, haha).

So, we're thinking of mixing ThemeUI with a few utility classes. For example this one:

/* common.scss */
.flex--center {
    display: flex;
    align-items: center;
    justify-content: center;
}

After doing research and playing with the library, it seems like the ThemeUI way to have a nav with centered children would be something like this:

<Flex as="nav" sx={{ justifyContent: 'center', alignItems: 'center' }}>
  ...
</Flex>

I personally prefer the native classes aproach here because there are less abstractions:

<nav className="flex--center">
  ...
</nav>

Now, regarding pros and cons we thought of:

Pros

  • more readable code
  • class composition
  • ability to extract these utility-styles into a separate file thus improved performance

Cons

  • without proper enforcement it may start containing styles related to the theme - like mr-2 - and we you have 2 approaches doing kinda the same thing. And one of them is not responding to theme changes.
  • hard to read elements which may contain classes as well as props/sx based on theme
  • [... any other thing we haven't thought of?]

So yeah, the TLDR for me is: I see the value in ThemeUI & CSS-in-JS but I also see the value of classes in certain use-cases. Hope I explained it clearly, and thanks for doing such great work with all these projects (rebass, theme-ui, etc)

@iampava I've left this issue open since it sounded like an open question for the community. Use whatever works for you, but I've written a bit of my own thoughts on utility-based CSS here, since I sorta helped popularize that pattern along with Tachyons: https://jxnblk.com/blog/two-steps-forward/

Hey! Thanks for the article, really nice read.

I guess what I'm trying to ask is if you use exclusively the sx prop or related props when styling native elements/components. I'm thinking that a mix between this and utility CSS would be more desirable 馃

@iampava Yes, the sx prop can be used on any component that accepts className. In my experience, it tends to be easier to stick to one styling approach as opposed to mixing different ones together. You might run into cascade issues (source order, etc.), and the API surface areas can get unwieldy. Ultimately utility-based CSS like Basscss and Tachyons, etc. will never be able to provide everything a team might need for styles, but can work well for individuals and small sites

Ok, got it. What about offering the theme as CSS Variables for styling native elements - like <h1> - without the need for the sx prop?

I posted a comment regarding this here: https://github.com/system-ui/theme-ui/issues/499

@jxnblk I'm new to styled-system / theme-ui, I'm confusing should I just use props of styled-system:

<Box display="flex" justifyContent="center" width={[1, 1, 1/2]} />

Or use sx prop of theme-ui:

<Box
  sx={{
    display: 'flex',
    justifyContent: center,
    width: {[1, 1, 1/2]},
  }}
/>

May I know which one is better?

@yeungc @jxnblk I also have this question. It may be a deciding factor for our team, since some devs feel like the sx prop is "just too ugly"

Hi guys,
I used ThemeUI on various different projects, I built a Design System based on the "styled-system props way", then I built various websites using the JSX pragma with the sx prop and also websites without the JSX pragma. So here is a quick review of my experience:

styled-system props way

I think it's great to build primitive components (pretty much what Rebass does) for something like a Design System and for components that are used for layouting only. But the problem of this syntax is that you are basically creating a new styling API: your developers will have to learn what props are supported or not by each component. Also if you just allow every single CSS property as a component prop, you can introduce props naming clash...
I think this is a great approach if you want to force a limitation of usage of your components (so yeah again, for a Design System), for example a Button has a color prop because it has styling limitations (you don't want your developer to override its font family for example, but only a set of accepted/theme-aware prop). The styled-system props style makes this super clear.

JSX pragma + sx prop everywhere

It's great as you can directly use the sx prop on any component. However I experienced 2 issues with this workflow:

  • Sometimes I was forgetting to add the JSX pragma on my new component, then I was loosing 10min trying to understand what was going on (happens more often than you might think!). It's also weird for newcomers to understand/get used to.
  • The way styles are merged together when doing composition of components might be hard to predict. I had various issues with using the sx prop on top of a custom component that was already internally using it, etc.

Without JSX pragma

This is "my favourite way" to use ThemeUI:

  • I have a unique Box primitive component (can be the one from rebass).
  • I do not use the JSX pragma at all.
  • Every components I build are using my primitive Box component.
  • I style everything using the sx prop, this prop is a normal React prop that is just passed down to the primitive Box component, that does the "magic ThemeUI stuff":
    const Button = ({ sx, ...otherProps }) => <Box as="button" sx={{ borderRadius: 2, ...sx }} {...otherProps}  />

This way this is pretty easy to predict how your styles will be merged (it's just top > down).
Also @cameronwlewis you can adopt a similar style as when using Styled-Components even using the sx prop actually, it doesn't necesarilly makes things ugly (even if I have to admit you tend to put everything inline directly in your JSX and that can grow pretty badly).

   const StyledContainer = props => <Container sx={{ p: 4 }} {...props}  />

   render() {
      <StyledContainer>
          <div>your content</div>
      </StyledContainer>
  }

Hope that helps,

I'm new to styled-system / theme-ui, I'm confusing should I just use props of styled-system:

<Box display="flex" justifyContent="center" width={[1, 1, 1/2]} />

Or use sx prop of theme-ui:

<Box
  sx={{
    display: 'flex',
    justifyContent: center,
    width: {[1, 1, 1/2]},
  }}
/>

May I know which one is better?

@yeungc Depending on the prop, you can use both in Theme UI! (You can only use theme values as props afaik, I might be wrong there鈥攚e should definitely document a list.) The balance I鈥檝e found in my own (extensive) usage of Theme UI is to only use the props for a few simple properties (whitespace, color, font size, typically) & if there鈥檚 more than 1-2 props, use them inside the sx prop, since you can then use them alongside arbitrary, non-theme CSS properties & the syntax is terser.

@hasparus We can close as a(n inactive) discussion I think :+1:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Everspace picture Everspace  路  3Comments

vojtaholik picture vojtaholik  路  3Comments

mxstbr picture mxstbr  路  3Comments

VinSpee picture VinSpee  路  3Comments

tesseralis picture tesseralis  路  3Comments