Count Badge
- Stable
- WCAG 2.2 evidence
- RTL
A small count or dot that flags unread, new or pending items. Place it on the corner of an icon, avatar or tab, or
beside a label. The number is real text, so it can be translated, zoomed and selected. For assistive technology label (for example
"{count} unread messages") replaces the bare number, and a dot without a label is hidden, because a coloured circle alone
says nothing (WCAG 1.1.1, 1.3.1, 1.4.1). Numbers above max read "99+". Presentational: renders in React Server Components. Consumer duties: write the label, keep the count truthful and updated, and announce changes that matter (LiveRegion):
the badge itself is not a live region.
import { CountBadge } from "@nexera-ui/react";- 5
- examples
- 5
- props
- 2
- live controls
- 1
- platform
- 6
- WCAG criteria
- 1
- block uses it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { CountBadge } from "@nexera-ui/react";
<CountBadge />Examples 4
The same examples as Storybook, rendered live. Open Code to copy one.
Large numbers
Numbers above max (99 by default) read "99+"; the label still gets the real number.
import { CountBadge } from "@nexera-ui/react";
export function LargeNumbers() {
return (
<div className="flex flex-wrap items-center gap-4">
{[1, 9, 10, 99, 100, 1250].map((count) => (
<CountBadge key={count} count={count} label="{count} unread messages" />
))}
<CountBadge count={42} max={9} label="{count} unread messages" />
<CountBadge count="New" label="New messages" tone="brand" />
</div>
);
}
On icon and avatar
On the corner of an icon and of an avatar, where the 2 px surface ring separates it from what it sits on.
import { Avatar, CountBadge } from "@nexera-ui/react";
import { LuBell } from "react-icons/lu";
export function OnIconAndAvatar() {
return (
<div className="flex items-center gap-8">
<span className="text-primary relative inline-flex size-8 items-center justify-center">
<LuBell className="size-6" />
<CountBadge
count={4}
label="{count} new notifications"
className="absolute -end-1.5 -top-1.5"
/>
<span className="sr-only">Notifications</span>
</span>
<span className="relative inline-flex">
<Avatar isDecorative initials="AK" size="lg" />
<CountBadge
type="dot"
tone="brand"
label="New activity"
className="absolute -end-0.5 -top-0.5"
/>
</span>
</div>
);
}
Beside label
Beside a label, as in a navigation row: the label and the badge are read together ("Inbox 3 unread messages").
import { CountBadge } from "@nexera-ui/react";
export function BesideLabel() {
return (
<ul className="text-body-default text-primary m-0 flex max-w-xs list-none flex-col gap-3 p-0">
<li className="flex items-center justify-between gap-3">
<span>Inbox</span>
<CountBadge count={3} label="{count} unread messages" />
</li>
<li className="flex items-center justify-between gap-3">
<span>Approvals waiting for the regional payroll administrator</span>
<CountBadge count={128} tone="neutral" label="{count} waiting" />
</li>
</ul>
);
}
Right to left
Right-to-left: the badge moves to the inline-end corner and the number stays left to right.
import { CountBadge } from "@nexera-ui/react";
import { LuBell } from "react-icons/lu";
export function RightToLeft() {
return (
<div dir="rtl" lang="ar" className="flex items-center gap-8">
<span className="text-primary relative inline-flex size-8 items-center justify-center">
<LuBell className="size-6" />
<CountBadge
count={100}
label="{count} إشعارات جديدة"
className="absolute -end-1.5 -top-1.5"
/>
</span>
<span className="text-body-default text-primary">الوارد</span>
<CountBadge count={3} label="{count} رسائل غير مقروءة" />
</div>
);
}
Props 5
Press "Try it" on a card to load that prop into the playground.
5 props shown
toneNexera"danger" | "brand" | "neutral"Colour set: danger for things that need attention (unread, overdue), brand for new or selected items,
neutral for a plain tally.
labelNexerastringText for assistive technology that says what is counted, with {count} standing for the number: "{count} unread
messages". It replaces the visible number for screen readers (the number is hidden from them, so nothing is read
twice). Translate it for your locale. Without it the visible number is read on its own, so say what is counted in
the element that holds the badge, and always give a Type=Dot a label: a dot without one is decorative and hidden
from assistive technology (WCAG 1.1.1, 1.3.1).
typeNexera"count" | "dot"What the badge is: count is a pill with the number, dot a 10 px circle without one.
A dot: something is new or needs attention, without saying how many.
countNexerastring | numberThe number shown. A number above max is shown as "99+"; label's {count} still receives the real number. A string is shown as it is, for example "New".
A dot has no number.
maxNexeranumberLargest number shown in full; above it the badge reads "{max}+". A dot has no number.
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
4 direct · 2 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.3.2Meaningful SequenceLevel A · supporting test
- 1.4.1Use of ColorLevel A · tested directly
- 1.4.11Non-text ContrastLevel AA · supporting test
- 4.1.2Name, Role, ValueLevel A · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<CountBadge className="shadow-sm" />Used in blocks
Related components
- AccordionItemOne collapsible section of an FAQ or settings page.
- AreaChartA stacked area chart: layers piled up over time with the title, range switch, actions and legend of the card.
- AvailabilityRowOne person's availability across a window of the day: an avatar with initials and the name, and a timeline with the busy periods drawn as bars.
- AvatarA person or organisation shown as a photo, initials or an icon.
- AvatarGroupA row of overlapping avatars with a "+N" chip for the rest.
- AvatarLabelAn avatar with a name and an optional subtitle beside it, for a person in a list, a header or a mention.
- BadgeShort status or category label: `Tone` x `Variant` x `Size`, with an optional dot, leading icon and remove button.
- BadgeGroupA pill that pairs a small badge with a short message, for an announcement or a status line.