Storybook: Building UI Components made easy
Author: Deepanshu Galyan
UI development is the process of developing components with which users can interact on front-end of a website/software application. This process of UI development includes the HTML and CSS development of the component, i.e. how it will appear on the user screen. However, UI development is no easy process and in large websites/software applications, UI development poses numerous challenges. Most of the complex/common challenges are listed below:
- Lack of common repository and overhead required to maintain one: UI development requires a common repository where all the variations of every component are present. This repository serves as a common source of truth and prevents the rebuilding of same component. Lack of such repository may result in the duplication of components and duplicate code if the same component is used at two different points over a period of time or by different developers. Besides, without the repository, there will be no common source of truth and to maintain the knowledge of all the components and their variations will be a tedious task.
- The presence of a style guide introduces a new set of challenges and the development of themes and variations of the same component is more complex than the development of a single variation.
- As the product and design team works closely with the developer for the development of UI components, a common platform to visualize the components is very crucial. The absence of such platform may result in unnecessary hindrance in the development cycle or the final product may be different from the expected one.
To rescue the developer from all the above-mentioned challenges, Storybook provides a tool to design, develop, and test UI components in isolation. The storybook runs outside the application and servers as a common source of truth for building and referring to the UI components.
Workflow in Story Book
- Building stories
A story is a code snippet that describes the component in one particular visual state.
The first step is to develop the UI component in isolation, outside the consumer application. The stories of the component will include all the variations of the component with different styling. These stories will be developed outside the main application and will be hosted on a separate static web application.
2. Publishing story online and reviewing the UI
The stories developed on local systems by developers are then published on the server where stakeholders from all the verticals can come together to review the final product. Feedback for any enhancements or changes in the UI of the component developed can be gathered here and the developer can implement the changes till the desired outcome is achieved.
3. Test to prevent UI bugs
UI bugs can create major issues on the website and may affect the quality of the application and decrease the user experience. Also, the process of rectifying UI bugs can be trivial and may require re-deployments. To avoid this, the stories developed, need to be tested before publishing. Storybook provides multiple strategies to test the developed stories (read here in detail), some of these strategies are:
i) Manual testing
ii) Unit testing
iii) Visual regression testing
iv) Interaction testing
v) Snapshot testing
4. Documenting the story for future reference
Storybook provides the add-on docs to document the stories which can be used for defining the stories. The add-on generates a doc page that aggregates stories, text descriptions, docgen comments, args tables, and code into a single page for each component. (You can read further about documenting the story and about the doc page)
5)Deploying and distributing stories
Once the UI components are developed, reviewed, tested, and documented, they need to be distributed to other stakeholders. One easy solution for this is to host the storybook on a test server or VPN protected server that can only be accessed by the desired set of audience.
Integrating Storybook with React Application
Most of the organizations have their projects running on different front-end tools such as React, Vue, or Angular. Therefore, the storybook needs to be integrated with the existing FE application. The integration is required as storybook imports the components from the application.
To integrate storybook with React Application, you can follow the below steps:
- Installing storybook
Install the storybook tool inside your react project as dev-dependency with the help of the below command.
npm install @storybook/react — save-dev
2. Add scripts in package.json
After installing the storybook as dev-dependency, if you check your package.json file, you will find the below script automatically added in the file. This indicates that the storybook is installed in your application as dev-dependency.
“devDependencies”: {
“@storybook/react”: “^6.0.28”
}
The above script only adds storybook to your application, it does not mean that you will be able to run the application. In order to run the storybook application independently, two additional scripts are required:
i) To kick start the developer server
ii) To build a version of the style guide that can be hosted on the server
"scripts": {
"storybook": "start-storybook -p 9090",
"build-storybook": "build-storybook -c .storybook -o buildStorybook/storybook",
. . .
}
The “-p 9090” is the port on which the storybook server will be hosted. You can change the port as per your need.
3. Importing stories in storybook
The stories are created inside the main application and therefore, they are required to be imported. To do so, you need to create a main.js file in .storybook folder with the below code
module.exports = {
stories: [“../src/**/*.stories.[tj]s”],
}
The above code snippet imports all the stories matching the regex inside the storybook and these stories are visible on the front end. (The [tj] in the above code is used for importing both, typescript and javascript files)
4. Running storybook
To kick start the server and run the storybook application, you need to execute the below command. After the execution of this command, storybook will start running on the port you have mentioned in the script.
npm run storybook
(The above screenshot contains no stories as there are no stories imported yet in the storybook)
5. Developing stories
The final step is to build stories for the UI components required in your application. Once the story is developed and imported, it will be visible on the front end.
Building the first story
A story is a code snippet that describes the component in one particular visual state. Therefore, in order to have multiple variations of the same component, the developer needs to develop multiple stories to depict each variation of the component. In the below example, I have represented 3 variations of the Button component. The three variations are default button, save button, and disabled button
Step 1: Defining the component
To develop the stories of the component (in this example, the Button component), the component needs to be defined first. The below code snippet defines the Button component.
import React from “react”;
import styled from “styled-components”;const ButtonElement = styled.button`
background: ${(props) => {
if (props.disabled) {
if (props.disabled) return “#cccccc”;
} else {
if (props.orange) return “#F37921”;
}
return “#ffffff”;
}};
width: 70px;
height: 25px;
border: 1px solid
${(props) => {
if (props.disabled) {
if (props.disabled) return “#ffffff”;
} else {
if (props.orange) return “#F37921”;
}
return “#008489”;
}};
`;const Button = (props) => {
const {label} = props;
return (
<ButtonElement {…props}>{label}</ButtonElement>
);
}export default Button;
Step 2: Importing the component inside *.stories.js file
The component for which the stories need to be developed is imported in *.stories.js file (example: button.stories.js)
import React from ‘react’;
import { storiesOf } from ‘@storybook/react’;
import Button from ‘./index’;const PrimaryButton = (props) => {
return (
<Button {…props} />
);
};
Step 3: Writing stories for the imported component
The simplest way of writing stories is by using props and storiesOf API provided by the storybook. Different props in each story will render different results.
storiesOf(“Button”, module)
.addParameters({
component: PrimaryButton,
componentSubtitle: “Button subtitle”,
})
.add(“Default”, () => (
<PrimaryButton
label=”Default”
/>
))
.add(“Save”, () => (
<PrimaryButton
label=”Save”
orange
/>
))
.add(“Disabled”, () => (
<PrimaryButton
label=”Disabled”
disabled
/>
));
- addParamteres: Parameters and decorators are used for controlling how the stories of components will be rendered. Parameters contain the metadata of the stories, therefore, only one parameter can be defined per component whereas decorators can be added as per the requirement.. addParameters and addDecorators functions are used for defining parameters and decorators respectively.
- add: Add function is used for defining the stories of the component. Each “.add” call takes a story name, a story function that returns a renderable object. It has two mandatory and one optional argument:
i) storyName: It is the mandatory argument that defines the name of the story. If you pass a string like ‘Widgets|Button/Button’ it can also be used to position your component’s story within Storybook’s story hierarchy.
ii) stroyFn: It is a webpack module, which is available on the global (per-file) scope. Storybook needs it to enable hot-module-replacement. If it’s not included, you need to refresh your browser with each change we make.
iii) parameters: It is the third optional argument that can be used for defining parameters and decorators of the story.
Indulging further
The above article was dedicated to make you familiar with the basic work-flow of storybook and how to develop the stories and build UI components using it. Although, the storybook provides some advanced level features (add-ons) that provide various useful functionalities required while building the UI components. Try going through them on the official link and adopt the ones that align with your use cases.
Note: Read about Storybook 6.0 here.