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.
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
https://gist.github.com/d99ae7890470f188280ede3afee7badd
And then you can define your css: https://gist.github.com/1c014e908817add02a8ce58c8d723b2f
Here 3
does not mean 3px
, but actually the third value in the space scale array. It is basically equal to:
https://gist.github.com/59bfe0f3b0a696fb2c51c33855e95066
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.
As you see above, you can put a sx
prop to style a component. There you have access to the theme.
https://gist.github.com/66e5680be2ba782802f41a57bf305ae0
A problem I have though, is not able to add sx
to a custom component
https://gist.github.com/721954bfd723c12affb0e814b601a129
But emotion actually lets you do that.
https://gist.github.com/b38168f8e491dc8ca77407a773666399
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.
I live this feature most and it is really powerful and beautiful. You can define some breakpoints
In your theme
https://gist.github.com/2a22e6081cd2209aa0df805bfa6f119c
Then you can have any array for your css, whose value corresponds to the screen size defined in the theme breakpoints.
https://gist.github.com/b535562f96ec77f6151a3569d55226d5
Boom! You have a responsive font! You don’t need any media query to make responsive design!
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
https://gist.github.com/89463657b29db4fe31874f88d9799433
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
https://gist.github.com/bda046d8188b4be8d74eec3bcdc8a090
You do still have access to the theme, but you end up with more code https://gist.github.com/997b95197f4ee15ae1dae56a155ee372
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.
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.
Style guide driven development in React with Theme UI – Mitch Gavan
#tech/js/css #writing/draft