Theme UI: encouraging consistent and responsive styling practices
CSS is not fun to me personally. But the css-in-js solution provided by tools like emotion
and styled-components
makes it a lot more fun as I feel I am developing a react component with all props available beyond simply css.
I like both emotion
and styled-component
. Albeit that they implement in different mechanisms under the hood and thus their size and performance differ, the exposed API and developer experience is very similar. They would be my "go-to" solution for styling a component.
…until I came across Theme UI recently.
Is this yet another css-in-js solution?
Not really. Theme UI is built upon emotion
. It does not care about how to enable css in js but relies on emotion
to do the hard work. Instead, it provides a high level, opinionated, and purposely constraint API to shape how developers style components.
I have mixed feeling towards Theme UI. I want to share what I like and what I don’t like.
Likes
Constraint based
What distinguishes Theme UI is that it offers a constraint based design system. It allows you to define an array of scales (or reuse such scales defined in other themes) and makes it easy to refer to the value in the scales when you define your css later. For example, in your theme you can have an array of spaces
And then you can define your css:
Here 3
does not mean 3px
, but actually the third value in the space scale array. It is basically equal to:
By providing this sweet syntax sugar, it encourages developers to use the style predefined in the theme, which pushes for a consistent UI across app. Such constraint will be especially useful for large team/organization development.
Concise syntax
As you see above, you can put a sx
prop to style a component. There you have access to the theme.
A problem I have though, is not able to add sx
to a custom component
But emotion actually lets you do that.
Considering Theme UI builds upon emotion, I’m wondering if there is a way to do that in Theme UI. I cannot find anything in its document though.
Responsive style as array
I live this feature most and it is really powerful and beautiful. You can define some breakpoints
In your theme
Then you can have any array for your css, whose value corresponds to the screen size defined in the theme breakpoints.
Boom! You have a responsive font! You don’t need any media query to make responsive design! By making responsive styling easy, I believe it will encourage more developers to create responsive design.
Dislikes
Styled component?
What bugs me most is that its limited support of styled components. For example, with emotion
, you can create a styled component using @emotion/styled
With Theme UI, you can still use @emotion/styled
to create styled components since Theme UI builds upon emotion. However, the scale system is not readily available. That is, you can't write something like
You do still have access to the theme, but you end up with more code
Fixed scale system
As much as I like the constraint based solution, I do have two issues. First, it seems to add extra mental burden while developing because I have to look up the index of the space value first. I have to keep my theme file open when I am styling a component. This problem might get better as I become more used to the design system though.
A bigger issue is the scale system is fixed. But what if you want to change the scale system itself. Since things are referred to with the array index, if you change the array, say insert a new value in the middle of the array, values referred by the index are likely to change. There is one time when I really need a space of 24
. But if I added it between 16
and 32
, css like { m: 4 }
which stands for { margin: 32px }
before will become { margin: 24px }
. Of course you can always break out from the scale system and put { m: '24px' }
directly. This is a caution that the theme, or the design system, should not be changed regularly.
Conclusion
Overall I like the idea of Theme UI, and it is a great example of how to shape developer behavior with tooling. By making the desired practice easier for developers to implement (rather than forbidding them to do otherwise), developers naturally follow the suggested practice while they always have a way to escape. This reminds me of react-testing-library
, which shares exactly the same philosophy: it exposes a set of API to encourage desired testing practices (test what end users see but not implementation detail). Similarly, Theme UI exposes a set of API to encourage desired styling practices, that is, consistent and responsive.