Skip to content

Badge

Marcador compacto de uma linha para rotular, classificar ou contar. Não é botão, não é chip, não é alerta.

Regras: cantos retos (pill apenas em BadgeCount), IBM Plex Mono uppercase por padrão, sem hover no badge inteiro — só no __dismiss interno.

Uso

vue
<script setup lang="ts">
import { Badge, BadgeCount, BadgeDot } from '@halfbyte-labs/maka'
</script>

<template>
  <Badge tone="success" dot>Ativo</Badge>
  <Badge family="soft" tone="warning" dismissible @dismiss="removeFilter">Cliente: HalfByte</Badge>
  <BadgeCount :value="7" tone="blue" />
</template>

Família × Tonalidade

Família define o peso visual; tonalidade carrega o significado.

Solid — máximo destaque

Outline — metadado calmo

Soft — tabelas e listas densas (padrão recomendado)

vue
<!-- Solid: hero, card destacado, status crítico -->
<Badge family="solid" tone="danger">Falhou</Badge>

<!-- Outline: Draft, v1.2, Beta — metadado calmo -->
<Badge family="outline" tone="black">Beta</Badge>

<!-- Soft: item de tabela, lista densa — padrão -->
<Badge family="soft" tone="success">Ativo</Badge>
ContextoFamília recomendada
Hero / marketing / CTAsolid (geralmente lime + display)
Card destacado, status críticosolid
Item de tabela / lista densasoft
Filtros ativos removíveissoft + dismissible
Tag de metadado calmo (Beta, v1.2)outline
Sobre fundo coloridooutline ou solid white

Tamanhos

vue
<Badge size="xs">XS</Badge>   <!-- inline em labels, tabelas densas -->
<Badge size="sm">SM</Badge>   <!-- padrão — status em listas, cards -->
<Badge size="md">MD</Badge>   <!-- headers de card, com ícone -->
<Badge size="lg">LG</Badge>   <!-- pricing tier, marketing hero -->

Tipografia

vue
<Badge type="mono">Ativo</Badge>           <!-- padrão — status, tags -->
<Badge type="display" tone="lime">Pro</Badge>  <!-- marketing, pricing -->
<Badge type="body" family="soft">Cliente: HalfByte</Badge>  <!-- filtros com valor humano -->
typeFontUso
monoJetBrains Mono · uppercaseStatus, tags, taxonomia — padrão
displaySpace Grotesk · uppercaseMarketing, pricing, hero
bodyPlus Jakarta Sans · sem capsFiltros ativos com valor legível

Status dot

vue
<Badge family="soft" tone="success" dot>Online</Badge>
<Badge family="soft" tone="danger" dot>Offline</Badge>

<!-- Pulse APENAS para estado genuinamente ao vivo -->
<Badge family="solid" tone="blue" dot pulse>Ao vivo</Badge>

Regra: pulse é exclusivo de streaming / monitoramento em tempo real. Não anime badges parados.


Com ícone

vue
<Badge family="soft" tone="success" size="md">
  <template #icon>
    <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
      <polyline points="1,6 4.5,9.5 11,2.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/>
    </svg>
  </template>
  Verificado
</Badge>

Use o slot #icon para SVGs monocromáticos com stroke="currentColor". Nunca emoji ou unicode.


Dismissível (filtros ativos)

vue
<Badge
  family="soft"
  type="body"
  tone="blue"
  dismissible
  dismiss-label="Remover filtro: Cliente HalfByte"
  @dismiss="removeFilter('cliente')"
>
  Cliente: HalfByte
</Badge>
  • Use type="body" (sem uppercase) para valores legíveis como Cliente: HalfByte
  • dismiss-label deve descrever o que está sendo removido, não apenas "Fechar"
  • O evento @dismiss é emitido após o fade-out de 160ms

BadgeCount

Pill exclusivo para contagens. Pill (radius 999px) é a única exceção à regra de canto reto.

vue
<BadgeCount :value="3"    tone="blue" />    <!-- → "3" -->
<BadgeCount :value="100"  tone="blue" />    <!-- → "99+" -->
<BadgeCount :value="2400" tone="blue" />    <!-- → "2.4K" -->
<BadgeCount :value="9900" tone="danger" />  <!-- → "9.9K" -->
<BadgeCount :value="3"    tone="danger" size="lg" />

Regra: nunca mostre count: 0. Esconda o BadgeCount com v-if="count > 0".


BadgeDot

Bolinha 8×8 sem texto — sinaliza "tem coisa nova". Sempre aria-hidden="true".

vue
<button aria-label="Notificações, com novidades" style="position: relative">
  <BellIcon />
  <BadgeDot tone="blue" style="position: absolute; top: -2px; right: -2px" />
</button>

Use halo-color para combinar com o fundo do container (cria o halo de separação):

vue
<!-- BadgeDot sobre fundo preto -->
<BadgeDot tone="danger" halo-color="#111114" />

Props — Badge

PropTipoPadrãoDescrição
family"solid" | "outline" | "soft""solid"Peso visual
tone"black" | "blue" | "lime" | "cyan" | "white" | "gray" | "success" | "warning" | "danger" | "info""black"Cor e significado
size"xs" | "sm" | "md" | "lg""sm"Tamanho
type"mono" | "display" | "body""mono"Família tipográfica
dotbooleanfalseExibe status dot à esquerda
pulsebooleanfalseAnima o dot (requer dot) — apenas para "live"
dismissiblebooleanfalseExibe botão "×"
dismiss-labelstring"Remover"aria-label do botão dismiss
as"span" | "mark" | "output""span"Elemento semântico
aria-labelstringLabel acessível (use para siglas: aria-label="Novo")

Evento: @dismiss — emitido 160ms após o clique no "×" (após o fade).

Slot #icon: SVG monocromático com stroke="currentColor".


Props — BadgeCount

PropTipoPadrãoDescrição
valuenumber | stringValor. Números >99 viram "99+". Strings são exibidas literalmente.
toneBadgeTone"blue"Tonalidade (usa família solid)
size"sm" | "lg""sm"Tamanho

Props — BadgeDot

PropTipoPadrãoDescrição
tone"blue" | "danger" | "lime""blue"Cor do dot
halo-colorstringvar(--colors-bg)Cor do halo (deve combinar com o fundo)

Boas práticas

vue
<!-- ✅ 1 palavra, semântica com texto -->
<Badge family="soft" tone="success" dot>Ativo</Badge>
<Badge family="soft" tone="danger" dot>Falhou</Badge>

<!-- ✅ Lime para destaque marketing — pontual -->
<Badge family="solid" tone="lime" type="display" size="lg">Pro</Badge>

<!-- ✅ Outline para metadado calmo -->
<Badge family="outline" tone="black">Beta</Badge>
<Badge family="outline" tone="black">v1.2.0</Badge>

<!-- ✅ Count com v-if para esconder zero -->
<BadgeCount v-if="unread > 0" :value="unread" tone="blue" />

<!-- ❌ Frase como conteúdo -->
<Badge>Status atual do usuário</Badge>

<!-- ❌ Não misture lime com success — são cores diferentes -->
<Badge tone="lime">Aprovado</Badge>  <!-- errado — lime é detail/brand -->
<Badge tone="success">Aprovado</Badge>  <!-- correto -->

<!-- ❌ Solid danger repetido em lista vira ruído -->
<Badge family="solid" tone="danger">Vencida</Badge>  <!-- só para o mais crítico -->
<Badge family="soft" tone="danger">Vencida</Badge>   <!-- use soft em listas -->