One of the most popular CSS-in-JS solutions out there is styled-components, and one of its killer features is the ability to easily create themes for your React applications. There are many ways to work with themes, and in this article I'll share my method that revolves around creating reusable helper functions to simplify the process and reduce the amount of code involved in styling. We'll also touch on using the polished library to add some pizzazz and further functionality to a styled-components
theme.
My motivation for this pattern was to achieve the same ease that Sass and Stylus offer for writing functional CSS; I believe that the combination of styled-components
and polished
comes really close.
Set up a new create-react-app
project and add the dependencies (or add to an existing project) - go ahead and delete everything except App.js
and index.js
in /src:
https://gist.github.com/d915fd437ca520243d894a4eccc25402
styled-components
themes work with the Context API via a <ThemeProvider />
component. In index.js
, import the component and theme and wrap <App />
:
https://gist.github.com/6dbd004ad9d4482ec1295363cab28b02
<ThemeProvider /> takes one prop, an object called
theme; create the
theme.js` file that was imported and set up the values:
https://gist.github.com/50b0201f1c940ff26e11109cce8c3a16
Let's use our theme colors and sizes in <App />
in a styled component:
https://gist.github.com/24ecfe9fad17ee23d61b091ac6200930
Hm. The syntax is kind of...bulky - we have the use the name of the property of the property of the theme object of the props each time. How can we simplify this?
Functions to the rescue! Let's create some reuseable helpers functions to make it easier to access theme values. In theme.js
:
https://gist.github.com/72f9f4a7c879591d70a4a81a105f994e
Now we can import and use this function anytime we need a color in a styled component:
https://gist.github.com/f324e9932e46bed117f1991aad747c36
Let's do the same for sizes:
https://gist.github.com/e67298094c999a5415b483029048a294
https://gist.github.com/5cc218b82c2b221ca297783e931d0670
Alright, maybe it's not that much less code right now, but this pattern really shines when you're dealing with complex themes and nested theme objects. It puts the power of JavaScript functions in your hands for managing theme styling.
Lastly let's use some polished
features via helper functions in theme.js
:
https://gist.github.com/edf0fc83dcaf8f2bfe38b1efd50211a3
In <App />
let's use this on a new styled component:
https://gist.github.com/64e70d82d8ba351b7e7903c39fce7486
If you've used Sass's lighten feature, this should feel familiar.
Why can't we just import lighten
directly into the component? Try it - ${lighten(getColor('secondary'), '0.2')}
- it isn't parsed correctly. Keeping it in the theme means it's only imported from polished
once, and doesn't rely on having direct access to getColor
in the component.
One more - let's utilize the rgba
feature from polished for easily controllable text shadows:
https://gist.github.com/402311ba23a9959739b6177fce16eb93
rgba
automatically converts hex values to rgb values (exactly like the Sass function of the same name). This is great because it means we don't have to re-declare color values in different formats; the availability of default parameters is also a nice tool for setting base values. Add to <Content />
:
https://gist.github.com/81da74a4ebf1b138e98732c17a73b9b5
That wraps up my method of theming styled-components
; functions make for a powerful, infinitely expandable system. In the example project you'll also find a simple grid component created with breakpoint values in the theme.