Introdução
Storybook é uma ferramenta que permite, dentre outras coisas, documentar componentes de forma isolada paralelamente à aplicação.
Nesse artigo, vou apresentar uma forma de customização da documentação de componentes, que fui aprendendo durante o desenvolvimento de um projeto pessoal que uso para estudo, que espero que auxilie a dar visibilidade a algumas opções dentre várias disponíveis usando essa lib. Será seguido as seguintes etapas:
- setup: configuração do storybook
- stories: definição dos principais cenários dos componentes a serem documentados
- mdx: documentação dos componentes, trazendo as customizações definidas nos stories
- exemplo: vai ser apresentado um exemplo de documentação de um componente
Cada componente terá seu próprio arquivo mdx
e de stories
.
Setup
Para adicionar o storybook em uma aplicação com React, com as configurações iniciais, é necessário executar no terminal: npx storybook init
. Esse comando vai adicionar o storybook com base nas dependências do projeto. Para visualizar se ocorreu corretamente a adição, é executar no terminal: yarn storybook
, e ver se é aberta uma página (nesse momento sem nenhum componente documentado).
Stories
Para cada componente vai ser definido um arquivo *.stories.tsx
, onde será definido os cenários de customização mais importantes a serem documentados, seguindo a seguinte estrutura:
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
Dos imports do @storybook/react
:
- Meta: define a metadata do componente a ser documentado, nesse caso está se passando o componente em si em
component
e o título que vai parecer no menu lateral emtitle
- StoryObj: permite definir os cenários de customização do componente a serem exibidos na documentação, que corresponde as definições de
Scenario1
,Scenario2
... acima
Para cada cenário definido, vai ser criado uma entrada no menu lateral, dentro da "pasta" com o nome definido no title
de Meta
, com a seguinte estrutura:
- Component
- Scenario 1
- Scenario 2
- Scenario 3
Em Scenario1.args
acima são definas as props default do componente a ser apresentado, com o objetivo de definir uma base de exibição do componente (pode ser por exemplo um texto para um botão como Button
por exemplo).
Já em const Scenario1
é definido o componente a ser renderizado variando a props1
, onde o objetivo é mostrar na documentação o que acontece com o componente ao mudar essa props.
MDX
Vai ser a documentação do componente, onde vai ser trazido os cenários presentes no arquivo de *.stories.tsx
e definido textos para explicar as principais funcionalidades do componente, seguindo a seguinte estrutura:
import { ArgTypes, Canvas, Meta, Story } from '@storybook/blocks';
import * as Stories from './Component.stories';
<Meta of={Stories} />
# Component
Descrição do Component.
## Props
<ArgTypes />
## Predefined properties
### Scenario 1
Descrição do uso da props1.
<Canvas withToolbar>
<Story of={Stories.Scenario1} />
</Canvas>
## Custom properties
// ### Scenario 2
// ### Scenario 3
É um arquivo mix de markdown com javascript.
Dos imports do @storybook/blocks
:
- ArgTypes: retorna uma tabela com o nome de todas as props disponíveis pelo componente, a descrição delas (trazendo os Types das props) e se tem um valor default, isso de forma automatizada, pois o comando
npx storybook init
já adiciona na app o@storybook/addon-essentials
. Para o caso de uma versão de storybook que não faz a instalação desse addon em conjunto, será necessário adicionar a lib comyarn add @storybook/addon-essentials --dev
e no arquivomain.ts
presente dentro da pasta.storybook
adicionar em addons ela:
// ...
const config: StorybookConfig = {
// ...
addons: [
// ...
"@storybook/addon-essentials",
],
};
export default config;
A tabela terá o seguinte layout:
- Canvas: vai criar uma caixa onde os componentes do cenário a ser puxado do arquivo
*.stories
estarão presentes, que possui uma opção chamadaShow code
que mostra o código para usar o componente mostrado
Meta: define onde está o arquivo de stories associado a documentação, que vem do import
import * as Stories from './Component.stories';
Story: permite renderizar os cenários definidos no arquivo de stories, englobado pelo
Canvas
para permitir ver o código também
Exemplo
Vou apresentar um exemplo simples de documentação partindo do que foi passado acima.
Começando pela criação de um componente definido em 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;
É um componente de Tag que tem uma propriedade predefinida type
, ou seja, a própria app define o css associado de acordo com o type passado. Podendo ser error
, alert
e success
.
E uma propriedade customizável backgroundColor
, ou seja, customizável por quem está usando o componente, podendo escolher a cor que desejar.
No exemplo estou definindo o css a partir de uma lib chamada styled-components
, mas a documentação é indiferente a forma que o css é definido.
E é definido os Types tanto das props do componente em si, quanto a referente ao styled component.
Agora será criado um componente específico para documentação StorybookContainer
, que será responsável em centralizar dentro do Canvas
do arquivo mdx, os componentes do cenário a ser mostrado, com um pequeno espaçamento entre eles. No arquivo 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;
Vai ser criado o arquivo Tag.stories.tsx
com os dois cenários a serem apresentados na documentação:
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",
};
Foram definidos dois cenários no arquivo, para mostrar como o componente muda com a variação da props type
(que é uma propriedade pre-definida na app) e como o componente muda com a variação da props backgroundColor
(que é uma propriedade customizável, pois o usuário pode passar a cor que quiser usar).
Por fim vai ser criado o arquivo da documentação do componente Tag.mdx
, onde vai ser mostrada os dois cenários definidos no arquivo de stories:
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>
Onde vai estar descrito o componente que está sendo mostrado, com uma tabela mostrando as prop dele devido a inclusão do <ArgTypes />
, onde vai ser mostrado um cenário de customização usando a variação da props type
(propriedade pre-definida) e vai ser mostrado um cenário usando a variação da props backgroundColor
(propriedade customizável).
Por fim, é executar no terminal yarn storybook
.
Ficando o menu lateral da seguinte forma:
E a documentação da seguinte forma:
E clicando em Show code
em um dos cenários, é mostrado o código associado:
Conclusão
A ideia desse artigo foi apresentar uma ferramenta de documentação de componentes que permite customizar a documentação usando um arquivo mdx de diversas formas, a partir de blocks
que a lib fornece. Foi apresentado um modo de escrita desse arquivo de documentação, mas dado a várias possibilidades que a lib fornece, vou colocar nas referências alguns links para quem quiser se aprofundar mais no assunto.
Referências
Stories File
Blocks
Argtypes Block
Canvas Block
Meta Block
Stories Block
MDX File