Skip to content

pesquisa componente empty state

Mateus Villain edited this page Aug 22, 2026 · 1 revision

Pesquisa de componente: Empty State

Premissa de escopo: este documento trata do "Empty State" como padrão/componente de UI que substitui uma área de conteúdo (lista, tabela, painel, página inteira) quando não há dados a exibir — cobrindo os três grandes tipos reconhecidos pelo mercado (primeiro uso, ação do usuário/sem resultados, e gerenciamento de erro). Não trata de skeleton loading (estado de carregamento) nem de páginas de erro de sistema (404/500 de servidor), que são padrões relacionados mas distintos — a diferença entre eles é discutida na Seção 1.


1. Definição e propósito

Um Empty State é o conteúdo que substitui uma área da interface — um cartão, uma tabela, um painel lateral ou uma página inteira — no momento em que não há dados para exibir ali. Em vez de deixar um espaço em branco (ou, pior, manter cabeçalhos de tabela e controles apontando para nada), o Empty State comunica por que aquele espaço está vazio e o que fazer a seguir.

O trabalho que esse componente precisa realizar não é decorativo — é de orientação. Um espaço em branco sem explicação gera três problemas recorrentes: o usuário não sabe se é um bug, não sabe se aquele recurso existe de fato, e não sabe como sair daquele estado. O Empty State resolve isso comunicando status (Heurística nº 1 de Nielsen — visibilidade do status do sistema) e, quando aplicável, apontando o caminho de recuperação (Heurística nº 9 — ajudar o usuário a reconhecer, diagnosticar e se recuperar de erros).

Quando usar:

  • Primeiro acesso a uma funcionalidade, antes de o usuário ter criado qualquer conteúdo.
  • Busca ou filtro que não retornou resultados.
  • Conteúdo que foi deletado, arquivado ou expirou.
  • Confirmação de que uma tarefa foi concluída (ex.: caixa de entrada zerada).
  • Impossibilidade de exibir dados por permissão, configuração pendente ou falha de sistema relacionado.

Quando não usar (ou usar outro componente):

  • Falha de carregamento em andamento → use um estado de loading/skeleton, não um Empty State (o dado ainda pode chegar).
  • Erro de sistema/servidor genérico (404, 500, "algo deu errado") → geralmente tratado como um padrão de "página de erro" separado, com tom e detalhamento técnico diferentes; a Carbon, por exemplo, mantém isso como um padrão futuro distinto do Empty State.
  • Confirmação pontual de uma ação bem-sucedida sem estado persistente (ex.: "arquivo salvo") → um Toast ou Flag é mais apropriado; o Empty State só entra quando a área da interface muda de fato para um estado sem conteúdo.
  • Validação de campo de formulário vazio → isso é responsabilidade dos estados de erro do próprio campo (ver componentes de formulário), não de um Empty State.

Alternativas e quando preferi-las: para pequenas áreas onde não há espaço para imagem, texto e botão (por exemplo, uma célula de tabela ou um chip), prefira apenas um texto discreto (ex.: "—" ou "Sem dados") em vez de um Empty State completo — a Carbon é explícita sobre isso: "se o espaço é limitado, use apenas texto".

2. Modelo mental do usuário

O usuário espera que uma área da interface que deveria ter conteúdo, mas não tem, explique isso — a ausência de explicação é lida como falha do sistema, não como "não há nada aqui mesmo". Esse é um padrão de expectativa herdado de décadas de interfaces gráficas: um espaço em branco onde uma lista deveria estar é indistinguível, para o usuário, de uma tela que travou no meio do carregamento.

Padrões que moldam essa expectativa:

  • Apps de produtividade (Gmail zerado, Todoist, Trello): o Empty State de "zero inbox" ou "nada pendente" é hoje uma expectativa de recompensa — o usuário espera ser parabenizado, não apenas informado.
  • E-commerce e busca: "Nenhum resultado encontrado" com sugestão de ajuste de busca é um padrão tão consolidado que sua ausência (uma página simplesmente em branco) é percebida como erro do site.
  • Onboarding de SaaS B2B: o primeiro Empty State de uma funcionalidade nova costuma ser o primeiro contato real do usuário com aquela feature — por isso Carbon e outros sistemas tratam o "no data / first use" como oportunidade educacional, não apenas como aviso.

Romper essa convenção — por exemplo, mostrar uma tabela com cabeçalhos e rodapé "fantasmas" sobre um corpo vazio — tem custo cognitivo real: o usuário precisa investigar se há um problema antes de agir. Vale romper a convenção apenas quando o contexto já deixa claro que o vazio é esperado (ex.: um campo de busca recém-aberto sem query digitada ainda não deveria mostrar "nenhum resultado").

3. Anatomia

