Badge
A small piece of status text. The lightest component in the library, and the one whose accessibility problem is the least obvious.
Example (a11y tier)
Import
import Badge from 'abaabil/badge' // structure onlyimport Badge from 'abaabil/badge/styled' // + CSSimport Badge from 'abaabil/badge/a11y' // + context“3” is not a message
A badge is shorthand that only means something beside what it is attached to. Next to an inbox icon, “3” is obvious. Read out on its own, in a list of everything on the page, it is noise: the user hears “three” and has no way to know three of what.
context supplies the rest of the sentence, so the badge still draws 3 and announces “3 unread messages”.
<Badge variant="danger" context="unread messages">3</Badge>Why hidden text and not aria-label
Because aria-label would do nothing. A badge is a <span>, a span has no role, and aria-label is prohibited on a generic element: set it there and the browser discards it, leaving the badge exactly as unlabelled as before while looking fixed.
That is not a hypothetical. It shipped in this library's own popover one release earlier, where naming the panel was the entire job of the a11y tier and the name was being thrown away. It was found by computing the accessible name rather than by reading the code, and this component was written the other way round because of it.
Not a live region
A count that changes while the page is open does not announce itself, and this component does not make it. That is deliberate: most badges change often and matter little, and a live region that interrupts for every increment is worse than silence. If a change really is worth interrupting for, wrap it in alert.
Props
| Prop | Type | Default | Tier | Description |
|---|---|---|---|---|
variant | 'neutral' | 'info' | 'success' | 'warning' | 'danger' | 'neutral' | all | Applied as data-variant. |
className | string | — | all | Merged with the base class. |
context | string | — | a11y | The rest of the sentence, announced but not drawn. |