How to Use Theme UI Tailwind CSS Preset

March 9th 2020

If you’ve read our article about using Tailwind CSS in Gatsby you know we are big fans of the Tailwind CSS library. As another option to using Tailwind in Gatsby we can turn to the Theme UI library to integrate Tailwind into our Gatsby or React application.

The Theme UI library allows you to create constraint based, themeable design systems allow for consistent, mobile-first responsive styles. Theme UI layers nicely on top of React components and provides an sx prop for React components to define styles for your component which get extracted and scoped to each and every component you define. Scoped CSS allows you to specify styles for your components without worrying about scope leak or conflicts with global styles. The library also offers over 30 predefined components for layout/styling such as: containers, flex box parents, grid components and many more. On top of the other benefits of Theme UI, there are also over a dozen preset themes that you can import into your theme definition which have predefined typography, color palettes, responsive definitions, margin/padding sizes, width/height sizes, responsive breakpoints and many other predefined definitions. Today we’ll be looking at how to use the tailwind preset from Theme UI preset package to create and extend theme definitions.

Theme UI provides a higher order component ThemeProvider which you can pass your defined theme object so you can use the sx prop in child components to style your React components. We’ll assume you have a react project setup or if you are using Gatsby you can use gatsby-plugin-theme-ui to configure the ThemeProvider for gatsby sites. We will first need to install the theme-ui package for our project:

yarn add theme-ui
// or 
npm install theme-ui

We can now create file called theme.js in our src folder or if you are using gatsby-pugin-theme-ui you will create an index.js file in /src/gatstby-plugin-theme-ui folder to define your theme object. Since we are using Theme UI’s Tailwind CSS preset we will need to install the preset packages as well:

yarn add @theme-ui/presets
// or 
npm install @theme-ui/presets

With the theme-ui and @theme-ui/presets installed we can start defining our theme object in our theme.js (or gatsby-plugin-theme-ui index.js file). Our theme.js file will import our preset and export our default theme object such that:

import { tailwind } from '@theme-ui/presets'

export default {
  ...tailwind
}

This basic export spreads the tailwind preset so that we are inheriting all of the preset library’s definitions and styles. This will give us a lot of options out of the box to use in our sx prop definitions but we will extend the preset to customize the theme object a bit more. Before we customize our object we can take a quick look at what some of the theme definitions look like out of the box.

Responsive Breakpoints

By default the theme defines 4 different breakpoints:

{
  ...
  "breakpoints": [
    "640px",
    "768px",
    "1024px",
    "1280px"
  ],
  ...
}

These breakpoints are definitions for the mobile-first media queries that will be converted to min-width definitions and in which you can use for defining specific width, sizes, margin, padding and other properties in your sx prop by using an array definition such that:

<div
  sx={{
    width: ['100%', '49.999%', '33.333%', '20%']
  }}>

This definition would be converted to @media queries such that the width for the div would be 100% at a min-width: 640px all the way to 20% at a min-width: 1280px

Theme UI, like Styled System, includes a shorthand syntax for writing mobile-first responsive styles using arrays as values. This is useful when you want to change a single property across multiple breakpoints without needing to write verbose media query syntax.

theme-ui.com

If we need to add more custom breakpoints we can extend this property to add further breakpoints:

import { tailwind } from '@theme-ui/presets'

export default {
  ...tailwind,
  breakpoints: [
    ...tailwind.breakpoints,
    '1520px'
  ]
}

This is going to spread all of the preset’s definitions and override the breakpoints property while spreading the breakpoints array and adding a fifth breakpoint definition at 1520px for large screens.

Defining Colors

Your color palette for you theme is one of the most important and used utilities in your styling definitions. You will be using the color properties a lot as you are styling your components. Tailwind CSS has a robust default color palette out of the box with a lot of color definitions. To access the default color properties you will need to use functional property values to access Tailwind’s default color paragraph such as:

/** @jsx jsx */
import { jsx } from 'theme-ui'
export default props => (
  <div
    {...props}
    sx={{
      boxShadow: theme => `0 0 4px ${theme.colors.gray[5]}`,
    }}
  />
)

Looking at the default gray color palette for the theme you will see at index 5 the color definition resolves to #a0aec0

"colors": {
    "transparent": "transparent",
    "black": "#000",
    "white": "#fff",
    "gray": [
      null,
      "#f7fafc",
      "#edf2f7",
      "#e2e8f0",
      "#cbd5e0",
      "#a0aec0",
      "#718096",
      "#4a5568",
      "#2d3748",
      "#1a202c"
    ],
    ...
}