Elemento Tipo Função
Container Obrigatório Substitui integralmente a área/elemento que teria conteúdo (a tabela, o painel, a página) — não deve coexistir com cabeçalhos ou rodapés do componente vazio.
Imagem/ilustração/ícone Opcional Reforça visualmente a situação (não uma decoração genérica); em espaços pequenos, deve ser omitida.
Título (heading) Obrigatório Frase curta, idealmente positiva ou orientada à ação, resumindo a situação.
Corpo/descrição Opcional, mas recomendado quando há ação a explicar Explica a próxima ação, o motivo do vazio, ou o benefício de agir.
Ação primária Opcional Botão ou link que resolve a situação (criar item, ajustar busca, solicitar acesso).
Ação secundária Opcional Ação alternativa (ex.: link para documentação), renderizada com menor destaque.
Ação terciária Opcional (usada por alguns sistemas, ex. Atlassian) Link para conteúdo de apoio/externo, abaixo das ações primária/secundária.
Lista de critérios/sugestões Opcional Usada quando há múltiplas causas possíveis (ex.: "tente remover filtros", "tente outras palavras-chave") — presente, por exemplo, no Empty State da Morningstar Design System.

Hierarquia visual, de fora para dentro: container → imagem (topo ou lateral) → título → corpo → ações. A ordem de leitura sempre coloca a explicação (título/corpo) antes da ação — o usuário precisa entender a situação antes de decidir agir.

4. Estados

O Empty State, ao contrário de componentes interativos como um botão ou input, tem poucos "estados" no sentido tradicional (hover/focus/active), porque ele é majoritariamente um bloco de conteúdo estático, não um controle. Os estados relevantes são de natureza/contexto, não de interação direta com o container:

Estado Quando ocorre Comportamento Representação visual
Primeiro uso (no data) Usuário nunca populou aquela área Explica o que vai aparecer ali e como adicionar dados Tom neutro/positivo, pode ter ilustração maior, ação primária de criação
Sem resultados (busca/filtro) Query ou filtro não retornou itens Sugere ajuste de termos/filtros Tom neutro, geralmente sem ilustração pesada, foco no texto
Confirmação/sucesso Usuário concluiu uma tarefa (ex.: zerou uma fila) Comunica conclusão, pode dispensar texto de apoio se autoexplicativo Tom celebratório, pode omitir ação se não houver próximo passo
Erro de permissão Usuário não tem acesso ao recurso Explica a restrição e como solicitar acesso Tom neutro/sério, ação primária "solicitar acesso"
Erro de sistema/integração Dado existe mas não pôde ser exibido por falha externa Explica o que se sabe e como verificar/tentar de novo Tom sério, sensível — evita humor
Configuração pendente Recurso requer setup antes de mostrar dados Explica o passo de configuração necessário Tom instrutivo, ação primária de configuração
Loading (dentro do próprio componente, opcional) Usado por alguns sistemas para indicar que uma ação disparada pelo Empty State está em progresso (ex.: prop isLoading do Atlaskit) Mostra spinner ao lado das ações, mantém o texto visível Botão com spinner, ações desabilitadas

Nota importante: o estado de erro de sistema e o estado "disabled" do próprio Empty State não fazem sentido como conceito — o Empty State não é "desabilitado", ele é substituído por outro Empty State (ex.: de erro) quando a causa muda. Isso é diferente de um input, onde disabled e readonly coexistem como estados independentes do conteúdo.

5. Interações

Como o Empty State em si é majoritariamente conteúdo estático, a interação relevante está concentrada nos elementos filhos (botões e links), não no container:

  • Mouse: clique nos botões de ação primária/secundária/terciária; hover nos botões segue o padrão do componente Button do sistema, não é definido pelo Empty State.
  • Touch: tap nos botões de ação; a área de toque deve seguir o mínimo do sistema de botões (WCAG 2.2 recomenda ≥ 24×24 px CSS, idealmente 44×44 px).
  • Teclado: o Empty State inteiro não é focável como bloco — ele não é um widget interativo, então não recebe tabindex próprio. O foco do teclado vai diretamente para os elementos interativos internos (botões/links), na ordem: ação primária → ação secundária → ação terciária. Tab/Shift+Tab navegam entre eles como em qualquer botão/link comum; Enter/Espaço ativam o botão focado.

O ponto mais frequentemente esquecido — e o mais citado em auditorias — é o de gerenciamento de foco quando o Empty State aparece dinamicamente (por exemplo, depois de uma busca ou de deletar o último item de uma lista). Se o usuário estava com foco em um elemento que desapareceu (ex.: o último item da lista que ele acabou de excluir), o foco deve ser movido de forma previsível — geralmente para o container do Empty State, para o campo de busca, ou para o próximo elemento lógico da página — nunca deixado "perdido" no <body>.

6. Acessibilidade

