Documentação de componentes em React com Typescript usando Storybook
Eduardo Henrique Gris
Posted on August 27, 2024
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
Posted on August 27, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.