Badge

Compact labels for status, counts, and metadata.

PremiumDraftBetaBlocked
<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.

SolidSubtleOutline
<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.

PrimaryAccentNeutralInfoConstructiveCautionWarningDestructive
<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.

primaryaccentneutralinfoconstructivecautionwarningdestructive
primaryaccentneutralinfoconstructivecautionwarningdestructive
primaryaccentneutralinfoconstructivecautionwarningdestructive
<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.

Loading

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>

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

PropTypeDefaultDescription
variant"solid" | "subtle" | "outline""solid"Type / fill treatment.
intent"primary" | "accent" | "neutral" | "destructive" | "constructive" | "warning" | "caution" | "info""primary"Colour / semantic role.
asChildbooleanfalseMerge props onto the child element (e.g. <a>) instead of rendering a span.
classNamestringAdditional 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.

On this page