O Empty State não é um padrão de widget do WAI-ARIA Authoring Practices Guide (APG) — ele não aparece na lista de "Patterns" do APG porque não é um controle interativo com papel próprio (como um combobox ou um dialog); é uma região de conteúdo. Isso significa que a acessibilidade do componente se apoia em três pilares: semântica HTML nativa, tratamento de imagens decorativas, e comunicação de mudanças dinâmicas via live regions — todos padrões gerais do WCAG/WAI-ARIA, não um "ARIA pattern" dedicado.

Semântica HTML:

  • O título deve ser um heading nativo real (<h2>, <h3> etc.), não um <div> estilizado como título. O nível deve seguir a hierarquia lógica do documento em torno dele — por isso o Atlaskit expõe uma prop headingLevel configurável (padrão 4, ajustável de 1 a 6) em vez de fixar o nível.
  • O corpo/descrição é um parágrafo (<p>) comum; não há necessidade de papel ARIA especial.
  • Botões de ação devem ser <button> (ação) ou <a> (navegação), nunca <div onClick>.

ARIA — roles, states e properties relevantes:

  • Imagem/ilustração decorativa: deve ser tratada como puramente visual — alt="" (string vazia) é a técnica recomendada pelo WCAG e pela Carbon, preferível a role="presentation" por ter suporte mais amplo entre leitores de tela. Nenhuma informação relevante pode depender só da imagem.
  • Grupo de botões de ação: quando há mais de um botão, um aria-label no container do grupo (ex.: buttonGroupLabel, presente na API do Atlaskit) ajuda leitores de tela a anunciar o conjunto como uma unidade.
  • Mudança dinâmica de conteúdo: quando o Empty State aparece como resultado de uma ação do usuário no mesmo carregamento de página (ex.: busca sem resultado, exclusão do último item), a região deve ser anunciada via role="status" (implicitamente aria-live="polite", aria-atomic="true") — a técnica ARIA22 do W3C. Isso evita que o usuário de leitor de tela precise navegar manualmente até a área para descobrir que o resultado mudou. Para erros mais graves (ex.: falha de sistema), pode se justificar role="alert" (aria-live="assertive"), que interrompe a leitura em curso — usar com parcimônia, só quando a informação exige atenção imediata.
  • Cuidado com anúncios vazios/redundantes: o container de live region deve estar presente no DOM desde o carregamento inicial (mesmo vazio) para que a técnica funcione de forma confiável em todos os leitores de tela; e o conteúdo injetado deve ser significativo — não anunciar transições intermediárias sem sentido.

Navegação por teclado e gerenciamento de foco: como descrito na Seção 5, não há foco no container; o cuidado principal é mover o foco de forma previsível quando o Empty State substitui conteúdo que tinha o foco.

Leitores de tela — como é anunciado: título (heading) é anunciado com seu nível; corpo como texto corrido; imagem é ignorada (por ser decorativa); botões são anunciados como botões/links com seus rótulos. Uma boa prática explícita da Carbon é que o Empty State deve substituir completamente o componente vazio (ex.: a tabela inteira, incluindo cabeçalhos de coluna e rodapé), para que o leitor de tela não precise "atravessar" uma tabela de cabeçalhos vazios antes de chegar à mensagem.

Outros critérios WCAG:

  • Contraste: título e corpo devem atender a AA (4.5:1 para texto normal, 3:1 para texto grande) mesmo em fundo neutro/claro.
  • Área mínima de toque: botões ≥ 24×24 px CSS (WCAG 2.2 SC 2.5.8), idealmente 44×44 px.
  • Zoom/reflow: o layout deve reorganizar (imagem acima do texto, por exemplo) em telas estreitas ou com zoom até 400%, sem overflow horizontal.
  • Necessidades cognitivas: linguagem direta, sem jargão do produto, é também um requisito de acessibilidade cognitiva, não só de UX writing (ver Seção 8).

7. Validação e feedback

O Empty State em si não participa de validação de formulário — ele não é um campo de entrada. No entanto, ele frequentemente é o resultado de uma validação ou de uma ação (busca, filtro, submissão), o que o torna parte do ciclo de feedback do sistema:

  • Quando aparece: tipicamente após a conclusão de uma ação assíncrona (busca, filtro, exclusão), nunca "no meio" de uma digitação — evitar mostrar "nenhum resultado" a cada tecla digitada em um campo de busca; espere um debounce ou o "settle" da query, senão o Empty State pisca de forma frustrante enquanto o usuário ainda está digitando.
  • O que comunicar: se a causa for controlável pelo usuário (filtro muito restritivo, termo de busca), a mensagem deve indicar isso e como resolver — nunca apenas "Nenhum resultado", que a NN/g já apontou como oportunidade perdida (ver Seção 15/16).
  • Preservar contexto do usuário: ao mostrar o Empty State de "sem resultados", os filtros/termos de busca aplicados não devem ser limpos — o usuário precisa poder ajustar a partir de onde estava, não recomeçar do zero.

