HabBadge
A non-interactive state label — build status, role, version state.
<HabBadge tone="success">Passing</HabBadge>Use HabChip instead when the thing is selectable, removable or a filter. Badge and Chip look deliberately similar and behave completely differently, so the choice is about what the user can do with it, not how it looks.
Tones
The five tinted tones read their --hab-<tone>-tint / -text pair. neutral is the exception on both counts. Three details are not obvious:
neutralfills with the--hab-neutral-tonaloverlay, not a surface token. A badge does not know what it sits on, and--hab-containedis a fixed fill mixed for the page surface — on--hab-surface-2(a panel's raised header, a footer, a banded row) it landed within two units of its background in dark mode, so the badge stopped reading as a badge. An overlay lightens or darkens whatever is under it, which is the same step on either surface. The tinted tones never had the problem: a-tintis a colour against a neutral ground, and that difference survives a surface change.neutralcarries a real border; the tinted tones carry a transparent one. The overlay's step is deliberately small, so fill alone is too close to its ground to carry the badge's outline on a tinted light surface. The transparent border on the other five keeps all six geometrically identical.accentuses--hab-accent-text, not--hab-accent-on.-onis the accent used as text on a neutral surface. On the accent tint it would be the base color on a tint of itself, which is the exact failure the-textleg exists to prevent.
Icons
<HabBadge tone="success" :icon="mdiCheckCircle">Passing</HabBadge>The icon is sized from --hab-icon-sm, never from the type ladder. Badge was the one component in the system sizing its glyph off type, which produced a fifth icon size in a system that documents four.
The height is pinned at --hab-control-xs, so an icon never changes the box. Left to the type it came out 23px, and an icon pushed it to 26px — a row mixing plain and icon badges sat 3px out of line.
The icon is decorative and aria-hidden. The label carries the meaning: a badge with an icon and no text is a colored box to a screen reader.
An arbitrary color
color overrides tone for a classifying color that comes from data — an entity kind, a session role.
<HabBadge :color="entity.color">{{ entity.kind }}</HabBadge>Fill, edge and text are all mixed from the one value: 14% fill, 32% edge, and text at --hab-tint-text-mix (45%) toward --hab-fg.
Pass the base color, not a pre-darkened one. The text is deliberately darkened toward the ink rather than being the base color — base-on-its-own-tint is what the -text leg exists to prevent, and it failed AA for half the hues in both product palettes. 45% is the highest ratio that clears 4.5:1 for every hue.
Passing a color drops the tone treatment entirely rather than layering over it, so the two can never disagree.
Uppercase
uppercase opens the tracking along with the transform — uppercase at 11px without tracking sets solid. Reach for it for built-in or system labels rather than states: a status that shouts reads as an alarm.
Code values
mono sets the label in the mono face, for a value that is code rather than a word — a type, an id, an environment variable's name. It replaces the sans rather than adding to it: a font-mono class passed from outside would compete with the component's own font by stylesheet order, and lose or win by accident.
Long labels
A badge is never wider than its container: a label that does not fit ends in an ellipsis, as HabChip's does. When the cut-off part matters, wrap the badge in a HabTooltip carrying the whole value.
Accessibility
- A plain
<span>with no role and no tab stop. It is a label, not a control. - Never let the color be the only thing carrying the meaning. The label text has to say it too — for anyone color-blind, anyone in forced-colors mode, and anyone using a screen reader.
- Every built-in tone pair is contrast-measured. An arbitrary
coloris mixed to clear AA for every hue in the palette, but if you pass something far outside it, check the result. - If the badge communicates a change that matters as it happens, the live region belongs on the container that owns the update, not on the badge.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
color | string | undefined | An arbitrary classifying color, overriding tone — an entity kind, a session role. Any CSS color, var() included. The fill, edge and text are all mixed from it, and the text is darkened toward --hab-fg so any hue clears AA on its own tint. Pass the base color, not a pre-darkened one. |
icon | string | undefined | Leading icon as SVG path data, e.g. mdiCheck from @mdi/js. Decorative — the label is what carries the meaning. |
mono | boolean | false | Sets the label in the mono face: for a value that is code — a type, an id, an environment variable's name — not a word. One font, never both: a mono class added from outside would compete with the component's own sans by stylesheet order. |
tone | "error" | "neutral" | "accent" | "info" | "success" | "warning" | "neutral" | Semantic color role. |
uppercase | boolean | false | Uppercases the label and opens its tracking. For built-in or system labels rather than states. |
Slots
| Slot | Bindings | Description |
|---|---|---|
default | any | The label. A badge with no label is a colored box; give it text. |
leading | any | Leading adornment, replacing the glyph. Takes precedence over icon. |