Badge
A count or a status dot, usually put on another element with PantrixBadgedBox.
import com.pantrixui.components.elements.badge.PantrixBadge
- A count or a dot. With a
countthe badge is a pill that writes the number; without one, a dot. A number of one digit sits in a circle. - A count that overflows. A number above
maxCountis written "99+", and the pill stops growing there. - Zero is a count too. Zero is drawn as "0": taking the badge away when there is nothing left to count is the caller's to do. A number below zero is drawn as "0" as well.
- Six tones.
tonefills the badge from one of the theme's roles;colorsgives a colour that no role has. - On the corner of something.
PantrixBadgedBoxsets the badge on a corner of its content; on round content it sets it on the circle, not on the box (BadgeOverlap.Circular). - Font scale. The number is set in the theme's
captionstyle and grows with the system's text size, and the pill with it.
Examples
Dot and count
Without a count the badge is a dot; with one it is a pill that grows wider with its number. A number of one digit is a full circle, and the pill is never narrower than it is tall.
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
verticalAlignment = Alignment.CenterVertically
) {
PantrixBadge()
PantrixBadge(count = 3)
PantrixBadge(count = 12)
PantrixBadge(count = 128)
}
A count that overflows
A number above maxCount is not written; the limit and a plus are written in its place: the default limit is 99. The pill stops growing there, and does not cover the icon it sits on. The last badge's limit is 9.
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
verticalAlignment = Alignment.CenterVertically
) {
PantrixBadge(count = 99)
PantrixBadge(count = 100)
PantrixBadge(count = 2500)
PantrixBadge(count = 12, maxCount = 9)
}
Tones
tone fills the badge with the colour of one of the theme's roles, and writes the number in the colour that reads on it. The default tone is Danger: a badge mostly tells of something that needs looking at. The top row has a number in every tone, and the one under it a dot in every tone.
FlowRow(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
verticalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm),
itemVerticalAlignment = Alignment.CenterVertically
) {
BadgeTone.entries.forEachIndexed { index, tone ->
PantrixBadge(count = TONE_COUNTS[index], tone = tone, tagKey = "tone_${tone.name}")
}
}
Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md)) {
BadgeTone.entries.forEach { tone -> PantrixBadge(tone = tone) }
}
private val TONE_COUNTS = listOf(1, 12, 5, 8, 120, 0)
On the corner of an icon
PantrixBadgedBox sets the badge on a corner of its content: by default the top corner on the side where lines end.
The badge is hidden from screen readers; the icon's own description says the number ("Inbox, 5 unread"). When the number gets down to zero no badge is put there at all: it is the caller that does this, not the badge. Raise the number with the buttons: past 99 it reads "99+", and the pill grows away from the icon.
var unread by rememberSaveable { mutableIntStateOf(START_UNREAD) }
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.lg),
verticalAlignment = Alignment.CenterVertically
) {
PantrixBadgedBox(badge = { if (unread > 0) PantrixBadge(count = unread, tagKey = "unread") }) {
PantrixIcon(
imageVector = PantrixIcons.Inbox,
contentDescription = if (unread > 0) "Inbox, $unread unread" else "Inbox",
tagKey = "inbox"
)
}
PantrixButton(
text = "+1",
onClick = { unread += 1 },
variant = ButtonVariant.Outline,
size = ButtonSize.Small,
tagKey = "one_more"
)
PantrixButton(
text = "+50",
onClick = { unread += MANY },
variant = ButtonVariant.Outline,
size = ButtonSize.Small,
tagKey = "many_more"
)
PantrixButton(
text = "Mark as read",
onClick = { unread = 0 },
variant = ButtonVariant.Text,
size = ButtonSize.Small,
tagKey = "read"
)
}
private const val START_UNREAD = 5
private const val MANY = 50
On avatars
On round content the badge stands on the circle, not on the corner of the box: overlap = BadgeOverlap.Circular. alignment says which corner; the status dot is at the bottom, on the side where lines end.
The status dots are made larger with BadgeStyle(dotSize = 12.dp): large enough to be made out on an avatar. The avatar's description says what the dot means ("İbrahim Öztürk, online"); the dot is hidden from screen readers.
val statusDot = BadgeStyle(dotSize = 12.dp)
Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.xl)) {
PantrixBadgedBox(
badge = { PantrixBadge(count = 2, tagKey = "messages") },
overlap = BadgeOverlap.Circular
) {
PantrixAvatar(contentDescription = "Ayşe Yılmaz, 2 new messages", initials = "AY", tagKey = "badged_ayse")
}
PantrixBadgedBox(
badge = { PantrixBadge(tone = BadgeTone.Success, style = statusDot, tagKey = "online") },
alignment = Alignment.BottomEnd,
overlap = BadgeOverlap.Circular
) {
PantrixAvatar(
contentDescription = "İbrahim Öztürk, online",
initials = "İÖ",
tone = AvatarTone.Info,
tagKey = "badged_ibrahim"
)
}
PantrixBadgedBox(
badge = { PantrixBadge(tone = BadgeTone.Neutral, style = statusDot, tagKey = "offline") },
alignment = Alignment.BottomEnd,
overlap = BadgeOverlap.Circular
) {
PantrixAvatar(
contentDescription = "ilker kaya, offline",
initials = "ik",
tone = AvatarTone.Success,
tagKey = "badged_ilker"
)
}
PantrixBadgedBox(
badge = { PantrixBadge(count = MANY * 3, tagKey = "team") },
overlap = BadgeOverlap.Circular
) {
PantrixAvatar(
contentDescription = "Team, more than 99 new messages",
icon = PantrixIcons.Person,
tone = AvatarTone.Primary,
tagKey = "badged_team"
)
}
}
private const val MANY = 50
A colour and a description of its own
colors gives the badge a fill of the given colour, not of a tone: here the app's own purple, which is in none of the theme's roles. Only the fields that are set change; the tone still decides the rest.
These badges stand alone, not on an icon. So they say what they mean themselves: each is given a contentDescription, and a screen reader reads "4 new offers".
val own = ownColors()
Row(
horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.md),
verticalAlignment = Alignment.CenterVertically
) {
PantrixBadge(count = 3, contentDescription = "3 new notifications", tagKey = "described")
PantrixBadge(
count = 4,
colors = BadgeColors(container = own.color, content = own.onColor),
contentDescription = "4 new offers",
tagKey = "own_colors"
)
}
Beside a text
A badge can stand on a text too. PantrixBadgedBox keeps the baseline of its content: with alignByBaseline the "new" label stands on the same line as the title beside it, and the dot on the label's corner.
Row(horizontalArrangement = Arrangement.spacedBy(PantrixTheme.spacing.sm)) {
PantrixText(
text = "Campaigns",
modifier = Modifier.alignByBaseline(),
style = PantrixTheme.typography.callout
)
PantrixBadgedBox(
badge = { PantrixBadge(tone = BadgeTone.Primary, tagKey = "new") },
modifier = Modifier.alignByBaseline()
) {
PantrixText(text = "new", style = PantrixTheme.typography.footnote)
}
}
API
modifier
A count or a status dot, usually put on another element with PantrixBadgedBox.
| Parameter | Type | Default | What it is |
|---|---|---|---|
modifier | Modifier | Modifier | the badge's modifier. |
count | Int? | null | the number to show, or null for a dot. |
maxCount | Int | 99 | the largest number that is written out. It has to be positive. |
tone | BadgeTone | BadgeTone.Danger | the colour role the badge is filled from. |
colors | BadgeColors? | null | this badge's own colours, in place of its tone's: the ones it sets, with the tone's for the rest. |
style | BadgeStyle? | null | this call's own style: over every enclosing one and under the density. Only the fields it sets change, on every platform. |
contentDescription | String? | null | what a screen reader says for the badge, or null to hide the badge from it. |
tagKey | String? | null | the badge's automation key: it is Badge_<tagKey>, and is tagged only when given one. |
BadgeStyle
PantrixBadge's geometry: a dot where there is nothing to count, and otherwise a pill that grows with its number.
| Parameter | Type | Default | What it is |
|---|---|---|---|
dotSize | Dp | Dp.Unspecified | The dot's width and height. |
height | Dp | Dp.Unspecified | The pill's height. A number set larger than it has room for, at a large font scale, makes the pill taller. |
minWidth | Dp | Dp.Unspecified | The pill's least width. The pill is never narrower than it is tall, whatever this says. |
horizontalPadding | Dp | Dp.Unspecified | The room on each side of the number, which is what makes the pill wider than it is tall as the number grows. |
BadgeColors
What PantrixBadge is painted with, for a badge that does not take its tone's colours: a colour that is set is used, and one that is left out stays the tone's.
| Parameter | Type | Default | What it is |
|---|---|---|---|
container | Color | Color.Unspecified | The badge's fill, and the whole of a dot. The color of the tone's role. |
content | Color | Color.Unspecified | The number: the colour that reads on container. The onColor of the tone's role. |
Accessibility
- Screen reader. Without a
contentDescriptionthe badge is hidden from screen readers: a lone "3" read out says nothing, and the number is said by the description of the element the badge sits on.