Aplicabilidade: como o Empty State não é ele mesmo um campo, os conceitos de aria-invalid e aria-describedby da Seção 6 do framework não se aplicam diretamente a ele — eles pertencem ao campo de busca/filtro que gerou o estado, não ao Empty State em si.

8. Conteúdo e UX Writing

Esta é, segundo praticamente todas as fontes pesquisadas (Carbon, Atlassian, Basis, NN/g), a parte mais crítica do componente — o Empty State é 80% texto e 20% layout.

Princípios:

  • Título em voz positiva/orientada à ação, evitando culpar o usuário. Prefira "Comece adicionando ativos de dados" a "Você não tem nenhum ativo de dados" (exemplo da própria Carbon).
  • Sentence case, não Title Case (padrão consistente entre Atlassian, Nord e outros).
  • Um único foco de ação por Empty State. Se há várias coisas que o usuário poderia fazer, escolha a mais importante — não liste opções concorrentes no mesmo espaço.
  • Linguagem direta e sem jargão do produto que o usuário talvez ainda não conheça — especialmente crítico em Empty States de primeiro uso.
  • Tom deve respeitar a gravidade da situação. Em erro de sistema/permissão, evite humor ou linguagem "descontraída" — a Carbon é explícita: "seja respeitoso com o usuário e não brinque ou use linguagem despreocupada" em cenários de erro. Já em confirmações de sucesso (zerar uma fila, por exemplo), tom mais leve é bem-vindo.
  • CTA com verbo imperativo específico ("Criar campanha", "Solicitar acesso"), nunca vago ("OK", "Continuar").

Exemplos corretos e incorretos:

✅ Primeiro uso: "Comece adicionando seu primeiro projeto" + "Projetos organizam suas tarefas por cliente ou equipe." + botão "Criar projeto" ❌ "Nenhum projeto encontrado." (não orienta, soa como erro)

✅ Sem resultados de busca: "Nenhum resultado para 'relatorio financeiro 2024'" + "Tente termos mais genéricos ou remova filtros ativos." + botão secundário "Limpar filtros" ❌ "0 resultados" (sem contexto, sem próximo passo)

✅ Erro de permissão: "Você não tem acesso a este board" + "Peça a um administrador do projeto para liberar seu acesso." + botão "Solicitar acesso" ❌ "Erro 403" (código técnico, sem ação clara)

✅ Confirmação: "Sua caixa de entrada está zerada 🎉" (sem corpo necessário, sem ação obrigatória) ❌ "Nenhuma notificação pendente no momento atual do sistema." (burocrático, redundante)

9. Variantes

Combatendo a proliferação: nem toda variação visual precisa virar uma prop separada. As variantes que realmente importam para consistência e manutenção são:

Variante Quando usar Quando não usar / cuidado
Com imagem/ilustração Espaços grandes (página inteira, painel principal), primeiro uso, onde vale investir em impacto visual Evitar em espaços pequenos (célula, chip, tile pequeno) — a Carbon recomenda "se o espaço é limitado, use apenas texto"
Somente texto Espaços pequenos, contextos repetidos na mesma tela (ex.: múltiplos widgets falhando ao mesmo tempo) Repetir a mesma ilustração várias vezes na tela reduz o impacto — a Carbon recomenda texto puro nesses casos
Com ação primária (botão) Quando há um próximo passo claro e recomendado Não usar quando não há nada para o usuário fazer (ex.: aguardando um processo externo)
Com instrução para clicar em elemento da UI Quando é mais didático ensinar onde o controle já existente está do que duplicar a ação em botão Evita duplicar affordance — mas exige que o elemento referenciado esteja visível na mesma tela
Com lista de sugestões/critérios Quando há mais de uma causa provável (ex.: busca sem resultado) Não usar mais que ~3 itens — vira parede de texto
Largura estreita/larga (Atlaskit `width: narrow wide`) Estreita para painéis laterais/modais; larga para páginas
Com estado de loading (isLoading) Quando a ação primária dispara um processo assíncrono que o próprio Empty State acompanha Evitar combinar com "erro" simultaneamente sem hierarquia clara (ver Seção 13)

Essas variantes são coerentes com a API proposta na Seção 12: a maioria delas é resultado de quais props opcionais são preenchidas, não de um enum de "tipo visual" fixo — o que reduz a necessidade de multiplicar componentes.

