Badge
A small marker overlaid on the corner of another element. Use it to report an unread count or a current status without covering what it sits on.
import { Badge, Button } from 'neba';
<Badge content={4} label="4 unread notifications">
<Button startIcon={<BellIcon />} />
</Badge>
<Badge dot color="success" overlap="circle">
<Avatar />
</Badge>;Props
| Prop | Type | Default | Description |
|---|---|---|---|
| variantshared | 'solid' | 'outline' | 'text' | 'solid' | Weight of the surface: filled, hairline, or none |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | The size of the mark, on a ladder of its own: a badge hangs off a corner, so it lines up with nothing |
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | Semantic colour role. Arbitrary colour values are not accepted |
| densityshared | 'default' | 'compact' | 'default' | The room around the digits, and nothing else |
| elevationshared | 0 | 1 | 2 | 3 | 0 | Drop shadow depth. 0 means no shadow at all |
| content | ReactNode | — | What the badge says: usually a count. Omit it and the badge draws a dot |
| max | number | 99 | Caps a numeric content and adds a plus. Text is never truncated |
| dot | boolean | false | Draws a dot even with content, keeping the count for screen readers only |
| showZero | boolean | false | Shows a count of zero. Off by default: zero unread messages is not news |
| invisible | boolean | false | Hides the marker without giving up its box, so nothing moves when it returns |
| placementshared | 'top-start' | 'top-end' | 'bottom-start' | 'bottom-end' | 'top-end' | Which corner it sits on. start/end, so the corner flips with the writing direction |
| overlap | 'square' | 'circle' | 'square' | The shape underneath, which decides how far the mark tucks in: a circle's corner is further out than a square's |
| label | string | — | What a screen reader hears instead of the raw count: "3" beside a bell means nothing |
| children | ReactNode | — | What the badge is pinned to. Without it, the badge is a standalone marker that lays out inline |
Given children, the wrapping <span> becomes the positioning context and the marker pins to its corner. Without children the marker lays out inline on its own, which is what a status marker in a table cell is.
The shared axes (variant size color density elevation) are defined in prop conventions.
Examples
variant and color
solid is a filled marker, outline a border over a faint panel, text a tinted mark with no edge. color picks one of the six role colours.
content and max
content is what the marker says. A number past max (default 99) renders as 99+; a string is never truncated.
A content of 0 draws nothing by default: turn it on with showZero. When there is nothing to count but something to report, use dot; invisible hides the marker while keeping the layout intact.
placement and overlap
placement is the corner the marker pins to: one of four values built from top/bottom and start/end. Because it uses start/end, the corner flips automatically in RTL.
overlap is the shape of the element underneath. circle tucks the marker further in, by the amount a circle's corner sits inside its bounding box, so the marker does not float off an avatar.
size
Badge has its own size steps rather than a step off the control heights. md is 18px, the smallest at which a two-digit number stays legible.
Accessibility
content={3}on its own is just "3" to a screen reader. A sentence inlabelbecomes the marker's accessible name instead.
<Badge content={3} label="3 unread notifications">
<Button startIcon={<BellIcon />} aria-label="Notifications" />
</Badge>- Under
dotthecontentstays in the DOM, clipped rather than removed, so what the dot means is still readable. - When the badge is
invisibleor has nothing to show, it leaves the DOM entirely, so find-on-page does not turn up text that is not on screen.