Badge
A small pill that labels something — a dance style, an event type, a status. Badges describe; they never act.
Demo
<Badge>Sold out soon</Badge>
<Badge variant="secondary">Workshop</Badge>
<Badge variant="outline">Cuban Salsa</Badge>
<Badge variant="destructive">Cancelled</Badge>Variants
Four variants. Pick by meaning, not by which colour looks nicest next to the photo.
defaultThe one thing on the card that needs attention. Red — use sparingly.
secondaryCategory or type labels: workshop, social, festival, concert.
outlineNeutral tags — dance styles, levels, cities. Safe to show many at once.
destructiveSomething went wrong or is no longer available.
With an icon
A leading 12px icon adds scannability on busy event cards. The badge already sets the gap.
<script setup lang="ts">
import { Flame, Ticket } from 'lucide-vue-next'
</script>
<template>
<Badge><Flame class="w-3 h-3" aria-hidden="true" /> 12 tickets left</Badge>
<Badge variant="secondary"><Ticket class="w-3 h-3" aria-hidden="true" /> Early bird</Badge>
</template>In context
Dance-style tags on an event row: outline badges, wrapping freely at phone width.
<div class="flex flex-wrap gap-1.5">
<Badge v-for="style in event.styles" :key="style" variant="outline">
{{ style }}
</Badge>
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | 'default' | 'secondary' | 'destructive' | 'outline' | 'default' | Colour treatment. See Variants for when to use each. |
| class | HTMLAttributes["class"] | — | Extra classes, merged with cn() — later classes win, so you can override padding or colour. |
| default slot | slot | — | Label text, optionally with a leading 12px Lucide icon. Keep it to one to three words. |
Do & don't
Do — One red badge per card at most, for the thing that needs attention now.
Don't — Stack several red badges — when everything shouts, nothing is urgent.
Do — Short labels: one to three words a dancer can scan on the floor.
Don't — Sentences in a badge. Put explanations in body text instead.
Accessibility
- Badge renders a plain
<div>— it is not focusable and not interactive. Never put a click handler on it; if it filters or toggles, use a Button (a filter chip pattern is planned). - Colour is never the only signal: the label must say what the colour means (“Cancelled”, not a red dot).
- Icons inside a badge are decorative — mark them
aria-hidden="true"so screen readers read the label once. - Text is 12px semibold, so it needs 4.5:1.
default(white on red, ~4.8:1),secondaryandoutlinepass.destructive— red text on a 10% red tint — measures ~4.1:1 and is below AA; keep its label short and redundant with surrounding text until the variant is fixed. Never place badges on photos without a solid backing.