Badge
The little red number on a tab, the dot on an avatar, the "Sale" label on a product. Learn count, dot and status badges, app icon badges on iOS and Android, and the zero, overflow, stale count and accessibility bugs testers find in them.
A red 3 on the Chats tab. A dot on the bell. Sale −20% on a pair of running shoes. A 12 on your banking app’s icon that won’t go away, no matter how many times you open the app.
Badges are tiny, but they make a promise: “there’s something here for you”. When the promise is wrong (a “0” that should be gone, a count that never updates, a number nobody can hear) users stop trusting it, or they open the app twenty times a day for nothing. Here’s how to test them.
What is a badge?
A badge is a small marker attached to another element (an icon, a tab, an avatar, a card) that adds a bit of status. It doesn’t do anything on its own; tapping the badge is tapping the thing it sits on.
There are three kinds, and it’s worth naming them correctly in bug reports:
| Kind | Looks like | Means | Example |
|---|---|---|---|
| Count badge | Small pill with a number | How many new things | Chats 3, cart 2 |
| Dot badge | Small dot, no number | Something new, or a presence state | Dot on the bell, green dot on an avatar |
| Status label (pill, tag) | Word in a colored pill | A property of the item | New, Sale −20%, Sold out, In transit |
Count and dot badges are about attention and change all the time. Status labels describe the item and change with its data. Both are UI stateUI stateHow a component looks and behaves in a given situation: default, hover, pressed, focused, disabled, loading, error.Open in glossary → that has to match the real data behind it.
Anatomy
- 1
Anchor
The icon, tab, avatar or card the badge belongs to. The badge sits on its corner and must never hide it.
- 2
Count badge
A number: unread messages, items in the cart. Capped ("99+") and hidden at zero.
- 3
Dot badge
No number, just "something new here". Also used for presence (online) on avatars.
- 4
Status label (pill)
"Sale −20%", "Sold out", "In transit". A word that describes the item, not a count. The text carries the meaning, color only supports it.
- 5
Separator ring
A thin outline in the background color, so the badge stays readable on top of the icon or photo.
- 6
Accessible name
Not visible, but essential: the screen reader must hear the count with the anchor, e.g. "Messages, 3 unread".
Designs & variants
Several of these react to taps. Use the switch to compare light and dark.
Tab bar badge
iOSRed pill with a white number on the top-right of the icon. Tap Chats: the badge disappears when the messages are read.
Small and large badges
Android · Material 3A 6 dp dot for “something new”, a 16 dp badge for numbers. Material caps at four characters: 999+.
Tap the bag to add items (caps at 9+, hides at 0).
Header icons
WebCart count and a notification dot. Each icon button needs a name that includes the count.
- ANOnline
- MKAway
- JSOffline
Presence on avatars
iOS · Android · WebGreen, orange, nothing. Without the text below, colorblind and screen reader users can't tell who's online.
Status labels (pills)
iOS · Android · WebWords, not numbers: Sale, New, Sold out. The word carries the meaning; the color is a bonus.
App icon badges
iOS · AndroidSet by the OS from the app's notifications. iOS shows a number (if the user allows badges); Android launchers usually show a dot.
Where badges sit
- On icons in tab bars and navigation bars: the top-right corner of the icon, overlapping it slightly, never covering it. See Navigation Bar and Tabs.
- Inside a tab or list row: a counter next to the label (Inbox 24, Unread 3). Here it’s part of the text, not floating on top.
- On avatars: a presence dot (online, away) in the bottom-right corner, with a ring in the background color so it stands out from the photo.
- On cards and product tiles: a status label in a corner or next to the price, like the “Sold out” label on the Card page.
- On the app icon: drawn by the operating system, not by the app. More on that below.
The rules for counts
- Zero hides the badge. “0” means “nothing new”, which is exactly what no badge says. A red “0” is a bug.
- Big numbers are capped. Exact counts above a limit don’t help anyone and break the layout. iOS apps usually show 99+; Material 3 allows at most four characters, so 999+.
- The number is the truth. It equals the number of unread (or new) things, not “how many arrived since you last looked”, unless the spec says otherwise.
- It updates when the truth changes. Reading a message, marking all as read, reading it on another device, deleting it: the badge follows, without a restart.
- It has words for screen readers. The visible “3” becomes “Chats, 3 unread” in the accessible name.
When does the count update?
Ask this before you test, because there are two valid designs:
- Realtime: the server pushes changes (a push notificationPush notificationA message an app sends to the device that appears even when the app is closed.Open in glossary →, a websocket) and the badge updates while you look at the screen. Typical for chat.
- On open or refresh: the app fetches counts when it starts, comes back from the background or the user pulls to refresh. Typical for shops and news.
Either way, the badge must be right after every way of reading: opening the item, “Mark all as read”, swiping it away, reading it on the web, and coming back from the background (Background and foreground). And when the user reads something, the badge should drop immediately, without waiting for the next sync.
App icon badges (iOS and Android)
The number or dot on the app icon is drawn by the system, so it follows the system’s rules:
- iOS shows a red number on the icon. The app can only set it if the user allowed notifications with badges; the user can switch badges off per app in Settings › Notifications. The app (or its server, via the push payload) is responsible for setting it back to zero. A stuck icon badge is one of the most common badge bugs.
- Android (8.0 and newer) shows notification dots: a dot appears while the app has active notifications, and long-pressing the icon shows them. Some launchers (Samsung, for example) can show a number instead. The dot disappears when the notifications are dismissed, so test dismissing them, not only opening the app. On Android 13+, notifications need a runtime permission, so no permission means no dot. See Push Notifications.
- Web: installed web apps can set an icon badge where the browser and OS support it. Websites often put the count in the page title instead: (3) Inbox.
Dev note
Icon badges use the Badging API (navigator.setAppBadge()).
Push it to the limits
Try the counts testers always try: 0, 1, 99, 100, 1,000 and 12,345. Then shrink the screen, raise the text size and turn off the count in the accessible name.
🧪 Badge stress test
Feed the badge awkward numbers, shrink the screen and make the text huge. Watch the tab bar and what a screen reader would say.
Unread count: 3
Cap the number at
Only matters above the cap: try 100 or 1,000.
Style
Screen width: 360px
Text size: 100%
VoiceOver: "Chats, 3 unread, tab, 1 of 5"
Real count 3 · badge shows "3"
Looks good. Now try 12,345 with no cap, 0 without hiding, a 260px screen or 200% text.
When to use it
- To show that new or unread things are waiting somewhere else: messages, notifications, order updates.
- To show how many items are in a container the user cares about: cart, downloads queue.
- To show a short status that helps users scan a list: Sale, New, Sold out, Delivered.
- To show presence: online, away, busy.
Good and bad uses
No badge when there's nothing new
The Calls tab is quiet. Users can trust that a badge means something.
A badge that says 0
Red and alarming, but it means “nothing”. Users tap it anyway, every time.
Capped at 99+
Fits on the icon and says the same: “a lot”.
The exact four-digit count
“1284” is too wide for the tab and spills over the neighbor.
Status as a word
“Sale −20%” and “New” are readable by everyone, including screen readers.
Status as a colored dot
Red means sale, green means new, if you can see the difference. Many people can’t.
Also avoid badges as decoration (a permanent “NEW” on a feature launched a year ago), badges on everything at once (if every tab has a badge, none stands out), and badges for things the user can’t act on.
Common bugs
| # | Bug | What you see | Typical severity |
|---|---|---|---|
| 1 | Zero shown | A red “0” instead of no badge | Low–Medium |
| 2 | No cap | “1000” or “12345” overflows the tab, overlaps the next icon or is cut off | Medium |
| 3 | Stale count | Badge doesn’t drop after reading, only after restarting the app | Medium |
| 4 | Wrong count | Counts messages instead of chats (or the other way round), counts read items, counts twice | Medium |
| 5 | Stuck app icon badge | The icon shows 12 even though everything is read | Medium |
| 6 | Count not spoken | Screen reader says “Chats, tab” but not “3 unread” | High (for affected users) |
| 7 | Color-only status | Sale and New differ only by red vs green | Medium |
| 8 | Badge hides the anchor | With large text or on a small screen the badge covers the icon | Medium |
| 9 | Low contrast | Light text on a bright red or a pastel pill; invisible in dark modeDark modeA display setting that uses light text on dark backgrounds.Open in glossary → | Low–Medium |
| 10 | Inconsistent counts | Tab says 3, the list shows 2 unread, the app icon says 5 | Medium |
| 11 | Negative or nonsense values | “-1” after deleting, “NaN”, “undefined” | Medium |
| 12 | Localization | “99+” or “Sold out” not translated, or a long word like “Ausverkauft” truncated | Low–Medium |
Find the bug
This messenger has six badge bugs. Explore it like a tester:
- Look at every tab’s badge. Then visit each tab and come back.
- Open a few unread chats and go back. Does the Chats badge agree with the list? Try Restart app.
- Turn on Screen reader and tap a tab once to hear it (twice to open it).
- Open Shop and turn on the grayscale color filter.
- Turn on Larger text and look at the tab bar.
🐞 Bug hunt: Messenger badges
This demo has 6 hidden bugs. Explore it like a tester, then check your findings.
Chats
Device settings
- 1
Hint: Open the Calls tab, then go back to Chats and look at the Calls icon.
- 2
Hint: Look at the Channels tab badge, especially on the right edge of its tab.
- 3
Hint: Open Ana's and Marko's chats, go back, and compare the badge with the list. Then tap Restart app.
- 4
Hint: Turn on Screen reader, tap the Chats tab once, then a chat row once.
- 5
Hint: Open Shop, read the legend, then turn on the grayscale color filter. Also try the screen reader on a product.
- 6
Hint: Turn on Larger text and look at the Chats, Calls and Channels icons.
How to test it
Checklist
Badge test checklist
0 of 13 checked
Example test cases
TC-BDG-001Badge disappears at zeroedgemedium
Preconditions
- 2 missed calls, Calls badge shows 2
Steps
- Open the Calls tab
- Go back to Chats
Expected result
The Calls badge is gone. No "0" is shown.
TC-BDG-002Count is capped above the limitedgemedium
Preconditions
- Test account with 99, then 100, then 1,284 unread items
Steps
- Open the app with 99 unread
- Receive one more item
- Switch to the account with 1,284 unread
Test data
Counts: 99, 100, 1,284
Expected result
Badge shows "99", then "99+", then "99+". It stays inside its tab on the smallest supported screen.
TC-BDG-003Badge updates after readingpositivehigh
Preconditions
- 3 unread chats
Steps
- Open one unread chat and go back
- Use "Mark all as read"
Expected result
Badge shows 2 right after going back, then disappears after Mark all as read. No restart needed.
TC-BDG-004Badge syncs when read on another devicepositivemedium
Preconditions
- Same account on phone and web, 2 unread chats
Steps
- Read both chats on the web
- Return to the app on the phone (from the background)
Expected result
The tab badge and the app icon badge both clear within the expected sync time.
TC-BDG-005Screen reader announces the countpositivehigh
Preconditions
- VoiceOver or TalkBack on
- 3 unread chats
Steps
- Move focus to the Chats tab
Expected result
The screen reader says something like "Chats, 3 unread, tab, 1 of 5". After reading one chat, it says "2 unread".
TC-BDG-006Status labels without colorpositivemedium
Steps
- Open the shop list
- Turn on a grayscale color filter (iOS: Accessibility › Display & Text Size › Color Filters; Android: Accessibility › Color correction or Developer options › Simulate color space)
Expected result
Every status (Sale, New, Sold out) is still readable as text.
TC-BDG-007App icon badge clears (iOS)positivemedium
Preconditions
- Notifications with badges allowed
- App icon shows 4
Steps
- Open the app
- Read all 4 items
- Go to the home screen
Expected result
The app icon shows no badge.
Tip: click a test case to expand it.
Accessibility
- The count belongs in the accessible name. A visual badge is usually hidden from assistive tech, so the element itself must say it: “Chats, 3 unread”, “Cart, 2 items”. This is WCAG 4.1.2 Name, Role, Value (Level A). Test with a screen readerScreen readerSoftware that reads the screen aloud for blind and low-vision users, like VoiceOver or TalkBack.Open in glossary →.
Dev note
The badge is hidden witharia-hidden="true". On the web, usearia-labelon the button or visually hidden text; on iOS theaccessibilityValueor label; on Android thecontentDescriptionor state description. - Say what’s capped. If the badge shows “99+”, the name can say “more than 99 unread”. Never just “99 plus”.
- Changing counts. Users don’t need every change announced, but if a count change matters (an item added to the cart), a polite announcement helps (WCAG 4.1.3 Status Messages, Level AA). See ARIAARIAHTML attributes that tell assistive technology what custom elements are and what state they're in.Open in glossary →.
- Not color alone. Status labels need text; presence dots need a text equivalent (“Ana, online”). WCAG 1.4.1 Use of Color (Level A).
- Contrast. The number in the badge needs 4.5:1 against the badge color, and the badge 3:1 against what’s behind it (WCAG 1.4.3 / 1.4.11). White on a bright red often lands around 3.5:1, so measure it with a contrast ratioContrast ratioHow different text and background colors are; WCAG asks for at least 4.5:1 for normal text.Open in glossary → checker, in light and in dark mode.
- Text size. At the largest Dynamic TypeDynamic TypeThe phone setting that lets users make text bigger or smaller across apps.Open in glossary → or font scale, the badge must stay readable and must not hide its icon or the neighbor.
- Touch targetsTouch targetThe area of the screen that responds to a tap, which should be large enough for a finger.Open in glossary →. The badge isn’t a separate target; the element it sits on is, and it needs at least 44×44 pt on iOS and 48×48 dp on Android. On the web, WCAG 2.5.8 (AA) asks for at least 24×24 CSS px; 44×44 px (2.5.5, AAA) is the comfortable target.
Mobile vs web
- Tab bar badges: red pill with white text by default.
Dev note
badgeValueonUITabBarItem(a string;"0"shows a zero) or.badge()in SwiftUI. - App icon badges need notification permission with badges. Test: allow, deny, and turning Badges off later in Settings › Notifications.
- Push payloads can set the icon badge. Check it’s correct after a push arrives while the app is closed, and that it clears when the app is opened and the items are read.
- Test with VoiceOver and the largest Dynamic Type size (long-press a tab bar item to see the large content viewer).
- Material 3 badges: a 6 dp dot or a 16 dp badge with up to four characters (“999+”).
Dev note
Badge/BadgedBox(Compose) orBadgeDrawable(Views). - App icons show notification dots on most launchers; the dot follows the app’s active notifications. Test dismissing notifications, and the Notification dot setting in system settings.
- Android 13+ asks for notification permission; without it there are no notifications and no dots (App permissions).
- Test with TalkBack, a large font size and display size, and on a narrow phone in landscape.
- Badges are usually custom
<span>s. Check the button’s accessible name in DevTools’ Accessibility pane: does it include the count? - The page title count (3) Inbox and installed web apps’ icon badges (where supported) must match the in-page badge.
Dev note
Icon badges are set withnavigator.setAppBadge(). - Test at 200% zoom and narrow viewports: header badges often overlap the logo or the next icon (Responsive design testing).
- Check realtime updates in two browser tabs: read in one, watch the other.
Check your understanding
Quick quiz
0/5 answered · 0 correct
1.All messages have been read. What should the Chats tab badge show?
2.There are 1,284 unread updates. What is the usual way to display that on a tab bar icon?
3.VoiceOver says "Chats, tab, 1 of 5" while the badge shows 3. What is wrong?
4.A shop marks sale items with a red dot and new items with a green dot. What do you report?
5.The badge drops only after restarting the app. Which test found it?
Key takeaways
- Three kinds: count badges, dot badges and status labels. Name them correctly in bug reports.
- Zero hides the badge, big numbers are capped (99+, 999+), and the badge stays inside its space without hiding the icon.
- The count is data: it must match the list, update immediately when items are read, and agree with the app icon badge.
- App icon badges belong to the OS: on iOS they need notification permission with badges; on Android they’re usually dots tied to active notifications.
- Accessibility: the count goes into the accessible name (“Chats, 3 unread”), status uses words, not only color, and contrast is checked in light and dark mode.
Finished this page?Nice work, this page is complete!
Mark it as done to track your progress. It's saved in this browser, no account needed.
Its review cards are now in Bites ⚡