Badge
A short label on something else, where the status is the word and never the colour.
NewLiveDraftFailed
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
npm i mihirmodi-ui motionThe 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
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
| Prop | Type | Notes |
|---|---|---|
| variant"solid" | "outline" | "soft" | "glass" | "solid" | "outline" | "soft" | "glass"= "soft" | Solid is ink, for the one that must be seen. |
| dotboolean | boolean | An ink dot before the label. |
| iconReactNode | ReactNode | A 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.
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>
);
}