Discovering Theme UI

May 07, 2020

One of my first challenges in my new role has been to make changes to gatsby-plugin-theme-ui. As it turns out, it’s a pretty sparse plugin, more of a passthrough than anything.

So, how hard could adding functionality be?

As it turns out, quite difficult if you’ve never used Theme UI in your life! I consider myself a bit of a global styles girl. My closest experience with CSS-in-JS is the way Vue does scoped styles. Which is to say, not really close at all.

But over the past few weeks I’ve learned quite a bit and thought I’d share it with you all.

A “theme”

Theme UI works off of a “theme”. I know, only slightly confusing since I work on Gatsby themes 😅.

In this case a theme is a JSON object that specifies styling in a number of different ways. You can checkout the base preset for an example of what I mean.

A theme can include various things. The most common is theme.colors that defines a series of colors such as primary, background, etc.

Themes can also specify typography with fonts, fontSizes, lineHeights and more.

The part of themes I spent a lot of time digging into was theme.styles. Much of what gets included in styles feels very familiar to global CSS people like me. You can assign styling for specific HTML tags such as h1, p, etc.

When I first started working with the theme.styles object I assumed it was applying the styling to the h1 tags in my site, but it didn’t appear to be! I was missing something pretty important to understanding Theme UI.

MDX

Theme UI was designed in large part to support styling MDX files. Seems natural that Gatsby uses it once you realize this!

So, as it turns out, my h1 tags do automatically receive my styles. However, it’s only the h1 tags that are generated from MDX.

# Like this!

h1’s in my JavaScript files have to do something else. But I’ll get back to that in a second.

pre

Once I realized that theme.styles is for MDX styling I started to understand the internal objects a lot better. One of those objects is theme.styles.pre. I’ve been playing around with theme.styles.pre quite a bit lately, and for good reason. When shadowing themes in Gatsby, code snippets in MDX get wrapped by a Prism component, like this.

import Prism from "@theme-ui/prism"
export default {
pre: props => props.children,
code: Prism,
}

When this happens, the Prism component uses prism-react-renderer to tokenize code snippets and create <span> elements with class names. This allows Theme UI to target those class names with styles found in the theme.styles.pre object.

Which means I can do something like this:

styles: {
pre: {
".variable": {
color: `#6F0DAB`,
},
}
}

Pretty cool stuff! Plus, it means I can take advantage of a number of prism presets Theme UI has available in its repo.

sx prop

Once I understood that theme.styles was for MDX, the sx prop made a lot more sense. sx allows you to make use of your Theme UI styles inside JSX. This can be inline styles, or reference your theme object directly.

/** @jsx jsx */
import { jsx } from 'theme-ui'
<div
sx={{
color: 'primary',
bg: '#FFC0CB',
}}
>
Let's test this out!
</div>

Note the pragma up top! That’s essential in order to leverage this feature.

Theme composition

One of the most interesting pieces of using Theme UI is the way styles compose. For example, when leveraging Gatsby themes, local styles perform a deep merge with whatever the theme sets. This allows you to make small changes without overriding everything.

What’s Next?

As it turns out, gatsby-plugin-theme-ui can do more than it’s doing right now. Make it easier to use the theme and prism presets that are available. Make it simpler to share those between projects.

Excited to finish up some new functionality and see what amazing things the community does with it. Theme UI is incredibly powerful, I might even give up my global styles 😜.


A blog by Laurie Barth.
Teacher of all things tech.