10. Responsividade

  • Desktop: layout com mais liberdade — imagem à esquerda do bloco de texto (para imagens mais altas) ou acima do título (para imagens mais largas), conforme orientação da Carbon; alinhamento à esquerda como bloco, com margem larga ou bloco centralizado no espaço vazio.
  • Tablet/telas médias: geralmente a imagem migra para cima do texto (empilhamento vertical) para não competir por largura horizontal.
  • Mobile: empilhamento vertical obrigatório; imagem reduzida ou omitida se o espaço vertical for curto (ex.: dentro de um card pequeno). Botões de ação em largura total ou empilhados verticalmente, seguindo o padrão de botões do sistema em telas estreitas.
  • Casos especiais: em tiles/cards pequenos, a Carbon recomenda uma exceção à regra geral de alinhamento à esquerda — centralizar a imagem acima do texto alinhado à esquerda, para evitar que o Empty State pareça conteúdo normal e seja ignorado.

Área de toque e densidade de informação acompanham as diretrizes gerais de acessibilidade (Seção 6): em mobile, evite empilhar múltiplas ações de mesmo peso visual — reforça a regra de "uma ação primária" da Seção 8.

11. Dependências e composição

  • Depende de: Button (ação primária/secundária/terciária), Icon/Illustration (opcional), Heading/Text (título e corpo), e, quando dinâmico, do mecanismo de live region (região ARIA) do sistema.
  • É usado dentro de: Table/Data table (substituindo corpo+cabeçalho quando vazia), Card/Tile, Panel/Drawer lateral, páginas inteiras (Page layout), Modal.
  • Classificação: componente composto — não é um átomo (como Button ou Icon), mas também não é um "pattern" de fluxo completo (como Onboarding). Ele compõe elementos mais simples (heading, texto, imagem, botões) em uma unidade reutilizável e independente do contexto onde é inserido.
  • Relação com outros padrões do sistema: frequentemente serve de ponto de entrada para padrões maiores — um Empty State de primeiro uso pode disparar um fluxo de Onboarding (spotlight/tour), ou pode ser complementado por "starter content" (dados de exemplo pré-carregados). Esses são padrões mais elaborados que existem em conjunto com o Empty State básico, não o substituem — ver Seção 15 (Carbon trata isso explicitamente como "alternativas aprofundadas").

12. API e implementação

Proposta de API para um componente EmptyState em React/TypeScript, combinando o que há de mais consistente entre Atlaskit, Polaris e Spectrum:

type EmptyStateWidth = "narrow" | "wide";

interface EmptyStateProps {
  /** Título obrigatório, curto e orientado à ação */
  heading: string;
  /** Nível do heading HTML renderizado (1–6). Ajuste conforme a hierarquia
   *  do documento ao redor — não assuma um valor fixo. */
  headingLevel?: number; // default: 4

  /** Texto de apoio opcional (parágrafo) */
  description?: string;

  /** Ilustração/ícone decorativo. Sempre renderizado com alt="" internamente. */
  illustration?: ReactNode;

  /** Ação recomendada — botão em destaque */
  primaryAction?: ReactNode;
  /** Ação alternativa — menor destaque, à esquerda da primária */
  secondaryAction?: ReactNode;
  /** Ação de apoio (ex.: link para documentação) — abaixo das anteriores */
  tertiaryAction?: ReactNode;
  /** Rótulo acessível para o grupo de ações, quando há mais de uma */
  actionsGroupLabel?: string;

  /** Indica que a ação primária está em processamento */
  isLoading?: boolean;

  /** Controla a largura do bloco de conteúdo */
  width?: EmptyStateWidth; // default: "wide"

  /** Torna a região anunciada dinamicamente por leitores de tela
   *  quando este Empty State aparece após uma ação do usuário
   *  (busca, filtro, exclusão) na mesma navegação de página. */
  announce?: "polite" | "assertive" | "off"; // default: "off"
}

Decisões de API comentadas:

  • primaryAction/secondaryAction/tertiaryAction como ReactNode (slots), não como objetos {label, onClick}: essa é a escolha do Atlaskit (primaryAction={<Button>...}) em vez da escolha mais antiga do Polaris legado (action={{content: 'Add transfer'}}). Slots dão mais flexibilidade (permitem usar <Button> ou <LinkButton> conforme a ação seja de clique ou navegação) e evitam que o Empty State precise reimplementar toda a API de variantes de botão internamente.
  • heading obrigatório, tudo mais opcional: segue o padrão do Atlaskit — o único caso de uso impossível de compor um Empty State útil sem título é o caso degenerado; todo o resto (imagem, descrição, ações) é contextual.
  • headingLevel explícito em vez de um heading fixo: decisão deliberada de acessibilidade (ver Seção 6) — um componente reutilizável não pode assumir em que nível da hierarquia de documento ele será inserido.
  • announce como enum, não boolean: modela diretamente a decisão de role="status" (polite) vs. role="alert" (assertive) vs. nenhuma anunciação (quando o Empty State já está presente no carregamento inicial da página, caso em que anunciar seria redundante).
  • Sem prop de "variante visual" (tipo type: "error" | "no-data" | "success"): deliberadamente omitida. O tom/tipo de Empty State (Seção 4) é uma decisão de conteúdo (o que o produto escreve em heading/description) e de composição (quais ações e ilustração são passadas), não uma variante visual fixa que o componente precisaria renderizar de forma diferente. Isso evita a proliferação de "temas" hard-coded e mantém a responsabilidade de tom na equipe de conteúdo.

