Everything's a box

Date published: 6-Jul-2020
2 min read / 629 words
Author: Paul Scanlon

React
Theme UI

In this post i'm going to introduce one of the concepts you can use when developing web pages/apps using Theme UI

If you're not familiar with Theme UI take a moment to have a read of the docs... and if you're not familiar with CSS-in-Js perhaps have a read up on that first.

I'm going to talk about one quite complicated but in my opinion unnecessary part of Theme UI and it's something that took me a while to work out since the docs don't really mention this in a clear and concise way.

It's my hope that this post might clarify a couple of things and help lower the barrier to entry when using Theme UI. I won't go into detail about how the CSS properties link to the their respective scales or keys... that's a post for another time.

In the docs you'll see a code snippet like this.

/** @jsx jsx */
import { jsx } from "theme-ui"
export default (props) => (
<div
sx={{
fontWeight: "bold",
fontSize: 4,
color: "primary",
}}
>
Hello
</div>
)

When i first saw this i was like "What the flip is @jsx", and "where's the import for React" ... and then after a while i read on and started to understand what jsx pragma actually is.

The TLDR version is as follows.

When you include /** @jsx jsx */ in your React component you don't need to import React. This because the jsx pragma kind of includes the functionality to transform JSX for us. The jsx pragma also allows a new "type" of HTML attribute, it's called the sx prop which can be applied to any normal HTML element.

With the sx prop you can now style you UI using Theme UI's super powers.

If you'd like to know about more, have a read of this: What is JSX Pragma

No more naming of CSS classes, or importing global variables 🤢 and in no way will we need to worry about order of specificity 🙌... nice ay!

But...

Importing jsx and having to explain the jsx pragma is all a bit unnecessary so i'm proposing we try this another way.

Instead of doing what the docs say, try this approach instead.

import React from "react"
import { Box } from "theme-ui"
export default (props) => (
<Box
sx={{
fontWeight: "bold",
fontSize: 4,
color: "primary",
}}
>
Hello
</Box>
)

You can see from the above that we don't need to import the jsx pragma and instead we can import React as we normally would and then use one of the components that ships with Theme UI.... The <Box />

The Box is technically just a div but if you inspect the below you'll see there's a few things Theme UI does for us which will save us time later.

JavaScript for Box 👇

<Box>I'm a Box</Box>
I'm a Box

JavaScript for div 👇

<div>I'm a div</div>
I'm a div

CSS for Box 👇

display: block;
box-sizing: border-box;
margin: 0;
min-width: 0;

CSS for div 👇

display: block;

You can see from the above that the CSS for the <Box /> includes some resets for us, eg. box-sizing,margin and min-width and whilst in the past we could have used a global CSS file that handles the resets, we don't want to use global CSS because this is where problems arise.

Global styles and the dreaded !important are escape hatches. These are work arounds we've developed over the years to compensate for some of the shortcomings of native CSS. But in the new world of CSS-in-Js these native shortcomings have been removed which allows us to spend more time focussing on actually building something.

But wait, there's more, here's the <Flex /> component that ships with Theme UI

JavaScript for Flex 👇

<Flex>I'm a Flex</Flex>
I'm a Flex

CSS for Flex 👇

display: flex;
box-sizing: border-box;
margin: 0;
min-width: 0;

...and you can see from the CSS snippet that the defaults that come with this component save us the time of adding them ourselves. e.g <Flex /> already has display: flex; Cool ay! 😎

One last thing. Theme UI also allows the Polymorphic as prop. Poly meaning many, and morphic meaning forms so you can do things like this.

JavaScript for aside 👇

<Box as="aside">I'm an aside</Box>

CSS for aside 👇

display: block;
box-sizing: border-box;
margin: 0;
min-width: 0;

You'll see if you inspect the "I'm man aside" element that the actual HTML element is in fact an <aside /> and it still inherits all the resets from <Box />

The as props works with all manner of HTML elements... even inputs

So now you know.

Everything's a <Box />



If you've enjoyed this post I'd love to hear from you: @PaulieScanlon