Design with Consistency: Learn how to Build a Design System with React and Storybook

In this blog, we'll explore the basics of design systems and learn how to create a simple design system using React and Storybook.

What is a design system?

A design system is a set of rules, guidelines, and components that help designers and developers create consistent, efficient, and cohesive user interfaces. It includes all the building blocks needed to create a product, such as typography, color schemes, spacing, layout, and components.

Design systems promote consistency and reduce the time and effort required to design and develop a product. They also help create a better user experience by ensuring that all the elements of a product work together harmoniously.

Creating a simple design system using React and Storybook

React is a popular JavaScript library for building user interfaces, while Storybook is a tool for developing UI components in isolation. In this section, we'll create a simple design system using React and Storybook.

Step 1: Setting up the environment

First, we need to set up the development environment. We'll need Node.js and npm installed on our machine. Once we have those installed, we can create a new React project using the following command:

<span><span style="color: var(--shiki-color-text)">   npx </span><span style="color: var(--shiki-token-string)">create-react-app</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">design-system</span></span>
<span></span>

Next, we'll navigate to the project directory and install the following dependencies:

<span><span style="color: var(--shiki-color-text)">  npm </span><span style="color: var(--shiki-token-string)">install</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--save</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">react</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">react-dom</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">prop-types</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">styled-components</span></span>
<span><span style="color: var(--shiki-color-text)">  npm </span><span style="color: var(--shiki-token-string)">install</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">--save-dev</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">@storybook/react</span></span>
<span></span>

Step 2: Creating the components

In this example, we'll create a Button component and a Header component. The Button component will be a simple button with a background color and a text label. The Header component will be a navigation bar with a logo and links.

We'll create these components in the src/components directory.

Button component Create a new file Button.js in the src/components directory and add the following code:

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> React </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;react&#39;</span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> PropTypes </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;prop-types&#39;</span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> styled </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;styled-components&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">ButtonWrapper</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">styled</span><span style="color: var(--shiki-token-string-expression)">.</span><span style="color: var(--shiki-token-function)">button</span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  background-color: </span><span style="color: var(--shiki-token-keyword)">${</span><span style="color: var(--shiki-color-text)">(props) </span><span style="color: var(--shiki-token-keyword)">=&gt;</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">props</span><span style="color: var(--shiki-color-text)">.backgroundColor</span><span style="color: var(--shiki-token-keyword)">}</span><span style="color: var(--shiki-token-string-expression)">;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  color: white;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  padding: 10px 20px;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  border: none;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  border-radius: 5px;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  cursor: pointer;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Button</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> ({ backgroundColor</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> label }) </span><span style="color: var(--shiki-token-keyword)">=&gt;</span><span style="color: var(--shiki-color-text)"> (</span></span>
<span><span style="color: var(--shiki-color-text)">  &lt;</span><span style="color: var(--shiki-token-constant)">ButtonWrapper</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">backgroundColor</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)">{backgroundColor}&gt;{label}&lt;/</span><span style="color: var(--shiki-token-constant)">ButtonWrapper</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">)</span></span>
<span></span>
<span><span style="color: var(--shiki-token-constant)">Button</span><span style="color: var(--shiki-color-text)">.propTypes </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> {</span></span>
<span><span style="color: var(--shiki-color-text)">  backgroundColor</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">PropTypes</span><span style="color: var(--shiki-color-text)">.</span><span style="color: var(--shiki-token-constant)">string</span><span style="color: var(--shiki-color-text)">.isRequired</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">  label</span><span style="color: var(--shiki-token-keyword)">:</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">PropTypes</span><span style="color: var(--shiki-color-text)">.</span><span style="color: var(--shiki-token-constant)">string</span><span style="color: var(--shiki-color-text)">.isRequired</span><span style="color: var(--shiki-token-punctuation)">,</span></span>
<span><span style="color: var(--shiki-color-text)">}</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">default</span><span style="color: var(--shiki-color-text)"> Button</span></span>
<span></span>

The Button component is a simple button with a background color and a text label. It uses the styled-components library to create a styled button component. The Button component takes two props: backgroundColor and label.

