Introduction
Storybook is a lib that allows, among other things, the documentation of components in isolation, parallel to the application. In this article, I will present a way to customize component documentation, which I learned during the development of a personal project that I use for study purposes. I hope this will help bring visibility to some of the options available when using this library. The following steps will be followed:
- setup: storybook configuration
- stories: definition of the main scenarios for the components to be documented
- mdx: documentation of the components, incorporating the customizations defined in the stories
- example: an example of component documentation will be presented
Each component will have its own mdx
and stories
file.
Setup
To add storybook to a React application with the initial configurations, you need to run the following command in the terminal: npx storybook init
. This command will add storybook based on the project's dependencies. To check if the addition was successful, run yarn storybook
in the terminal and see if a page opens (at this point, without any documented components).
Stories
For each component, a *.stories.tsx
file will be created, where the most important customization scenarios to be documented will be defined, following this structure:
import React from "react";
import { Meta, StoryObj } from "@storybook/react";
import Component from "./Component";
const meta: Meta<typeof Component> = {
component: Component,
title: "Component",
argTypes: {},
};
export default meta;
type Story = StoryObj<typeof Component>;
export const Scenario1: Story = (args) => (
<>
<Component {...args} />
<Component {...args} props1="option1" />
<Component {...args} props1="option2" />
</>
);
Scenario1.args = {
// (...),
props1: "default"
};
// Scenario2
// Scenario3
From the imports of @storybook/react
:
- Meta: define the metadata for the component to be documented. In this case, the component itself is passed in
component
, and the title that will appear in the sidebar is specified intitle
. - StoryObj: allows you to define the customization scenarios of the component to be displayed in the documentation, corresponding to the definitions of
Scenario1
,Scenario2
... mentioned above.
For each defined scenario, an entry will be created in the sidebar, within the "folder" named according to the title
defined in the Meta
, with the following structure:
- Component
- Scenario 1
- Scenario 2
- Scenario 3
In Scenario1.args
above, the default props for the component to be presented are defined, with the aim of setting a base display for the component (for example, text for a button like Button
).
In const Scenario1
, the component to be rendered is defined, varying props1
, with the goal of showing in the documentation what happens to the component when this prop is changed.
MDX
It will be the component documentation, where the scenarios present in the *.stories.tsx
file will be included, and texts will be defined to explain the main functionalities of the component, following this structure:
import { ArgTypes, Canvas, Meta, Story } from '@storybook/blocks';
import * as Stories from './Component.stories';
<Meta of={Stories} />
# Component
Component description.
## Props
<ArgTypes />
## Predefined properties
### Scenario 1
Description of the use of props1.
<Canvas withToolbar>
<Story of={Stories.Scenario1} />
</Canvas>
## Custom properties
// ### Scenario 2
// ### Scenario 3
It's a file that mixes markdown with javaScript. From the imports of @storybook/blocks
:
- ArgTypes: it returns a table with the names of all available props for the component, their descriptions (including the Types of the props), and whether they have a default value. This is done automatically, as the
npx storybook init
command already adds@storybook/addon-essentials
to the app. For versions of storybook that do not include this addon by default, you will need to add the library withyarn add @storybook/addon-essentials --dev
and then add it to the addons in the main.ts file located in the.storybook
folder:
// ...
const config: StorybookConfig = {
// ...
addons: [
// ...
"@storybook/addon-essentials",
],
};
export default config;
The table will have the following layout:
- Canvas: this will create a box where the components from the scenario defined in the
*.stories
file will be displayed. It includes an option called Show code that reveals the code to use the displayed component
Meta: defines where the associated stories file for the documentation is located, coming from the import
import * as Stories from './Component.stories';
Story: allows rendering the scenarios defined in the stories file, encapsulated by the
Canvas
to also enable viewing the code.
Example
I will present a simple example of documentation based on what has been provided above. Starting with the creation of a component defined in Tag.tsx
:
import React from "react";
import styled from "styled-components";
export interface TagProps {
text: string;
backgroundColor?: string;
type?: "success" | "alert" | "error";
}
export interface StyledTagProps {
$backgroundColor?: string;
$type?: "success" | "alert" | "error";
}
export const StyledTag = styled.div<StyledTagProps>`
border: none;
padding: 10px 12px;
background-color: ${(props) =>
props.$backgroundColor
? props.$backgroundColor
: props.$type === "error"
? "#e97451"
: props.$type === "alert"
? "#f8de7e"
: props.$type === "success"
? "#50c878"
: "#d3d3d3"};
pointer-events: none;
border-radius: 5px;
width: fit-content;
`;
const Tag = ({
text,
backgroundColor,
type,
}: TagProps) => (
<StyledTag
$type={type}
$backgroundColor={backgroundColor}
>
<span>{text}</span>
</StyledTag>
);
export default Tag;
It is a Tag component with a predefined type
property, meaning that the app itself defines the associated css based on the given type. The possible values are error
, alert
and success
. It also has a customizable backgroundColor
property, allowing users to choose any color they want.
In the example, the css is defined using a lib called styled-components
, but the documentation is indifferent to how the css is defined. Types are defined for both the component's props and the related to styled component.
Now, a specific component for documentation, StorybookContainer
, will be created. This component will be responsible for centering the scenario components inside the Canvas
of the mdx file, with a small spacement between them. In the file StorybookContainer.tsx
:
import React from "react";
import styled from "styled-components";
export interface StorybookContainerProps {
children: React.ReactNode;
}
export const StyledStorybookContainer = styled.div`
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
`;
const StorybookContainer = ({ children }: StorybookContainerProps) => (
<StyledStorybookContainer>
{children}
</StyledStorybookContainer>
);
export default StorybookContainer;
The file Tag.stories.tsx
will be created with the two scenarios to be presented in the documentation:
import React from "react";
import { Meta, StoryObj } from "@storybook/react";
import Tag from "./Tag";
import StorybookContainer from "../StorybookContainer/StorybookContainer";
const meta: Meta<typeof Tag> = {
component: Tag,
title: "Tag",
argTypes: {},
};
export default meta;
type Story = StoryObj<typeof Tag>;
export const PredefinedType: Story = (args) => (
<StorybookContainer>
<Tag {...args} />
<Tag {...args} text="Success" type="success" />
<Tag {...args} text="Alert" type="alert" />
<Tag {...args} text="Error" type="error" />
</StorybookContainer>
);
PredefinedType.args = {
text: "Default",
};
export const BackgroundColor: Story = (args) => (
<StorybookContainer>
<Tag {...args} />
<Tag {...args} backgroundColor="#89cff0" />
<Tag {...args} backgroundColor="#f0aa89" />
</StorybookContainer>
);
BackgroundColor.args = {
text: "Tag",
backgroundColor: "#d3d3d3",
};
Two scenarios were defined in the file to show how the component changes with variations in the type
props (which is a predefined property in the app) and how the component changes with variations in the backgroundColor
props (which is customizable, as the user can specify any color they want to use).
Finally, the documentation file for the Tag component, Tag.mdx
, will be created, where the two scenarios defined in the stories file will be displayed:
import { ArgTypes, Canvas, Meta, Story } from '@storybook/blocks';
import * as Stories from './Tag.stories';
<Meta of={Stories} />
# Tag
Tag base component.
## Props
<ArgTypes />
## Predefined properties
### Type
There are three type predefined properties: success, alert and error.
<Canvas withToolbar>
<Story of={Stories.PredefinedType} />
</Canvas>
## Custom properties
### BackgroundColor
Tag backgroundColor can be modified.
<Canvas withToolbar>
<Story of={Stories.BackgroundColor} />
</Canvas>
It will describe the component being displayed, with a table showing its props due to the inclusion of . It will also shows a customization scenario using the variation of the type
props (a predefined property) and a scenario using the variation of the backgroundColor
props (a customizable property).
Finally, run yarn storybook
in the terminal. The sidebar will look like this:
And the documentation will look like this:
And clicking on Show code
in one of the scenarios displays the associated code:
Conclusion
The idea of this article was to introduce a component documentation lib that allows customizing documentation using an mdx file in various ways, utilizing the blocks
provided by the lib. A way for writing this documentation file was presented, but given the many possibilities offered by the lib, I will include some links in the references for those who want to delve deeper into the subject.
References
Stories File
Blocks
Argtypes Block
Canvas Block
Meta Block
Stories Block
MDX File
Top comments (0)