Badge
Compact labels for status, counts, and metadata.
<HStack wrap> <Badge>Premium</Badge> <Badge variant="subtle" intent="neutral">Draft</Badge> <Badge variant="outline" intent="info">Beta</Badge> <Badge variant="solid" intent="destructive">Blocked</Badge></HStack>Usage
import { Badge } from "@reva/ui";Badge has two independent axes. variant sets the type / fill treatment (solid, subtle, outline) and intent sets the colour / semantic role (primary, accent, neutral, destructive, constructive, warning, caution, info). Any treatment combines with any colour. Defaults are variant="solid" and intent="primary", so a bare <Badge> is the brand identity label.
Examples
Variants
The variant axis controls the fill treatment, shown here at the default primary intent.
<HStack wrap> <Badge variant="solid">Solid</Badge> <Badge variant="subtle">Subtle</Badge> <Badge variant="outline">Outline</Badge></HStack>Intents
The intent axis carries meaning beyond decoration — reach for it when the badge communicates a role, state, or severity. Shown here at the subtle treatment.
<HStack wrap> <Badge variant="subtle" intent="primary">Primary</Badge> <Badge variant="subtle" intent="accent">Accent</Badge> <Badge variant="subtle" intent="neutral">Neutral</Badge> <Badge variant="subtle" intent="info">Info</Badge> <Badge variant="subtle" intent="constructive">Constructive</Badge> <Badge variant="subtle" intent="caution">Caution</Badge> <Badge variant="subtle" intent="warning">Warning</Badge> <Badge variant="subtle" intent="destructive">Destructive</Badge></HStack>Variant × intent matrix
Every treatment combines with every intent — all 24 permutations resolve onto the design-token intent families with no per-component colour.
<VStack gap={3}> {["solid", "subtle", "outline"].map((variant) => ( <HStack key={variant} wrap> {["primary", "accent", "neutral", "info", "constructive", "caution", "warning", "destructive"].map((intent) => ( <Badge key={intent} variant={variant} intent={intent}> {intent} </Badge> ))} </HStack> ))}</VStack>With Icon
Add data-icon="inline-start" or data-icon="inline-end" on the icon for correct spacing inside the badge.
Verified
Needs attention
Failed
<HStack wrap> <Badge> <Check data-icon="inline-start" /> Verified </Badge> <Badge variant="subtle" intent="neutral"> <Warning data-icon="inline-start" /> Needs attention </Badge> <Badge variant="subtle" intent="destructive"> <Prohibit data-icon="inline-start" /> Failed </Badge></HStack>With Spinner
You can render a spinner inside the badge. Add data-icon="inline-start" or data-icon="inline-end" on the spinner for correct spacing, same as icons.
Deleting
Generating
Loading<HStack wrap> <Badge variant="subtle" intent="destructive"> <Spinner data-icon="inline-start" /> Deleting </Badge> <Badge variant="subtle" intent="neutral"> Generating <Spinner data-icon="inline-end" /> </Badge></HStack>Link
Use asChild so the badge styles apply to a native link (or other element). Icons on links still use data-icon for padding.
<HStack className="flex-wrap gap-2"> <Badge asChild> <a href="#"> Link <ArrowUpRight data-icon="inline-end" /> </a> </Badge> <Badge variant="subtle" intent="neutral" asChild> <a href="#"> Link <ArrowUpRight data-icon="inline-end" /> </a> </Badge> <Badge variant="outline" intent="neutral" asChild> <a href="#"> Link <ArrowUpRight data-icon="inline-end" /> </a> </Badge> <Badge variant="subtle" intent="destructive" asChild> <a href="#"> Link <ArrowUpRight data-icon="inline-end" /> </a> </Badge></HStack>Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "solid" | "subtle" | "outline" | "solid" | Type / fill treatment. |
intent | "primary" | "accent" | "neutral" | "destructive" | "constructive" | "warning" | "caution" | "info" | "primary" | Colour / semantic role. |
asChild | boolean | false | Merge props onto the child element (e.g. <a>) instead of rendering a span. |
className | string | — | Additional Tailwind / utility classes. |
When asChild is false, Badge renders a span and accepts standard span attributes via React.ComponentProps<"span"> (e.g. id, aria-*). When asChild is true, pass a single child element and use that element's prop types instead.