Exemplo de uso:

<EmptyState
  heading="Nenhum resultado para “relatório financeiro”"
  description="Tente termos mais genéricos ou remova os filtros ativos."
  secondaryAction={<Button onClick={clearFilters}>Limpar filtros</Button>}
  announce="polite"
/>

13. Casos extremos e edge cases

Caso Comportamento esperado
Título muito longo Deve quebrar em múltiplas linhas normalmente (heading não trunca); se o design system impõe limite de largura ao bloco de texto, o título simplesmente ocupa mais altura — nunca truncar com reticências, pois cortaria a orientação ao usuário.
Nenhum conteúdo além do título (description, ações e imagem ausentes) Deve continuar válido e centralizado/alinhado corretamente — é o caso mínimo previsto pela API (Seção 12).
Múltiplos Empty States simultâneos na mesma tela (ex.: vários widgets de dashboard falhando) Reduzir para variante "somente texto" (Seção 9) em vez de repetir a mesma ilustração várias vezes; usar botão terciário em vez de múltiplos primários concorrentes, conforme recomendação da Carbon.
isLoading e uma ação de erro simultâneos Definir hierarquia clara: isLoading=true deve desabilitar as ações e mostrar o spinner; se a ação falhar, o Empty State deve transicionar para um novo estado de erro (não tentar sobrepor loading + erro no mesmo render).
Empty State dentro de um componente que já tem paginação/contadores (ex.: "1–20 de 0") O contador e controles de paginação devem ser ocultados junto com o restante do componente vazio — mesmo princípio de "substituir integralmente", da Seção 6.
Falha ao carregar a própria imagem/ilustração (ex.: CDN fora do ar) Como a imagem é decorativa (alt=""), a ausência dela não deve comprometer a compreensão — o layout deve absorver graciosamente a falta da imagem (fallback para "somente texto"), nunca mostrar um ícone de imagem quebrada.
Conteúdo internacionalizado com textos muito mais longos (ex.: alemão) O layout não deve depender de contagem de caracteres para decidir quebra de linha ou altura do container — usar comprimento flexível, testado com strings longas nos testes de i18n.
Empty State que aparece e desaparece rapidamente (ex.: busca com debounce mal ajustado) Evitar "piscar" — combinar com um pequeno atraso (debounce) antes de trocar de um estado de loading/conteúdo para o Empty State, para não gerar um flash perceptível a cada tecla digitada.

14. Boas práticas

Faça:

  • Escreva o título pensando no que o usuário pode fazer, não apenas no que não existe.
  • Substitua integralmente o componente vazio (sem cabeçalhos/rodapés fantasmas) — crítico tanto para clareza visual quanto para acessibilidade.
  • Preserve o contexto do usuário (filtros, termos de busca) ao mostrar "sem resultados".
  • Use apenas uma ação primária por Empty State; se houver mais opções, use ação secundária/terciária com hierarquia visual clara.
  • Combine tom com gravidade: leve/celebratório em confirmações, neutro e direto em "sem dados ainda", sério e respeitoso em erros.
  • Trate a imagem como decorativa por padrão (alt="") a menos que ela carregue informação que não está no texto.

Evite:

  • Empty States genéricos e reaproveitados ("Nada aqui!") em contextos muito diferentes — cada situação (Seção 4) merece uma mensagem específica ao contexto.
  • Empurrar múltiplas ações concorrentes de mesmo peso visual no mesmo Empty State.
  • Usar apenas um código de erro técnico como mensagem principal (ex.: "Erro 403").
  • Repetir a mesma ilustração pesada em vários Empty States simultâneos na mesma tela.

Não faça:

  • Não use humor ou linguagem "descontraída" em cenários de erro sério (permissão, falha de sistema) — é desrespeitoso com um usuário possivelmente frustrado.
  • Não deixe o usuário em um beco sem saída — se existe qualquer ação de recuperação possível, ela deve estar no Empty State (ou pelo menos referenciada).
  • Não anuncie o Empty State como role="alert" (assertive) por padrão — isso interrompe o que o leitor de tela estava lendo; reserve para casos que realmente exigem atenção imediata.
  • Não trunque o título com reticências para "caber" em um layout fixo.

15. Análise comparativa de mercado

Material Design (Google)

A documentação M1 legada (m1.material.io/patterns/empty-states.html) tinha uma seção de "Empty states" descrevendo um padrão com imagem não interativa e legenda em texto simples. Na documentação atual M3 (m3.material.io), não há mais uma página de padrão dedicada a "Empty state" — a busca no site atual não retorna um componente ou pattern com esse nome. Este é um achado relevante: o Material Design é o único dos seis sistemas pesquisados que não mantém uma documentação viva e específica de Empty State em sua versão atual, deixando a decisão de composição a cargo de cada equipe usando os componentes base (Text, Icon, Button).

