bitoverflow logobitoverflow logo
Navigate back to the homepage

Storybook: Doing Component Development the right way

Sachin Thakur
March 1st, 2020 · 6 min read

Nowadays, if you have ever tried to build a user interface you might have come across many problems. Building these interface components is a very expensive and effort consuming task. We have designers, product managers and many developers working on a single project.

The modern User interfaces are built with thousands of UI components that are reused between different screens and different user interfaces and sometimes between different products inside the same company to make the design look consistent. Now usually in these scenarios, there are design systems in place with the catalogs of all the reusable components in one place. This helps improves the productivity of the developers by up to 30–40%. Modern UI interfaces are build from thousands of reusable UI components

image placeholder

Now here Design System contains reusable components which can be used among different application to build complex, durable and accessible user interfaces. Since both designs and developers contribute to a Design system so it servers as a “single source of truth” where designs can test the Component design they build in different scenarios.

When Do we need a design system?

Now despite all the hype and pros of a design system, it is not for everyone. If you are working on a single project, you will be better off without a design system. It will just add to the complexity of your application. But if you sharing your components across different projects then building a designing a design system makes sense for you rather then copy and pasting component from one place to another.

image placeholder

okay, So what exactly does storybook do?

Storybook is used by developers for the following reasons

  1. Building the UI component in isolation
  2. To prevent UI bugs
  3. Standardizing Styling across different Projects
  4. Distributing UI Components among different projects

Okay, Great but how will Storybook help me?

UI/UX Designers

UI/UX designs can go into the storybook to see how exactly the components look and feel in different scenarios, see all the states of the component, how they are behaving in these different state changes and provide your valuable feedback.

Developers

Developers can easily share these components between different projects and see how exactly they are being used what properties do these components have and how they can extend them. This speeds up the development process since now you just have to build your component once and just import and use it elsewhere. Codesharing becomes easier and side effects can be easily handled at one single place.

image placeholder

Getting Started with React Storybook

Now the storybook book can be used with almost every frontend framework possible, and there are a lot of them. Why can we stick with just one and make it standard? Okay, enough of the framework rant. let us start with React. You can find documentation for other frameworks here.

Installing React Storybook

Now since Storybook is a part of the javascript ecosystem you can install it using your favorite package manager. For this introduction, I’m going to use yarn but npm also works the same way.

1yarn global add @storybook/cli

It will globally install storybook CLI on your system. if you don’t want to permanently install storybook CLI you can also use npx. Read more about this here.

Now all we need a React application. And we are going to create that using create-react-app. Install creat-react-app in your by running following command in your system.

1yarn create react-app storybook-intro --typescript
2cd storybook-intro

image placeholder

You can read more about create-react-app here. Now let’s start by adding storybook to our project.

Now run the following command to add storybook to your project.

1getstorybook

Now if you notice there are some extra folders add to your project.

image placeholder

.storybook is used for configuring storybook. we will do that later.

Now run

1yarn storybook

Now if you go to http://localhost:9009/ you will see the following page. Now make sure to restart your server whenever you change any config or add any new package.

image placeholder

Now let’s start building some component then we will see how we can configure storybook and make it more powerful and fully utilize its purpose.

So let’s create a basic component. Let’s start with a button.

1import React from "react";
2
3import "./index.css";
4
5interface IButtonProps {}
6const Button: React.FC<IButtonProps> = () => {
7 return (
8 <>
9 <button className="button">Primary Button</button>
10 </>
11 );
12};
13
14export default Button;
15export { Button };

Add the following CSS

1.button {
2 background-color: #4caf50; /* Green */
3
4 border: none;
5
6 color: white;
7
8 padding: 15px 32px;
9
10 text-align: center;
11
12 text-decoration: none;
13
14 display: inline-block;
15
16 font-size: 16px;
17
18 margin: 4px 2px;
19
20 cursor: pointer;
21}
22.primary {
23 background-color: #008cba;
24}
25
26.danger {
27 background-color: #f44336;
28}

Now let’s add a story for this component. btw you can delete the stories folder we don’t need anyway. Now create a new file button.stories.TSX alongside your button component.

