Extendable atomic design UI with styled-components and React
I’m not going to cover the details of atomic design methodology so if you aren’t familiar, I’d recommend reading this first → Atomic Design
Another helpful post that takes the atomic design principles and applies them using React → Managing Dynamic React Components using Atomic Design
In this post I will share the approach CollegeVine took to implement atomic design using styled-components and React. I will also cover how to build this for extensibility and changes to your design system down the road.
The core of our atomic component system is our ThemeProvider. The theme we define using ThemeProvider will set the base colors, available font sizes, weights, families and anything else we’d like to use in our components to style them according to our design system. Having them in one place has multiple advantages. We can quickly make changes to our base styles in one place and with the power of theming in styled-components, we can quickly create re-skinned versions of our atomic components without having to modify their code.
Code example time!
Here’s a basic theme setup that will allow us to pass a theme prop to our components containing our base style information.
For the next step, to increase the compose-ability of our components, we are going to make a distinction between things that have text and things that display text, like a p
or span
HTML element, so we can leverage more styled-components goodness.
Instead of styling a p
tag with our theme props, we are going to define a mixin for things that display text and then use that inside of our text component atoms. This will allow us to use our base text style themes in other components without having a mess of styled components that extend each-other so they can gain each others base styles.
More Examples!
First, lets set up the base styles for how text should appear on our site.
In addition the base styles, we are also exporting prop types that are required as well as default props. Defining default props that are the default value of your theme itself allow your component to use the theme but not require its presence. Assuming you apply these default props to your component as you’ll see in the next example, you could just import it into a fresh app with no theme applied and it would render correctly.
Now we tie our base text styles to our first component. Paragraph
now gets its text styles from our mixin but can also express additional styles that make it uniquely a paragraph.
The benefit of this approach is more apparent when you start building out additional components. Let’s take the same approach and build a button.
First we will add some new theme variables for our button.
Then we create a base for our button styles as we did with text, however this time we will use the base text styles as a foundation for our button styles since they also contain text.
And then the component definition
Now your paragraph and button are sharing styles based on your theme and you can change these styles at any time by tweaking your theme file.
This is a fairly basic example that only covers a few atomic components. Following this pattern of not only defining atomic react components but breaking down and composing their styles in a similar way will leave your components only caring about the styles that make them themselves and allows us to break out of declaring redundant styles.
Once you start gluing these together for your molecules and organisms, things only get easier since the foundation has been laid and each successively larger component you build will only have to worry about the things that make it unique.
Here’s a live code sandbox of the code from this article, along with additional examples of style overriding, theme overriding, and more!
You can also clone the repository on GitHub