Carbon Design System (IBM)

Fonte: carbondesignsystem.com/patterns/empty-states-pattern/. É de longe a documentação mais completa e madura entre as pesquisadas — o próprio artigo do Medium usado como referência secundária a chama de "a referência mais confiável para empty states em apps corporativos". Pontos fortes:

  • Distingue três tipos com objetivos de UX diferentes: no data (primeiro uso), user action (busca/confirmação) e error management (permissão/sistema/configuração).
  • Tem uma seção inteira de "alternativas aprofundadas" (documentação inline, onboarding, starter content) para quando o Empty State básico não é suficiente — algo que nenhum outro sistema pesquisado formaliza tão bem.
  • Orientação de acessibilidade explícita: imagens decorativas devem ser puladas por leitores de tela via alt="", com justificativa técnica de por que preferir isso a role="presentation".
  • Regras de layout muito específicas por tamanho de espaço (tile pequeno vs. tabela vs. página inteira), incluindo a exceção de centralizar a imagem em tiles pequenos.

Atlassian Design System

Fontes: atlassian.design/components/empty-state, developer.atlassian.com/platform/forge/ui-kit/components/empty-state/, atlassian.design/content/designing-messages/empty-state/. Tem a API mais explícita e madura entre os sistemas pesquisados (via Forge UI Kit / @atlaskit/empty-state):

  • Props claras: header (obrigatório), description, headingLevel (default 4, com orientação explícita de ajuste para manter hierarquia de documento), primaryAction/secondaryAction/tertiaryAction, isLoading, width (narrow/wide), buttonGroupLabel.
  • Guia de conteúdo dedicado (Content Design) com regras de sentence case, limite de 1–2 frases no corpo, e verbos imperativos no CTA — mais prescritivo em UX writing do que Carbon.
  • Interessante contraste de propósito: a documentação de conteúdo da Atlassian foca fortemente no cenário de "empty state = tarefa concluída" (zerar a inbox, terminar um trabalho) como forma de celebrar o usuário — um ângulo emocional mais explícito que os outros sistemas.

Shopify Polaris

Fontes: polaris.shopify.com/components/structure/empty-state, shopify.dev (Polaris Web Components). Dois pontos notáveis:

  • O componente React legado (EmptyState do @shopify/polaris) é explicitamente restrito a página inteira — a documentação diz que "não é destinado a elementos ou áreas individuais da interface", diferente de Carbon e Atlassian, que cobrem tanto página quanto componentes menores (tile, painel).
  • Na nova geração de Polaris Web Components, o Empty State foi reformulado como padrão de composição por slots (<s-empty-state> com slots graphic, primary-action), e a ilustração é restrita a um conjunto fechado de ícones do sistema (alert-circle, search, info, circle-info) — uma escolha de design system mais restritiva que a "imagem livre" permitida por Carbon/Atlassian/Spectrum, favorecendo consistência sobre flexibilidade visual.

Adobe Spectrum

Fonte: react-spectrum.adobe.com/react-spectrum/IllustratedMessage.html, opensource.adobe.com/spectrum-design-data/components/illustrated-message. O Spectrum não usa o nome "Empty State" — o componente equivalente se chama IllustratedMessage, usado tanto para empty states quanto para páginas de erro. Isso é, em si, um achado: a Spectrum não separa conceitualmente "vazio" de "erro" no nível do componente (diferente de Carbon, que trata como padrões relacionados mas distintos) — a diferenciação fica só no conteúdo (ilustração/título usados). API com props declarativas de tamanho (size: s | m | l) e orientação (vertical | horizontal), além de primaryActionLabel/secondaryActionLabel como strings simples (mais rígido que os slots ReactNode do Atlaskit).

Fluent UI / Fluent 2 (Microsoft)