There are also string definitions that we can use in the sx property definition and we will look at how we can customize these to our own theme palette:

"colors": {
    ...
    "grayDark": "#2d3748",
    "text": "#2d3748",
    "background": "#fff",
    "primary": "#2b6cb0",
    "primaryHover": "#2c5282",
    "secondary": "#718096",
    "muted": "#e2e8f0",
    "success": "#9ae6b4",
    "info": "#63b3ed",
    "warning": "#faf089",
    "danger": "#feb2b2",
    "light": "#f7fafc",
    "dark": "#2d3748",
    "textMuted": "#718096"
    ...
}

In our sx props we would reference these string properties such as

/** @jsx jsx */
import { jsx } from 'theme-ui'
export default props => (
  <div
    {...props}
    sx={{
      color: 'primary',
    }}
  />
)

Let’s say we wanted to override or define our primary, secondary definitions and add another property accent we can edit our theme.js file to look like:

import { tailwind } from '@theme-ui/presets'

export default {
  ...tailwind,
  breakpoints: [
    ...tailwind.breakpoints,
    '1520px'
  ],
  colors: {
    ...tailwind.colors,
    primary: '#012e57',
    secondary: '#5fc1ee',
    accent: '#8dc73f'
  }
}

We can now access these in our sx prop definition such that:

<div
  sx={{
    color: 'primary',
    borderColor: 'secondary',
    '&:hover': {
      color: 'accent'
    }
  }}>

Styled components

Not to be confused with the styled-components library for react components, Theme UI has a Styled component that allows you to render UI for various html elements with styles defined in the theme’s theme.styles property. Each element defined in this property can be composed and reused using the syntax: Styled.elementProperty. For example, if you have defined styles in theme.js:

import { tailwind } from '@theme-ui/presets'

export default {
  ...tailwind,
  breakpoints: [
    ...tailwind.breakpoints,
    '1520px'
  ],
  colors: {
    ...tailwind.colors,
    primary: '#012e57',
    secondary: '#5fc1ee',
    accent: '#8dc73f'
  },
  styles: {
    h1: {
      fontSize: 32,
      fontFamily: 'heading',
      fontWeight: 'heading',
      color: 'primary',
      mt: 4,
      mb: 2,
    },
  }
}

You can use the Styled component from the theme-ui library to access Styled.h1 such that:

import { Styled } from 'theme-ui'
export default props => (
  <div>
    <Styled.h1>Hello, styled heading!</Styled.h1>
  </div>
)

And the <h1> tag will be rendered with the styles defined in styles.h1 from your theme.js file.

Tailwind comes with a number of predefined Styled components but you can always add more (or override the tailwind preset) as so:

import { tailwind } from '@theme-ui/presets'

export default {
  ...tailwind,
  breakpoints: [
    ...tailwind.breakpoints,
    '1520px'
  ],
  colors: {
    ...tailwind.colors,
    primary: '#012e57',
    secondary: '#5fc1ee',
    accent: '#8dc73f'
  },
  styles: {
    ...tailwind.styles,
    span: {
      color: 'primary',
      mx: 2,
      pb: 2
    },
  }
}

And then use <Styled.span>My span</Styled.span> inside your components file.

Variants

To add groups of styles (possibly based on theme values), you can take advantage of the Variants feature. Variants are similar to Styled components which let you define a certain set of styles for each variant definition. The power in variants is that you can define multiple types of one variant such as button.primary and button.secondary and use the theme’s primary and secondary colors to coordinate the styles for the variants:

{
  colors: {
    primary: '#07c',
    secondary: '#639',
  },
  buttons: {
    primary: {
      color: 'white',
      bg: 'primary',
    },
    secondary: {
      color: 'white',
      bg: 'secondary',
    },
  },
}

Now in your components you can access the buttons variant like so:

<button sx={{ 
  variant: 'buttons.primary'
}} />

The { tailwind } preset from @theme-ui/presets has a few button variants and input variants defined for us that we can use out of the box and add more variants as we see fit.

We’ve done a deep dive into the Theme UI system and specifically into the Tailwind CSS preset that the Theme UI Preset package offers us. We’ve looked at how to extend the Tailwind preset to customize it for our theme. Lastly, we’ve looked at how to use the sx prop to define the styles for each component using our theme’s setting we defined. Hopefully you can use this powerful framework along with the tailwind preset to style your next React project.