← All components

Badge

A short label on something else, where the status is the word and never the colour.

NewLiveDraftFailedv0.2.0

The idea

A green Live and a red Failed ask the reader to have learnt a legend, and to see colour at all; Live and Failed in the same grey need neither. When there is a dot, it says that the thing has a state; the word says which. Solid ink is kept for the one label that must be seen.

Install

terminal1 line
npm i mihirmodi-ui motion

The tokens, the theme script and the routing provider are a one-time job — see Setup. Or skip the package entirely and take the source at the foot of this page.

Usage

Badge — usage6 lines
import { Badge } from "mihirmodi-ui";

// The word is the status; the dot only says there is one.
<Badge dot>Live</Badge>
<Badge variant="outline">Draft</Badge>
<Badge variant="solid">New</Badge>

Props

PropNotes
variant"solid" | "outline" | "soft" | "glass"Solid is ink, for the one that must be seen.
dotbooleanAn ink dot before the label.
iconReactNodeA mark before the label.

Source

Exactly what the package ships — this is read out of the source at build time, not a copy. Take it and adapt it if you would rather not add a dependency.

packages/ui/src/components/actions/Badge.tsx40 lines
import type { ReactNode } from "react";

export type BadgeVariant = "solid" | "outline" | "soft" | "glass";

export type BadgeProps = {
  /** `solid` is ink, for the one label that must be seen. `soft` and `outline` sit quietly in a row. */
  variant?: BadgeVariant;
  /** A dot before the label — live, draft, new. It is ink, not a colour: the word says which. */
  dot?: boolean;
  icon?: ReactNode;
  children: ReactNode;
  className?: string;
};

const LOOK: Record<BadgeVariant, string> = {
  solid: "bg-ink text-background-100",
  outline: "border-[0.5px] border-gray-alpha-500 text-muted",
  soft: "bg-gray-alpha-200 text-gray-1000",
  glass: "glass-menu border-[0.5px] border-gray-alpha-400 text-gray-1000",
};

/**
 * A short label on something else — a status, a count, a version.
 *
 * Statuses are words, not colours. A green "Live" and a red "Failed" ask the
 * reader to have learnt a legend and to see colour at all; "Live" and
 * "Failed" in the same grey need neither. The dot, when there is one, says
 * *that* this has a state, and the word says which.
 */
export function Badge({ variant = "soft", dot, icon, children, className = "" }: BadgeProps) {
  return (
    <span
      className={`inline-flex h-[22px] items-center gap-1.5 whitespace-nowrap rounded-full px-2 text-[11px] font-medium leading-none tabular-nums ${LOOK[variant]} ${className}`}
    >
      {dot && <span aria-hidden className="h-1.5 w-1.5 rounded-full bg-current" />}
      {icon && <span className="-ml-0.5 flex items-center">{icon}</span>}
      {children}
    </span>
  );
}