Busca dedicada não encontrou uma página de componente "Empty state" publicada em fluent2.microsoft.design. O único artefato encontrado é um Pull Request em desenvolvimento no GitHub do Fluent UI (microsoft/fluentui#33926, marcado como "NO-MERGE"), indicando que o componente está sendo prototipado mas não foi lançado publicamente até o momento desta pesquisa. A documentação de outro componente Fluent (Drawer) menciona o Empty State apenas de passagem ("If the whole drawer can't be rendered, try an empty state"), sem detalhar anatomia ou API. Este é o segundo achado de lacuna de documentação entre os seis sistemas — junto com o Material Design M3, a Fluent 2 não tem, hoje, um componente de Empty State formalmente documentado e publicado.

Tabela-síntese comparativa

Sistema Nome do componente Documentado na versão atual? Cobre página inteira e componentes menores? Distingue tipos (no-data/ação/erro)? Prop de nível de heading? Ilustração livre ou restrita?
Material Design "Empty states" (só M1) Não (ausente em M3) — — — —
Carbon Empty state pattern Sim Sim Sim (3 tipos formais) Não explícita na doc de padrão Livre
Atlassian EmptyState Sim Sim Parcial (via conteúdo, não via prop) Sim (headingLevel) Livre
Shopify Polaris EmptyState / <s-empty-state> Sim Não (legado: só página inteira) Não Não Restrita (web components)
Adobe Spectrum IllustratedMessage Sim Sim Não (unificado com erro) Não Livre
Fluent UI — Não (em desenvolvimento) — — — —

Diferenças, semelhanças e aprendizados:

  • Semelhança forte: os quatro sistemas com documentação madura (Carbon, Atlassian, Polaris, Spectrum) convergem na mesma anatomia central — imagem opcional, título obrigatório, descrição opcional, ação primária/secundária. Isso valida a API proposta na Seção 12 como um denominador comum robusto, não uma invenção isolada.
  • Diferença relevante: só a Carbon formaliza a distinção entre os três tipos de uso (no data / user action / error management) como guia de decisão explícito; os demais deixam essa decisão implícita no conteúdo. É uma lacuna que vale preencher na documentação do Systembook — declarar os três tipos ajuda quem está escrevendo o conteúdo a escolher o tom certo (Seção 8).
  • Aprendizado sobre nomenclatura: a escolha do Spectrum de unificar "vazio" e "erro" sob um único componente (IllustratedMessage) é um lembrete de que a fronteira entre os dois é uma decisão de produto, não uma verdade universal de design system — vale decidir isso conscientemente ao especificar o componente para o Systembook (a recomendação na Seção 16 é manter a distinção, seguindo Carbon).
  • Lacuna real de mercado: dois dos seis sistemas mais relevantes do mercado (Material Design M3, Fluent 2) não têm hoje uma página de componente dedicada e publicada — mesmo sendo um dos padrões de UI mais recorrentes em produtos reais. Isso sugere que o Empty State, apesar de onipresente, ainda é tratado como "pattern secundário" por parte das grandes design systems, o que reforça a observação da Carbon de que "empty states são frequentemente tratados como um afterthought".

16. Recomendações para Design Systems

UX: adote a distinção de três tipos de uso da Carbon (no data / ação do usuário / gerenciamento de erro) como guia obrigatório de decisão no processo de design — cada tipo deve vir com um checklist de tom e nível de detalhe esperado (Seção 4 e 8). Trate confirmação de sucesso como um quarto sub-caso dentro de "ação do usuário", não como tipo à parte, já que sua estrutura de conteúdo (título + ação opcional) é a mesma.

Acessibilidade: trate alt="" em imagens decorativas e headingLevel configurável como requisitos não-negociáveis da API — são os dois pontos que mais aparecem em auditorias reais e que a maioria das implementações "feitas à mão" (sem componente compartilhado) costuma errar. Adote role="status" como padrão para Empty States que aparecem dinamicamente após ação do usuário na mesma página, reservando role="alert" para casos de erro que exigem atenção imediata — e documente essa distinção explicitamente no guia do componente, porque é o ponto de acessibilidade menos intuitivo do padrão inteiro.

Arquitetura: classifique o Empty State como componente composto reutilizável (Seção 11) com slots para ações em vez de props de configuração fechada ({label, onClick}) — isso evita que o componente precise reimplementar toda a superfície de variantes do Button, e acompanha a direção mais recente do mercado (Atlaskit). Evite criar uma prop de "tipo visual" (variant: "error" | "success") — deixe o tom ser uma decisão de conteúdo, não de código, para não engessar a evolução da UX writing do produto.

Implementação: priorize a regra "substituir integralmente o componente vazio" (sem cabeçalhos/rodapés fantasmas) como requisito de implementação para qualquer componente de dados (tabela, lista) que use Empty State internamente — isso deveria estar documentado tanto no componente Empty State quanto nos componentes de dados que o consomem, já que o erro típico acontece na integração entre os dois, não no Empty State isoladamente.

Documentação: como dois dos seis principais sistemas do mercado ainda não documentam esse padrão formalmente, há uma oportunidade real de o Systembook se diferenciar sendo mais completo aqui — incluir, além da anatomia e API, uma tabela de "tipo de situação → tom → estrutura de conteúdo recomendada" (nos moldes da tabela da Seção 4), que é exatamente o tipo de orientação que falta na maioria das implementações reais e que reduz a dependência de intervenção de engenharia para ajustes de conteúdo — alinhado ao objetivo do próprio Systembook de dar autonomia a designers e editores.


Referências

WAI-ARIA / WCAG / acessibilidade geral:

Design systems (comparativo de mercado):

Outras referências consultadas: