Flutter Widgetbook: Como Documentar seu Design System do jeito certo!

Como o Widgetbook resolve o problema de documentar componentes em projetos Flutter com design system próprio. No Direção Fácil, virou catálogo visual, contrato com o Figma e contexto preciso para o Claude Code gerar telas usando os widgets certos.

Flutter Widgetbook: Como Documentar seu Design System do jeito certo!

Quando comecei a desenvolver o Direção Fácil, ficou claro desde cedo que o app teria um design system próprio. Cada botão, cada card, cada barra de progresso com visual específico, tudo desenhado pixel-perfect no Figma.

Para implementar os componentes mais rápido, usei LLM com o Figma como referência. Foi um processo direto: desenhei, passei para o modelo, ajustei, parti para o próximo. Quando terminei, tinha 25 componentes prontos: DFButton em 5 variantes, DFModule em 4 estados, DFQuizBar, DFQuestion e mais uma dúzia de outros.

Design dos componentes do Direção Fácil no Figma antes de virar código

Mas conforme os componentes iam ficando prontos, fui percebendo um gap: como eu sabia que o componente estava correto se nunca conseguia vê-lo isolado, fora do contexto do app inteiro? Eu queria poder abrir o DFModule com todos os seus estados lado a lado, ver o DFButton em todas as variantes de uma vez, e comparar com o Figma antes de sair usando nas telas. Precisava de um catálogo visual, do tipo que o Material Design tem para os widgets nativos do Flutter, mas para os componentes do meu próprio design system.

A primeira opção que veio à cabeça foi o Storybook, mas ele não tem suporte para Flutter. Foi procurando uma alternativa que descobri o Widgetbook.

O que é o Widgetbook

O Widgetbook é, basicamente, o Storybook do Flutter. Você cria "use cases" para cada componente: funções que renderizam o widget em estados específicos. O Widgetbook monta uma interface separada do seu app principal, onde você navega por todos os componentes, troca parâmetros em tempo real e valida visualmente.

Na prática, ele funciona como um entry point alternativo dentro do mesmo projeto Flutter: o app real continua inalterado, e o Widgetbook é só uma forma diferente de rodar o mesmo código, agora em modo catálogo.

Instalação

No pubspec.yaml, você precisa de quatro dependências:

dependencies:
  widgetbook: ^3.0.0

dev_dependencies:
  widgetbook_annotation: ^3.0.0
  widgetbook_generator: ^3.0.0
  build_runner: ^2.4.0

O widgetbook é o runtime com a interface visual, o widgetbook_annotation traz as anotações @UseCase e @App, e o widgetbook_generator é o que faz a parte mais interessante: roda via build_runner, descobre automaticamente todos os use cases do projeto e gera o arquivo de diretórios que monta o menu lateral do catálogo.

Criando o primeiro use case

Para cada componente, você cria um arquivo *_use_case.dart ao lado do widget, seguindo um padrão simples: uma função anotada com @UseCase que retorna um Widget.

No Direção Fácil, comecei pelo DFButton, que tem 5 variantes. O arquivo de use cases ficou assim:

import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook;

import '../components/buttons/df_button.dart';

@widgetbook.UseCase(name: 'Primary Button', type: DFButton)
Widget buildPrimaryButton(BuildContext context) {
  return DFButton.primary(label: 'Botão Primary', onPressed: () {});
}

@widgetbook.UseCase(name: 'Text Button', type: DFButton)
Widget buildTextButton(BuildContext context) {
  return DFButton.text(label: 'Botão Text', onPressed: () {});
}

...

Cada @UseCase recebe um name, que aparece no menu lateral do catálogo, e um type, que é o widget sendo documentado. Você pode criar quantos use cases quiser para o mesmo componente.

Catálogo do Widgetbook mostrando as variantes do DFButton

Configurando o entry point

Com os use cases criados, você precisa de um entry point separado para o Widgetbook: uma classe anotada com @App() onde você configura os addons. O build_runner gera automaticamente o arquivo de diretórios a partir dos seus use cases, sem precisar registrar nada manualmente. A documentação oficial cobre esse passo em detalhes.

Os addons são um dos pontos mais fortes do Widgetbook. Funciona parecido com um sistema de plugins: cada addon adiciona um controle no painel lateral que muda como o componente é exibido, sem alterar o código. Com o ViewportAddon você simula tamanhos de tela específicos, do iPhone 13 a um Galaxy Note, sem precisar trocar de dispositivo. O TextScaleAddon aumenta a escala de fonte para testar acessibilidade. O MaterialThemeAddon alterna entre temas do app em tempo real. E o AlignmentAddon reposiciona o componente na tela para testar diferentes contextos de layout, e por aí vai...

