Blips
Documentação

Empty

Exibe um estado vazio, sem resultados ou de erro.

Carregando…
import { Button } from "@blips/ui/components/button";
import {
  Empty,
  EmptyContent,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@blips/ui/components/empty";
import { FolderPlus } from "@phosphor-icons/react";

export default function EmptyDemo() {
  return (
    <Empty>
      <EmptyHeader>
        <EmptyMedia variant="icon">
          <FolderPlus />
        </EmptyMedia>
        <EmptyTitle>Nenhum projeto ainda</EmptyTitle>
        <EmptyDescription>
          Você ainda não criou nenhum projeto. Comece criando o seu primeiro.
        </EmptyDescription>
      </EmptyHeader>
      <EmptyContent>
        <div className="flex gap-2">
          <Button size="sm">Criar projeto</Button>
          <Button size="sm" variant="outline">
            Importar
          </Button>
        </div>
      </EmptyContent>
    </Empty>
  );
}

Instalação

pnpm add @blips/ui

Uso

import {
  Empty,
  EmptyContent,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@blips/ui/components/empty"
<Empty>
  <EmptyHeader>
    <EmptyMedia variant="icon">
      <FolderPlus />
    </EmptyMedia>
    <EmptyTitle>Nenhum projeto ainda</EmptyTitle>
    <EmptyDescription>
      Você ainda não criou nenhum projeto.
    </EmptyDescription>
  </EmptyHeader>
  <EmptyContent>
    <Button size="sm">Criar projeto</Button>
  </EmptyContent>
</Empty>

A anatomia é sempre a mesma — mídia + título + descrição + ação — para que todos os estados vazios do produto fiquem consistentes. A área de ação (EmptyContent) é opcional.

Exemplos

Sem resultados de busca

Use uma mensagem distinta do vazio inicial: deixe claro que houve uma busca e ofereça uma saída (limpar filtros, ajustar termos).

Carregando…
import { Button } from "@blips/ui/components/button";
import {
  Empty,
  EmptyContent,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@blips/ui/components/empty";
import { MagnifyingGlass } from "@phosphor-icons/react";

export default function EmptySearch() {
  return (
    <Empty>
      <EmptyHeader>
        <EmptyMedia variant="icon">
          <MagnifyingGlass />
        </EmptyMedia>
        <EmptyTitle>Nenhum resultado encontrado</EmptyTitle>
        <EmptyDescription>
          Não encontramos nada para "relatório anual". Tente outros termos ou
          remova os filtros aplicados.
        </EmptyDescription>
      </EmptyHeader>
      <EmptyContent>
        <Button size="sm" variant="outline">
          Limpar filtros
        </Button>
      </EmptyContent>
    </Empty>
  );
}

Erro de carregamento

Para falhas, combine uma mídia de alerta com uma ação de tentar novamente. A lógica de retry fica no consumidor — o componente cuida apenas da anatomia.

Carregando…
import { Button } from "@blips/ui/components/button";
import {
  Empty,
  EmptyContent,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@blips/ui/components/empty";
import { ArrowClockwise, WarningCircle } from "@phosphor-icons/react";

export default function EmptyError() {
  return (
    <Empty className="border border-dashed">
      <EmptyHeader>
        <EmptyMedia variant="icon">
          <WarningCircle />
        </EmptyMedia>
        <EmptyTitle>Não foi possível carregar</EmptyTitle>
        <EmptyDescription>
          Ocorreu um erro ao buscar os dados. Verifique sua conexão e tente
          novamente.
        </EmptyDescription>
      </EmptyHeader>
      <EmptyContent>
        <Button size="sm" variant="outline">
          <ArrowClockwise />
          Tentar novamente
        </Button>
      </EmptyContent>
    </Empty>
  );
}

Contorno tracejado

Aplique className="border border-dashed" na raiz para delimitar o estado vazio dentro de um card ou seção.

Carregando…
import { Button } from "@blips/ui/components/button";
import {
  Empty,
  EmptyContent,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@blips/ui/components/empty";
import { CloudArrowUp } from "@phosphor-icons/react";

export default function EmptyOutline() {
  return (
    <Empty className="border border-dashed">
      <EmptyHeader>
        <EmptyMedia variant="icon">
          <CloudArrowUp />
        </EmptyMedia>
        <EmptyTitle>Armazenamento vazio</EmptyTitle>
        <EmptyDescription>
          Envie arquivos para acessá-los de qualquer lugar.
        </EmptyDescription>
      </EmptyHeader>
      <EmptyContent>
        <Button size="sm" variant="outline">
          Enviar arquivos
        </Button>
      </EmptyContent>
    </Empty>
  );
}

Acessibilidade

  • EmptyTitle e EmptyDescription formam o texto anunciado pelo leitor de tela; mantenha o título curto e a descrição objetiva.
  • Quando o estado vazio representar o resultado de uma operação assíncrona (busca, carregamento), anuncie a região com role="status" no contêiner que envolve o Empty, para que a troca de conteúdo seja percebida.
  • A ação (botão/link) deve ser focável e descrever o que acontece ao acioná-la.

Referência da API

Empty

Contêiner raiz. Centraliza o conteúdo em coluna, com espaçamento e cantos arredondados.

PropTipoPadrão
classNamestring-

EmptyHeader

Agrupa mídia, título e descrição. Largura máxima sm, centralizado.

PropTipoPadrão
classNamestring-

EmptyMedia

Contêiner da mídia (ícone, avatar, ilustração).

PropTipoPadrão
variant"default" | "icon""default"
classNamestring-

variant="icon" aplica um quadrado de 32px com fundo muted e dimensiona o ícone interno; variant="default" exibe o conteúdo cru (útil para avatares e ilustrações).

EmptyTitle

Título do estado vazio.

PropTipoPadrão
classNamestring-

EmptyDescription

Texto de apoio. Estiliza links (<a>) automaticamente.

PropTipoPadrão
classNamestring-

EmptyContent

Área de ações abaixo do cabeçalho. Largura máxima sm, centralizado.

PropTipoPadrão
classNamestring-