image placeholder

Now let’s create our first story inside button.stories.tsx

1import React from "react";
2
3import { Button } from "./index";
4
5export default {
6 title: "Button",
7
8 component: Button,
9};
10
11export const Primary = () => <Button>Hello Button</Button>;

Let’s start the storybook server again and let’s see how our story looks.

image placeholder

Okay, we don’t see our newly added story. But why is that? If we go to .storybook/config.js file we see that the storybook is configured for javaScript, not TypeScript.

image placeholder

Now let’s configure it for TypeScript. This can easily be solved by just adding the correct regex in stories.

1../src/**/*.stories.(ts|tsx|js|jsx)

image placeholder

It will pick all the JSX/TSX/js/ts files in the project. Now if you go to localhost:9009 we see our story. Make sure you restart the storybook server since this is a configuration change.

image placeholder

Now let’s make our component a little more standard so we can expect some props and make changes.

1import React from "react";
2
3import "./index.css";
4
5interface IButtonProps {
6 buttonText: string;
7
8 primary?: boolean;
9
10 danger?: boolean;
11}
12
13const Button: React.FC<IButtonProps> = (props) => {
14 const { buttonText, primary, danger } = props;
15 let styles;
16 primary ? (styles = "primary") : danger ? (styles = "danger") : (styles = "");
17
18 return (
19 <>
20 <button className={"button" + " " + styles}>{buttonText}</button>
21 </>
22 );
23};
24
25export default Button;
26export { Button };

Now since we update we also need to update our storybook component to send in these props which we just added to our component.

1import React from "react";
2
3import { Button } from "./index";
4
5export default {
6 title: "Button",
7
8 component: Button,
9};
10
11export const Primary = () => (
12 <Button buttonText="Primary Button" primary={true} />
13);
14
15export const DangerButton = () => (
16 <Button buttonText="Danger Button" danger={true} />
17);

Now if we go back to our storybook we see 2 stories. One with Primary Button and one with Danger Button.

image placeholder

Now, This is just the isolation part of the development. we developed a storybook component in isolation but how do we tell other developers that we are expecting all these props like button text, primary, danger and they can change these to change the appearance of the button. That’s where storybook add-ons come to play which makes storybook so powerful for building a common component library.

Storybook has several recommended add-ons

  • a11y — Test components for user accessibility in Storybook
  • actions — Log actions as users interact with components in the Storybook UI
  • knobs — Interactively edit components input data in the Storybook UI
  • source — View a Stories code within the Storybook UI
  • viewport — Change display sizes and layouts for responsive components using Storybook. This can help you build responsive layouts

You can see all the add-ons here. On top of this, you can create your addon if you want. Learn more about that here.

Now let’s add some add-ons to our little project. Let’s start with the knobs add-on so that we can interact with our component.

Installation

First, we need to install the add-on to our project

1yarn add @storybook/addon-knobs @types/storybook__addon-knobs

Now register knob in your .storybook/main.js file

1// .storybook/main.js
2
3module.exports = {
4 stories: ["../src/**/*.stories.(ts|tsx|js|jsx)"],
5
6 addons: [
7 "@storybook/preset-create-react-app",
8
9 "@storybook/addon-actions",
10 "@storybook/addon-links",
11 "@storybook/addon-knobs",
12 ],
13};

Now let’s add the newly added knob there. Go to the .storybook folder and create new file config.js and add the newly added addon there. Adding addon like this will it to all the stories. If you just want want to add the addon to only one story that can also be done. You can read about that here. But if you are building a library you won’t be adding add-ons one by one to each file. So let’s start by creating a config.js file.

1// .storybook/config.js
2
3import { withKnobs } from "@storybook/addon-knobs";
4import { addDecorator } from "@storybook/react";
5
6addDecorator(withKnobs);

image placeholder

Now before we see any changes with our storybook we need to use knob inside our story. So now go to button.stories.tsx and use the knob. Now the knob provides us with a lot of knobs like text, boolean, object depending on your data type. Now in our case, we only need text and boolean since these are the only types we support in our button component. Now import the appropriate knob from the @storybook/addon-knobs

