DEV Community

Eduardo Henrique Gris
Eduardo Henrique Gris

Posted on

Documentação de componentes em React com Typescript usando Storybook

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
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 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
Enter fullscreen mode Exit fullscreen mode

É 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 com yarn add @storybook/addon-essentials --dev e no arquivo main.ts presente dentro da pasta .storybook adicionar em addons ela:
// ...
const config: StorybookConfig = {
  // ...
  addons: [
    // ...
    "@storybook/addon-essentials",
  ],
};
export default config;
Enter fullscreen mode Exit fullscreen mode

A tabela terá o seguinte layout:

Image description

  • 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

  • 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;
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 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 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",
};
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 { 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>
Enter fullscreen mode Exit fullscreen mode

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:

Image description

E a documentação da seguinte forma:

Image description

E clicando em Show code em um dos cenários, é mostrado o código associado:

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

Top comments (0)