Badge
stableA visual indicator that represents numeric values such as counters.
Overview
Badge is a small indicator that draws attention to a related element, most often by displaying a count. It's used to surface activity or volume — unread notifications, pending tasks, items in a queue — without requiring the user to leave the surface they're on. Badge is decorative; the meaning comes from what it's attached to.
Usage
When to use
- Showing unread or new counts on a navigation icon (notifications, messages)
- Indicating items pending review or action on a queue or list item
- Surfacing activity volume on a tab, list row, or avatar
When not to use
- Communicating status (active, error, warning) — use Status indicator instead
- Displaying non-numeric labels or categories — use Tag or Pill instead
- Conveying critical information that must be read — Badge is supplementary, not primary
Place the badge at the top-right of the thing it marks, overlapping the edge. The badge does not position itself.
Alternatives
Use when communicating state (online, error, warning) rather than quantity.
Use for non-numeric labels, categories, or filters.
Use for selectable filters or removable labels.
Anatomy
The badge component is made up of two elements.

- Container
Background shape that wraps the badge content. Has a minimum width that prevents contraction below a circle.
- Count
Numeric value shown inside the badge. Optional — when omitted, the badge renders as a dot.
Variants
Count
The default variant. Displays a numeric value inside the container. The badge expands and contracts to fit the count text, with a minimum width that keeps it from contracting narrower than a circle.
Use when the explicit tally matters — when "how many" is the information the user needs.
Dot
Renders as a circle with no displayed value. Used when the presence of activity is what matters, not the precise count.
Best in condensed layouts where space is tight, or on surfaces where the explicit number would be visually noisy without adding meaning (e.g., on an avatar to indicate "this contact has unread messages").
Max count
A max count limits the number displayed. When the count exceeds the max,
a + is appended. The max defaults to 99. Adjust or remove it based on
how much horizontal space is available and how precise the tally needs
to be. Use it when a count can grow long enough to collide with
surrounding content. Counts are numeric and at least 0. Omit the count
to render a dot.
States
Badge is non-interactive and has no hover, focus, or pressed states. Document the contextual states that affect appearance.
Default
On dark surface
On a dark surface, use the same count and dot.
At max count
Renders as {maxCount}+ when the underlying count exceeds the max.
Configuration
import '@jack-henry/jh-elements/components/badge/badge.js'| Prop | Type | Default | Description |
|---|---|---|---|
count | string | Number to show within the badge. If no count is supplied, Badge will render as a dot. | |
max-count | number | 99 | Sets the max count to show. Appends + to the max-count when value is exceeded. |
Theming
Tune via style hook
| Hook | Description | Default |
|---|
1 Container background (1)
| Hook | Description | Default |
|---|---|---|
--jh-badge-color-background-enabled | The badge background color. | --jh-color-content-negative-enabled |
1 Container radius (1)
| Hook | Description | Default |
|---|---|---|
--jh-badge-border-radius | The badge border radius. | --jh-border-radius-pill |
2 Text color (1)
| Hook | Description | Default |
|---|---|---|
--jh-badge-color-text-enabled | The badge text color. | --jh-color-content-on-negative-enabled |
Examples
Badge on a notification icon
The canonical use — overlaying an unread count on a navigation icon.
<jh-badge count="3"></jh-badge>Dot variant on an avatar
Use the dot when the count itself isn't informative — here, presence of unread activity is enough.
<jh-badge></jh-badge>Badge with max count
When counts can grow large, cap the displayed value to keep the badge from overflowing into adjacent content.
<jh-badge count="247" max-count="99"></jh-badge>Badge on a tab
Surfacing pending counts on tab labels lets users see where work waits without changing context.
<jh-badge count="4"></jh-badge>Count, dot, and max
Omit count for a dot. Set max-count when the tally should stop growing.
<jh-badge></jh-badge>
<jh-badge count="50"></jh-badge>
<jh-badge count="142"></jh-badge>
<jh-badge count="25" max-count="10"></jh-badge>Accessibility
WCAG conformance
Badge meets WCAG 2.2 success criteria 1.4.3 (Contrast Minimum) and 1.4.11 (Non-text Contrast) when used with default tokens on the default surface. Custom token overrides are the consumer's responsibility to validate. Also of concern: 1.4.1 (Use of Color) — color is not the only way the count is conveyed — and 1.4.4 (Resize Text) — the badge can scale to 200 percent without losing the count.
Keyboard
Badge is non-interactive and not focusable. It has no keyboard behavior of its own. When Badge wraps an interactive element (like an IconButton), the wrapped element handles keyboard interaction.
Screen reader
By default, Badge's count is read aloud as a number adjacent to its parent element. This is rarely sufficient on its own — "3" by itself doesn't tell a screen reader user what the 3 means.
When Badge is attached to an interactive element, the parent must include the count's meaning in its accessible name. For the dot variant, the parent must say that there is activity, because there is no count to read. When the badge marks a change on the page, such as a new message, put that update in a live region.