1// Button/button.stories.tsx
2
3import { text, boolean } from "@storybook/addon-knobs";

Now go to the component story and use the knob as follows.

1// PrimaryButton inside Button/button.stories.tsx
2<Button
3
4buttonText={text("Button Text", "Primary Button")}
5
6primary={boolean("Primary button", true)}
7
8/>
9
10// DangerButton inside Button/button.stories.tsx
11
12<Button
13
14buttonText={text("Button Text", "Danger Button")}
15
16danger={boolean("Danger Button", true)}
17
18/>

Now if you go back to localhost:9009/ you see your newly added knobs in action.

image placeholder

Now we can change the text of the button and use boolean to set the state of the button and see how the button behaves when its state changes.

Another very useful addon is the info. Now when you install it every story in your library gets a Documentation page. These can be used for documenting your component so the other developer can understand how and why it can be used.

To add this addon just install the addon

1yarn add @storybook/addon-info @types/storybook__addon-info

Now, lets first register it to our main.js file onto our addons.

1// .storybook/main.js
2module.exports = {
3 stories: ["../src/**/*.stories.(ts|tsx|js|jsx)"],
4
5 addons: [
6 "@storybook/preset-create-react-app",
7
8 "@storybook/addon-actions",
9
10 "@storybook/addon-links",
11
12 "@storybook/addon-knobs",
13
14 "@storybook/addon-info",
15 ],
16};

After this, we also need to configure this addon to work with our storybook so go to config.js and register this new addon.

1// .storybook/config.js
2
3import { withKnobs } from "@storybook/addon-knobs";
4
5import { addDecorator, addParameters } from "@storybook/react";
6
7import { withInfo } from "@storybook/addon-info";
8
9addDecorator(withInfo);
10
11addDecorator(withKnobs);

Now go back to your button story and configure this addon.

1import PropTypes from "prop-types";
2
3import { Button } from "./index";
4
5export default {
6 title: "Button",
7
8 component: Button,
9
10 parameters: {
11 info: { inline: false },
12 },
13};
14
15Button.propTypes = {
16 buttonText: PropTypes.string.isRequired,
17
18 primary: PropTypes.bool,
19
20 danger: PropTypes.bool,
21};

We just need can use the info the parameter to either pass certain options or specific documentation text to your stories. and add prop types to show the props received by the button component info. It is also possible to disable the add-on entirely. Depending on the scope at which you want to disable the addon. Just pass info:{disable:true} Now if we go back to localhost:9009/ after restarting the server we see a new section called show info on the top right corner.

image placeholder

Now if we go to docs we don’t see anything interesting. Just the component and how it is being used.

image placeholder

Now let’s add some documentation to better elaborate this component what it does and how it should be used. We can pass another key to info the called text which describes what the component does and how it can be used.

image placeholder

Now after adding the text if we go back to localhost:9009/ and click on show info we see our documentation of the component.

image placeholder

Conclusion

As you see throughout this article, Storybook is easy to use and has a lot of add-ons and make it easy for the code to be shared among different project along with the proper documentation and we can build all our components in isolation and all the team members can see what components have been built and how they can use these components. And if a new person joins he won’t have to worry whether a component has been build or how to use a component. This significantly reduces the development time and helps strengthen your interfaces and make them consistent throughout different projects.

P.S :- all code for this article is available here

Join my email list and get notified about new content

Be the first to receive my latest content with the ability to opt-out at anytime. I promise to not spam your inbox or share your email with any third parties.

More articles from Sachin Thakur

TypeScript -JavaScript on steroids

Learn more about TypeScript and how it helps in being more efficient in your application development

October 23rd, 2019 · 4 min read

How and why I built A nodeJs-MongoDb Starter kit

The main reason for building this Starter Code was to help others and myself by not going through that process of installing and following the same steps again and again to create even a simple API.

October 16th, 2018 · 2 min read
© 2018–2020 Sachin Thakur
Link to $https://twitter.com/thakursachin467Link to $https://github.com/thakursachin467Link to $https://www.linkedin.com/in/thakursachin467/