Badge

A small word or number at the edge of something else: a status, a count (also called a label or chip). Reach for it to mark the state of a row, or how many items wait behind a button.

import { Badge } from "@umriss-ui/core";

It is never the only place a state is said: the word inside carries the meaning, and the tone repeats it for the eye.

Examples

A badge

A short word at the edge of what it describes; it repeats a state the text around it could also carry.

import { Badge, Text } from "@umriss-ui/core";

export default function ABadge() {
  return (
    <Text size="sm">
      Profile page <Badge>In progress</Badge>
    </Text>
  );
}

Tones

Give each state one tone and keep it across the application; the word inside always says the same as the colour.

import { Badge, Stack } from "@umriss-ui/core";

export default function Tones() {
  return (
    <Stack direction="row" gap={2} wrap align="center">
      <Badge>To do</Badge>
      <Badge tone="accent">In progress</Badge>
      <Badge tone="warning">In review</Badge>
      <Badge tone="success">Done</Badge>
      <Badge tone="danger">Blocked</Badge>
    </Stack>
  );
}

Counters

pill is the shape for numbers: a number in it reads as a quantity. Cap long counts yourself, as in “99+”.

import { Badge, Button, Stack } from "@umriss-ui/core";

function capped(count: number) {
  return count > 99 ? "99+" : String(count);
}

export default function Counters() {
  return (
    <Stack direction="row" gap={3} wrap align="center">
      <Button size="sm">
        Open incidents <Badge pill tone="danger">{capped(2)}</Badge>
      </Button>
      <Button size="sm">
        Alerts <Badge pill tone="accent">{capped(7)}</Badge>
      </Button>
      <Button size="sm">
        Resolved this month <Badge pill>{capped(148)}</Badge>
      </Button>
    </Stack>
  );
}

Mark the state of each row

In a list the badges line up in one column, so the eye runs down the states without reading every title.

import { Badge, Stack, Text } from "@umriss-ui/core";
import type { BadgeTone } from "@umriss-ui/core";

/* Data from the planning world, written out here so the example runs on its own. */
const at = (day: number, hours = 9, minutes = 0) => new Date(2026, 2, day, hours, minutes).getTime();

/** A work item, shaped as `@umriss-ui/schedule`'s `Subtask`. */
interface WorkItem {
  id: string;
  /** The project. */
  task: string;
  /** The person. */
  lane: string;
  from: number;
  to: number;
  name: string;
  sprint: string;
  /** Hours, as estimated at planning. */
  estimate: number;
  status: "to do" | "in progress" | "in review" | "done";
}

const item = (id: string, task: string, lane: string, from: number, to: number, name: string, estimate: number, status: WorkItem["status"]): WorkItem =>
  ({ id, task, lane, from, to, name, sprint: "sprint-14", estimate, status });

const WORK: readonly WorkItem[] = [
  item("w-101", "portal", "arjun", at(9), at(11, 17), "Sign-in with e-mail code", 18, "done"),
  item("w-102", "portal", "arjun", at(12), at(17, 17), "Profile page", 26, "in progress"),
  item("w-103", "portal", "chloe", at(9), at(10, 17), "Session handling", 12, "done"),
  item("w-104", "shop", "chloe", at(11), at(13, 17), "Basket keeps items across devices", 20, "in review"),
  item("w-105", "portal", "chloe", at(16), at(19, 17), "Change of address form", 24, "in progress"),
  item("w-106", "portal", "noah", at(9), at(12, 13), "Profile page design", 14, "done"),
  item("w-107", "shop", "noah", at(16), at(18, 17), "Search results layout", 12, "to do"),
  item("w-108", "portal", "eva", at(12), at(13, 17), "Test plan for sign-in", 10, "done"),
  item("w-109", "portal", "eva", at(17), at(20, 17), "Regression run", 20, "to do"),
  item("w-110", "booking", "hana", at(9), at(13, 17), "Reminder scheduling service", 32, "done"),
  item("w-111", "booking", "hana", at(16), at(20, 17), "Push notifications", 30, "in progress"),
  item("w-112", "booking", "kofi", at(10), at(12, 17), "Calendar sync", 18, "done"),
  item("w-113", "intranet", "kofi", at(16), at(18, 17), "News feed", 16, "in progress"),
  item("w-114", "booking", "freya", at(9), at(11, 17), "Reminder settings screen", 16, "done"),
  item("w-115", "booking", "freya", at(18), at(20, 17), "Store screenshots", 12, "to do"),
  item("w-116", "booking", "david", at(16), at(19, 13), "Device test matrix", 14, "to do"),
];

const TONE: Record<WorkItem["status"], BadgeTone> = {
  "to do": "neutral",
  "in progress": "accent",
  "in review": "warning",
  done: "success",
};

export default function InAList() {
  return (
    <Stack gap={2} style={{ maxWidth: 520 }}>
      {WORK.filter((item) => item.task === "portal").map((item) => (
        <Stack key={item.id} direction="row" gap={3} align="center">
          <Text as="span" size="sm" mono tone="muted">
            {item.id}
          </Text>
          <Text as="span" size="sm" style={{ flex: 1 }}>
            {item.name}
          </Text>
          <Badge tone={TONE[item.status]}>{item.status}</Badge>
        </Stack>
      ))}
    </Stack>
  );
}

When to use something else

Keyboard

The keys of Button apply here.

API

BadgeProps

NameTypeDefaultDescription
toneBadgeTone
| "neutral"
| "accent"
| "success"
| "warning"
| "danger"
"neutral"What the badge stands for. There is always a word beside it: a colour on its own is not a statement.

Shown in: Configurator, Tones, Counters and 19 more

pillbooleanfalseFully rounded pill shape - for counters and key figures. The default is the slightly rounded badge shape for status labels.

Shown in: Configurator, Counters, Fold the body (Card) and 1 more

refRef<HTMLSpanElement>—Receives the component's root element. from RefProp

Shown in: A row that holds still (Sizes), An anchored surface (Popover), Take the width of the trigger (Popover) and 2 more

Also takes every attribute of <span>.

Types on this page

BadgeTone

What a badge stands for - never the only statement, a word stands beside it.

type BadgeTone = "neutral" | "accent" | "success" | "warning" | "danger";

Known limits

What umriss deliberately does not build, and why: ADR-0032.

Every page of @umriss-ui/core

Getting started

Customising

Layout

Typography

Actions

Forms

Choosing

Dates and times

Feedback

Overlays

Navigation

Data display

API index