DEV Community

Eduardo Henrique Gris
Eduardo Henrique Gris

Posted on

Documentação de componentes em React com Typescript usando Storybook (versão 8)

Introdução

English version: Documentation of components in React with TypeScript using Storybook (version 8)

Anteriormente escrevi em um artigo sobre a documentação de componentes usando storybook, quando a versão estava abaixo da 8. Devido a algumas mudanças que vieram com essa versão e ter me aprofundado mais com a lib, estou escrevendo uma versão atualizada nesse artigo.
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 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 detectar as dependências do projeto e pode apresentar algumas perguntas durante o processo. Alguns exemplos:

  • se está usando webpack ou vite no projeto
  • se é para documentação ou testes

No caso seria escolher a que corresponde ao seu projeto e no contexto de documentação, informar isso quando perguntar.
Observação: algumas libs usam o rollup ao invés de vite e webpack, em uma lib que uso para estudo, que usa rollup, escolhi a opção do vite e funciona bem, mas precisa adicionar duas novas libs:

yarn add vite @storybook/builder-vite --dev

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 type { Meta, StoryObj } from "@storybook/react"; import Component from "./Component"; const meta: Meta<typeof Component> = { title: "Component", component: Component, argTypes: {}, }; export default meta; type Story = StoryObj<typeof Component>; export const Default: Story = { args: {}, render: (args) => ( <Component {...args} />  ), }; export const Scenario1: Story = { args: {}, render: (args) => ( <> <Component {...args} />  <Component {...args} props1="option1" /> <Component {...args} props1="option2" /> </>  ), }; // Scenario2 // Scenario3 
Enter fullscreen mode Exit fullscreen mode

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 em title
  • StoryObj: permite definir os cenários de customização do componente a serem exibidos na documentação, que corresponde as definições de Default, 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
    • Default
    • Scenario1
    • Scenario2
    • Scenario3

Em Default é renderizado o componente com as propriedades default dele.
Em args: {} do Scenario1 acima não foi passado nenhuma props, com o objetivo de trazer na primeira renderização do componente uma base com o comportamento default dele.
Já nas duas outras renderizações do Scenario1 é variada a props props1, onde o objetivo desse cenário é 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 { Canvas, Controls, Meta, Story } from '@storybook/blocks'; import * as Stories from './Component.stories'; <Meta of={Stories} />  # Component Descrição do Component. <Canvas of={Stories.Default} withToolbar /> <Controls of={Stories.Default} />  ## Predefined properties ### Scenario 1 Descrição do uso da props1. <Canvas of={Stories.Scenario1} withToolbar /> ## Custom properties // ### Scenario 2 // ### Scenario 3 
Enter fullscreen mode Exit fullscreen mode

É um arquivo mix de markdown com javascript.
Dos imports do @storybook/blocks:

  • 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 chamada Show code que mostra o código para usar o componente mostrado:

Image description

  • Controls: vai trazer uma tabela com o nome de todas as props disponíveis pelo componente, a descrição delas (trazendo os types das props), se tem um valor default e um lugar onde pode ser mexida as props do componente para visualizar as mudanças que acontecem. Colocando em conjunto:
<Canvas of={Stories.Default} withToolbar /> <Controls of={Stories.Default} /> 
Enter fullscreen mode Exit fullscreen mode

Está se definindo que o Controls vai impactar o componente que vem de Stories.Default e acima está se trazendo ele <Canvas of={Stories.Default} withToolbar />, então a cada mudança de props vai dar para ver como o componente vai sendo customizado:

Image description

  • Meta: define onde está o arquivo de stories associado a documentação, que vem do import import * as Stories from './Component.stories';

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?: "default" | "success" | "alert" | "error"; } export interface StyledTagProps { $backgroundColor?: string; $type?: "default" | "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" : props.$type === "default" && "#d3d3d3"}; pointer-events: none; border-radius: 5px; width: fit-content; `; const Tag = ({ text="Tag", backgroundColor, type="default", }: TagProps) => ( <StyledTag $type={type} $backgroundColor={backgroundColor} > <span>{text}</span>  </StyledTag> ); export default Tag; 
Enter fullscreen mode Exit fullscreen mode

É 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 default, 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; 
Enter fullscreen mode Exit fullscreen mode

Vai ser criado o arquivo Tag.stories.tsx com o Default e os dois cenários a serem apresentados na documentação:

import React from "react"; import type { Meta, StoryObj } from "@storybook/react"; import Tag from "./Tag"; import StorybookContainer from "../StorybookContainer/StorybookContainer"; const meta: Meta<typeof Tag> = { title: "Tag", component: Tag, argTypes: {}, }; export default meta; type Story = StoryObj<typeof Tag>; export const Default: Story = { args: {}, render: (args) => ( <StorybookContainer> <Tag {...args} />  </StorybookContainer>  ), }; export const PredefinedType: Story = { args: {}, render: (args) => ( <StorybookContainer> <Tag {...args} />  <Tag {...args} type="success" /> <Tag {...args} type="alert" /> <Tag {...args} type="error" /> </StorybookContainer>  ), }; export const BackgroundColor: Story = { args: { backgroundColor: "#d3d3d3", }, render: (args) => ( <StorybookContainer> <Tag {...args} />  <Tag {...args} backgroundColor="#89cff0" /> <Tag {...args} backgroundColor="#f0aa89" /> </StorybookContainer>  ), }; 
Enter fullscreen mode Exit fullscreen mode

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 { Canvas, Controls, Meta } from "@storybook/blocks"; import * as Stories from "./Tag.stories"; <Meta of={Stories} />  # Tag Tag base component. <Canvas of={Stories.Default} withToolbar /> <Controls of={Stories.Default} />  ## Predefined properties ### Type There are four predefined types: default, success, alert and error. <Canvas of={Stories.PredefinedType} withToolbar /> ## Custom properties ### Background Color Tag background color can be modified. <Canvas of={Stories.BackgroundColor} withToolbar /> 
Enter fullscreen mode Exit fullscreen mode

Onde vai estar descrito o componente que está sendo mostrado, com uma tabela permitindo controlar as prop do componente logo acima dela devido a inclusão do <Controls />, 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:

Image description

E a documentação da seguinte forma:

Image description

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
Controls Block
Canvas Block
Meta Block
Stories Block
MDX File

Top comments (0)