Badge in Jetpack Compose:
Types, Use-Cases & Best Practices (2026)
π What is a Badge?
- Counts (notifications, cart items)
- Status (online, live)
- Attention signals (new content available)
What types of badges exist?
1. Numeric Badge – Shows a number (5, 99+)
2. Dot Badge – Small dot without text (attention indicator)
- New feature available
- Unread content exists
- Attention required (without exact count)
3.Status Badge – Shows state (Online, Offline) using color or short text.
- Profile avatars
- Chat apps
- Streaming apps
4. Label / Tag Badge – Short text (NEW, PRO, BETA)
Source Code:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BadgeDemoApp() {
var notificationCount by remember { mutableIntStateOf(3) }
var cartCount by remember { mutableIntStateOf(5) }
var isOnline by remember { mutableStateOf(true) }
Scaffold(
topBar = {
TopAppBar(
title = { Text("Badge Demo App") },
actions = {
// Numeric Badge (Notification)
BadgedBox(
badge = {
if (notificationCount > 0) {
Badge { Text("$notificationCount") }
}
}
) {
IconButton(onClick = { notificationCount++ }) {
Icon(Icons.Default.Notifications, null)
}
}
}
)
},
bottomBar = {
NavigationBar {
// Navigation Badge
NavigationBarItem(
selected = true,
onClick = {},
icon = {
BadgedBox(
badge = {
if (cartCount > 0) {
Badge { Text("$cartCount") }
}
}
) {
Icon(Icons.Default.ShoppingCart, null)
}
},
label = { Text("Cart") }
)
}
}
) { padding ->
Column(
modifier = Modifier
.padding(padding)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(24.dp)
) {
// 1. Dot Badge (New content)
Row(verticalAlignment = Alignment.CenterVertically) {
BadgedBox(badge = { Badge() }) {
Icon(Icons.Default.Email, null)
}
Spacer(Modifier.width(12.dp))
Text("Dot Badge – New Content")
}
// 2. Numeric Badge (Cart)
Row(verticalAlignment = Alignment.CenterVertically) {
BadgedBox(
badge = { Badge { Text("$cartCount") } }
) {
Icon(Icons.Default.ShoppingCart, null)
}
Spacer(Modifier.width(12.dp))
Button(onClick = { cartCount++ }) {
Text("Add Item")
}
}
// 3. Status Badge (Online / Offline)
Row(verticalAlignment = Alignment.CenterVertically) {
BadgedBox(
badge = {
Badge(
containerColor = if (isOnline) Color.Green else Color.Gray
)
}
) {
Icon(Icons.Default.Person, null)
}
Spacer(Modifier.width(12.dp))
Button(onClick = { isOnline = !isOnline }) {
Text(if (isOnline) "Go Offline" else "Go Online")
}
}
// 4. Icon Badge (Verified)
Row(verticalAlignment = Alignment.CenterVertically) {
BadgedBox(
badge = {
Badge(containerColor = Color.Blue) {
Icon(
Icons.Default.Check,
contentDescription = null,
modifier = Modifier.size(12.dp)
)
}
}
) {
Icon(Icons.Default.AccountCircle, null)
}
Spacer(Modifier.width(12.dp))
Text("Icon Badge – Verified")
}
// 5. Text Label Badge (NEW / PRO)
Row(verticalAlignment = Alignment.CenterVertically) {
BadgedBox(
badge = {
Badge(containerColor = Color.Red) {
Text("NEW", fontWeight = FontWeight.Bold)
}
}
) {
Icon(Icons.Default.Star, null)
}
Spacer(Modifier.width(12.dp))
Text("Text Label Badge")
}
// 6. Avatar Badge (Profile Status)
Row(verticalAlignment = Alignment.CenterVertically) {
BadgedBox(
badge = {
Badge(
containerColor = if (isOnline) Color.Green else Color.Gray,
modifier = Modifier.size(10.dp)
)
}
) {
Icon(
Icons.Default.Person,
contentDescription = null,
modifier = Modifier.size(48.dp)
)
}
Spacer(Modifier.width(12.dp))
Text("Avatar Status Badge")
}
// 7. Action Badge (Avoid – demo only)
Row(verticalAlignment = Alignment.CenterVertically) {
BadgedBox(
badge = {
Badge { Text("!") }
}
) {
IconButton(onClick = { /* avoid interaction in badge */ }) {
Icon(Icons.Default.Warning, null)
}
}
Spacer(Modifier.width(12.dp))
Text("Action Badge (Not Recommended)")
}
}
}
}OUTPUT:
Can a badge be clickable?
- No. Badges are informational only.
- If you want interaction, wrap the icon in a Clickable or IconButton and update the badge dynamically.
Why Badges Matter in Real Apps
- Badges improve UX by:
- Reducing unnecessary navigation
- Showing important updates instantly
- Keeping UI clean and minimal
π± Real-world examples:
How do I create a Badge?
BadgedBox(badge = { Badge { Text("3") } }) {
Icon(Icons.Default.Notifications, contentDescription = "Notifications")
}
- Wrap your main content in BadgedBox.
- Pass a Badge as the badge parameter.
How do I update a Badge dynamically?
var count by remember { mutableStateOf(1) }
BadgedBox(badge = { if (count > 0) Badge { Text("$count") } }) {
IconButton(onClick = { count++ }) {
Icon(Icons.Default.Notifications, contentDescription = null)
}
}Can I customize badge color or size?
Badge(
containerColor = Color.Red,
contentColor = Color.White
) {
Text("99+")
}- containerColor → background
- contentColor → text or icon color
If user can click → Chip
If just showing info → Badge
Real App Examples
- WhatsApp → unread messages count
- Instagram → story dot
- Gmail → new email count
- Amazon → cart item count
Common mistakes with Badge
- Using badges for long text or paragraphs
- Making badges interactive
- Ignoring state updates → UI won’t reflect counts
When NOT to Use Badge
- For user input
- For long descriptions
- For main content
- For interactive actions
In short
| Badge Type | Shows | Best Use |
|---|---|---|
| Numeric | Count | Notifications |
| Dot | Attention | New content |
| Status | State | Online / Live |
| Icon | Symbol | Verified / Error |
| Text Label | Tag | NEW / PRO |
| Navigation | Count / Dot | Tabs / BottomBar |
| Avatar | Status / Icon | Profile state |
| Action | Clickable | Rare (avoid) |
π Our Final Thoughts
- Improve clarity
- Reduce user effort
- Make apps feel polished and professional

