Skip to content
txbrendan/ui

Badge

beta

A small label for a status, category, or count, with tones, emphasis levels, and sizes.

Preview

solid

NeutralBrandDangerSuccessWarning

soft

NeutralBrandDangerSuccessWarning

outline

NeutralBrandDangerSuccessWarning

ghost

NeutralBrandDangerSuccessWarning

size

SmallMediumLarge

icons

PaidPendingFailedNew

counts

Inbox12 unreadDrafts3

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the component.

    npx shadcn@latest add @txbrendan/badge

Use it for

  • Labeling a status or category next to other content: Paid, Draft, Beta, Failed.
  • Showing a short count next to a label, like unread messages.
  • Use tone to say what the label means and emphasis to say how much it should stand out.
  • Use soft or outline in tables and long lists. Save solid for the one label that must stand out.

Avoid it for

  • Anything people click. A badge is not focusable. Use a Button with size='sm', or a link styled with badgeVariants().
  • Sentences or long text. A badge never wraps. Use an Alert or plain text.
  • Showing meaning with color alone. The text must say the status, like 'Failed', not just turn red.
  • Using tone='danger' for anything that is not an error or a risk.

Props

  • tone

    Color role.

    "neutral" | "brand" | "danger" | "success" | "warning" · default "neutral"

  • emphasis

    How loud the badge is.

    "solid" | "soft" | "outline" | "ghost" · default "solid"

  • size

    Height, padding, and text size. Density scales them.

    "sm" | "md" | "lg" · default "md"

  • className

    Extra classes. Later classes win, so className='rounded-full' replaces the radius.

    string

Accessibility

  • Renders a plain <span> with no role, so screen readers read its text in line with the content around it.
  • It is not focusable and does nothing on click. Keyboard users skip past it.
  • The text must carry the meaning. Some people cannot tell the tones apart.
  • A badge with only an icon needs words for screen readers. Add <span className="sr-only">Online</span> inside it.
  • The theme tests hold badge text to 4.5:1: solid and soft text on their own fills, and outline and ghost text on the page background.
  • Screen readers do not hear a count change. If the change matters, announce it in a role="status" region.

Examples

Status in a table row

<Badge tone="success" emphasis="soft">Paid</Badge>

Count next to a label

<span className="inline-flex items-center gap-2">
  Inbox
  <Badge tone="brand" size="sm">
    12<span className="sr-only"> unread</span>
  </Badge>
</span>

With an icon

import { CircleCheck } from "lucide-react";

<Badge tone="success" emphasis="outline">
  <CircleCheck />
  Verified
</Badge>

A link that looks like a badge

import Link from "next/link";
import { badgeVariants } from "@/components/ui/badge";

<Link href="/tags/react" className={badgeVariants({ emphasis: "outline" })}>
  react
</Link>