Create a new file Header.js in the src/components directory and add the following code:

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> React </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;react&#39;</span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> styled </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;styled-components&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">HeaderWrapper</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">styled</span><span style="color: var(--shiki-token-string-expression)">.</span><span style="color: var(--shiki-token-function)">header</span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  display: flex;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  justify-content: space-between;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  align-items: center;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  padding: 20px;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  background-color: #333;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">Logo</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">styled</span><span style="color: var(--shiki-token-string-expression)">.</span><span style="color: var(--shiki-token-function)">div</span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  color: white;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  font-size: 2rem;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  font-weight: bold;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">Nav</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">styled</span><span style="color: var(--shiki-token-string-expression)">.</span><span style="color: var(--shiki-token-function)">nav</span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  display: flex;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">NavItem</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">styled</span><span style="color: var(--shiki-token-string-expression)">.</span><span style="color: var(--shiki-token-function)">a</span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  color: white;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  margin: 0 10px;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">  text-decoration: none;</span></span>
<span><span style="color: var(--shiki-token-string-expression)">`</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">const</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">Header</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-color-text)"> () </span><span style="color: var(--shiki-token-keyword)">=&gt;</span><span style="color: var(--shiki-color-text)"> (</span></span>
<span><span style="color: var(--shiki-color-text)">  &lt;</span><span style="color: var(--shiki-token-constant)">HeaderWrapper</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">    &lt;</span><span style="color: var(--shiki-token-constant)">Logo</span><span style="color: var(--shiki-color-text)">&gt;MyDesignSystem&lt;/</span><span style="color: var(--shiki-token-constant)">Logo</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">    &lt;</span><span style="color: var(--shiki-token-constant)">Nav</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">      &lt;</span><span style="color: var(--shiki-token-constant)">NavItem</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">href</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;#&quot;</span><span style="color: var(--shiki-color-text)">&gt;Home&lt;/</span><span style="color: var(--shiki-token-constant)">NavItem</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">      &lt;</span><span style="color: var(--shiki-token-constant)">NavItem</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">href</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;#&quot;</span><span style="color: var(--shiki-color-text)">&gt;About&lt;/</span><span style="color: var(--shiki-token-constant)">NavItem</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">      &lt;</span><span style="color: var(--shiki-token-constant)">NavItem</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">href</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;#&quot;</span><span style="color: var(--shiki-color-text)">&gt;Contact&lt;/</span><span style="color: var(--shiki-token-constant)">NavItem</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">    &lt;/</span><span style="color: var(--shiki-token-constant)">Nav</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">  &lt;/</span><span style="color: var(--shiki-token-constant)">HeaderWrapper</span><span style="color: var(--shiki-color-text)">&gt;</span></span>
<span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-token-keyword)">export</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-keyword)">default</span><span style="color: var(--shiki-color-text)"> Header</span></span>
<span></span>

The Header component is a navigation bar with a logo and links. It also uses styled-components to create a styled component. The Header component does not take any props.

Step 3: Creating stories in Storybook

Next, we'll create stories for our components in Storybook. Stories are a way to develop UI components in isolation, without the need for a full application.

Create a new directory src/stories and add the following files:

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> React </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;react&#39;</span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { storiesOf } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;@storybook/react&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> Button </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;../components/Button&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-function)">storiesOf</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;Button&#39;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">module</span><span style="color: var(--shiki-color-text)">)</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-function)">.add</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;Primary&#39;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> () </span><span style="color: var(--shiki-token-keyword)">=&gt;</span><span style="color: var(--shiki-color-text)"> &lt;</span><span style="color: var(--shiki-token-constant)">Button</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">backgroundColor</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;#0074D9&quot;</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">label</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;Click me&quot;</span><span style="color: var(--shiki-color-text)"> /&gt;)</span></span>
<span><span style="color: var(--shiki-color-text)">  </span><span style="color: var(--shiki-token-function)">.add</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;Secondary&#39;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> () </span><span style="color: var(--shiki-token-keyword)">=&gt;</span><span style="color: var(--shiki-color-text)"> &lt;</span><span style="color: var(--shiki-token-constant)">Button</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">backgroundColor</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;#FF4136&quot;</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-function)">label</span><span style="color: var(--shiki-token-keyword)">=</span><span style="color: var(--shiki-token-string-expression)">&quot;Click me&quot;</span><span style="color: var(--shiki-color-text)"> /&gt;)</span></span>
<span></span>

The Button.stories.js file creates two stories for the Button component: a primary button and a secondary button. Each story sets a different background color.

<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> React </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;react&#39;</span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> { storiesOf } </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;@storybook/react&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-keyword)">import</span><span style="color: var(--shiki-color-text)"> Header </span><span style="color: var(--shiki-token-keyword)">from</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string-expression)">&#39;../components/Header&#39;</span></span>
<span></span>
<span><span style="color: var(--shiki-token-function)">storiesOf</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;Header&#39;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-constant)">module</span><span style="color: var(--shiki-color-text)">)</span><span style="color: var(--shiki-token-function)">.add</span><span style="color: var(--shiki-color-text)">(</span><span style="color: var(--shiki-token-string-expression)">&#39;Default&#39;</span><span style="color: var(--shiki-token-punctuation)">,</span><span style="color: var(--shiki-color-text)"> () </span><span style="color: var(--shiki-token-keyword)">=&gt;</span><span style="color: var(--shiki-color-text)"> &lt;</span><span style="color: var(--shiki-token-constant)">Header</span><span style="color: var(--shiki-color-text)"> /&gt;)</span></span>
<span></span>

The Header.stories.js file creates a single story for the Header component.

Step 4: Running Storybook

Finally, we can run Storybook to see our components in action. Run the following command to start Storybook:

<span><span style="color: var(--shiki-color-text)">npm </span><span style="color: var(--shiki-token-string)">run</span><span style="color: var(--shiki-color-text)"> </span><span style="color: var(--shiki-token-string)">storybook</span></span>
<span></span>

This will start a local server at http://localhost:6006. Open this URL in your browser to view the Storybook UI.

You should see the two components we created, along with their stories. You can interact with the components and see how they look in isolation.

Conclusion
In this blog, we explored the basics of design systems and learned how to create a simple design system using React and Storybook. We created two components, a Button and a Header, and added stories for each component in Storybook.

Design systems can be complex, but they provide significant benefits in terms of consistency and efficiency. By creating a design system for your project, you can ensure that your product looks and behaves consistently, which can lead to a better user experience.