ComponentsData display

Badge

A count beside a label: unread mail, Applications in a stage, tasks due today. Only numbers go in a badge. A status is a lozenge and a label is a tag.

Playground

Change the controls to try each prop. The code under the preview updates as you go and lists only the props you changed; copy it into your page.

14
import { Badge } from '@/ui/badge';<Badge>  14</Badge>

Default

Totals that inform: rows in a View, records in a stage, files on a record. Grey fill, subtle text.

414128
import { Badge } from '@/ui/badge';

export default function BadgeDefault() {
  return (
    <div className="flex items-center gap-100">
      <Badge>{4}</Badge>
      <Badge>{14}</Badge>
      <Badge>{128}</Badge>
    </div>
  );
}

Important

Counts that ask for action: unread conversations, items in Needs you. Ink fill, white text. Use one per area.

312
import { Badge } from '@/ui/badge';

export default function BadgeImportant() {
  return (
    <div className="flex items-center gap-100">
      <Badge appearance="important">{3}</Badge>
      <Badge appearance="important">{12}</Badge>
    </div>
  );
}

Max

Above max (99 unless you set it) the badge shows 99+. Screen readers still hear the real number.

12812
import { Badge } from '@/ui/badge';

export default function BadgeMax() {
  return (
    <div className="flex items-center gap-100">
      <Badge>{128}</Badge>
      <Badge appearance="important" max={9}>
        {12}
      </Badge>
    </div>
  );
}

In context

Tab count

The badge goes after the label, 6px from it. A tab with nothing in it shows no badge.

import { Badge } from '@/ui/badge';
import { Button } from '@/ui/button';

const tabs = [
  { label: 'Applications', count: 14 },
  { label: 'Contacts', count: 6 },
  { label: 'Files', count: 0 },
];

export default function BadgeTabCount() {
  return (
    <div className="flex items-center gap-100">
      {tabs.map((tab) => (
        <Button key={tab.label} variant="ghost">
          {tab.label}
          <Badge>{tab.count}</Badge>
        </Button>
      ))}
    </div>
  );
}

In a navigation row the badge sits at the end, so counts line up. The row's name includes the count.

import { Badge } from '@/ui/badge';
import { Button } from '@/ui/button';

export default function BadgeNavigationCount() {
  return (
    <div className="flex w-56 flex-col gap-025">
      <Button variant="ghost" className="justify-between" aria-label="Inbox, 3 unread">
        Inbox
        <Badge appearance="important">{3}</Badge>
      </Button>
      <Button variant="ghost" className="justify-between" aria-label="Tasks, 8 due">
        Tasks
        <Badge>{8}</Badge>
      </Button>
    </div>
  );
}

Zero

At zero the badge renders nothing. Never show 0, and never a dot without a number.

import { Badge } from '@/ui/badge';
import { Button } from '@/ui/button';

export default function BadgeZero() {
  const unread = 0;
  return (
    <Button variant="ghost">
      Inbox
      <Badge appearance="important">{unread}</Badge>
    </Button>
  );
}

On this page