Depois de configurado, rodar o catálogo é simples:

# No simulador
flutter run -t lib/main_widgetbook.dart

# No navegador, para compartilhar com o time de design
flutter run -d chrome -t lib/main_widgetbook.dart

O exemplo abaixo mostra o DFProfileBar no catálogo:

DFProfileBar no Widgetbook com 5 vidas e knobs na sidebar

O mesmo componente no app real, para comparar:

DFProfileBar no app Direção Fácil em produção

Knobs: parâmetros interativos

O que torna o Widgetbook mais útil no dia a dia são os knobs. Em vez de criar um use case para cada combinação possível de parâmetros, você expõe os parâmetros como controles na sidebar. Design e dev conseguem testar variações sem editar código.

Em um outro projeto que usa o mesmo padrão, o use case do botão principal ficou assim:

@UseCase(name: "default", type: AppButton)
Widget buildButtonUseCase(BuildContext context) {
  final variant = context.knobs.object.dropdown<AppButtonVariant>(
    label: "variant",
    options: AppButtonVariant.values,
    initialOption: AppButtonVariant.tonal,
    labelBuilder: (value) => value.name,
  );

  final label = context.knobs.string(
    label: "label",
    initialValue: "Continuar",
  );

  final enabled = context.knobs.boolean(
    label: "enabled",
    initialValue: true,
  );

  return AppButton(
    label: label,
    variant: variant,
    enabled: enabled,
    onPressed: () {},
  );
}

Com isso, você abre o catálogo, navega até o componente e tem um painel lateral para trocar a variante, editar o texto e habilitar ou desabilitar em tempo real. O Widgetbook oferece knobs para string, boolean, int, double, color, duration e dropdown.

Knobs do DFButton no painel lateral do Widgetbook

O pulo do jogo: Widgetbook como contexto para LLM

A combinação que mais acelerou o desenvolvimento foi essa: design system documentado no Widgetbook, com a lista de componentes exportada como arquivo de texto, passada como contexto para o Claude Code na hora de escrever as telas.

O fluxo no Direção Fácil ficou assim: conforme implementava os componentes com ajuda do LLM, ia criando os use cases do Widgetbook ao lado de cada um. Quando um componente ficava pronto, rodava o catálogo para validar visualmente em comparação com o Figma. Depois, quando ia implementar uma tela, passava dois contextos para o Claude Code: o arquivo com a documentação dos componentes e as instruções de arquitetura. A instrução central era direta: não crie novos componentes, use somente os listados nesta documentação.

Com isso, o LLM criava telas inteiras com os widgets certos, os construtores corretos e os parâmetros exatos. Sem esse catálogo, o modelo ficaria inventando nomes e assinaturas de widgets que não existem, e a tela não rodaria na primeira tentativa. A documentação dos use cases virou o contrato entre o design system e a geração de código.

Conclusão

O Widgetbook resolve um problema real em projetos Flutter com design system próprio: a falta de um lugar visual para consultar todos os componentes disponíveis.

Se você está começando um projeto Flutter que vai ter componentes customizados, vale configurar o Widgetbook desde o primeiro widget. O custo de manter o catálogo atualizado é praticamente zero quando você cria o use case junto com o componente. E o benefício de ter um catálogo que roda no simulador ou no navegador, que pode ser compartilhado com design para validação e que serve como contexto preciso para qualquer colaborador, compensa muito antes do projeto crescer.

O que usei aqui é só a base. O Widgetbook vai bem além disso: tem suporte a golden tests, que são testes de regressão visual automatizados, onde você tira um snapshot do componente e qualquer mudança futura é comparada contra essa referência. Se algo mudar sem querer, o teste falha. E tem o Widgetbook Cloud, que integra revisões visuais diretamente no fluxo de pull request: a cada PR, a plataforma compara as mudanças visuais entre builds e publica o resultado como um status no repositório, permitindo que design e dev aprovem ou bloqueiem a mesclagem com base no que realmente mudou na interface. Para times que trabalham com design system, essas duas funcionalidades mudam o nível do jogo.

Bora construir algo, ou só dar um oi

Se você tem um projeto em mente, quer falar sobre tecnologia ou só dar um oi, eu leio tudo que chega na caixa de entrada.