Skip to content

Badge

A hint red dot mirroring ColorOS's COUIHintRedDot, with three forms: a plain 6dp dot, a 16dp-high number capsule that widens with the digit count, and a three-dot ellipsis for counts of 1000 and above. BadgeBox anchors a badge at the top end corner of an icon like COUIRedDotFrameLayout.

Import

kotlin
import io.github.suqi8.coui.kmp.basic.Badge
import io.github.suqi8.coui.kmp.basic.BadgeBox
import io.github.suqi8.coui.kmp.basic.BadgeDefaults

Basic Usage

kotlin
Badge()                // plain dot
Badge(count = 8)       // number capsule
Badge(count = 1000)    // three-dot ellipsis (1000+)
Badge(stroke = true)   // white outline for colored surfaces

Badge Forms

Dot Badge

Counts of 0 or below (the default) render a plain 6dp dot (COUI POINT_ONLY_MODE):

kotlin
Badge()

Count Badge

Counts from 1 to 999 render a 16dp-high capsule that widens with the digit count (16dp under 10, 20dp under 100, 26dp under 1000). Count changes ease the capsule width over 517ms while the old and new numbers crossfade over 150ms:

kotlin
var unread by remember { mutableIntStateOf(8) }

Badge(count = unread)

Overflow Ellipsis

Counts of 1000 and above render a 20dp-wide capsule with a three-dot ellipsis (COUI red_dot_more):

kotlin
Badge(count = 1000)

Stroke Outline

stroke = true draws a 1dp white outline around the dot or capsule, for badges placed on colored surfaces (COUI POINT_ONLY_MODE_STROKE / POINT_NUM_MODE_STROKE):

kotlin
Badge(stroke = true)              // dot with outline
Badge(count = 99, stroke = true)  // capsule with outline

Anchoring with BadgeBox

BadgeBox anchors a badge at the top end corner of its content. A positive overhang lets the badge stick out of the corner by that amount and grows the layout accordingly (COUI rectangular anchors such as icons):

kotlin
BadgeBox(
    badge = { Badge(count = 8) },
    overhang = BadgeDefaults.CountOverhang,
) {
    Icon(
        imageVector = COUIIcons.Settings,
        contentDescription = "Settings",
    )
}

A negative overhang insets the badge inside the corner instead (COUI circular anchors such as avatars):

kotlin
BadgeBox(
    badge = { Badge() },
    overhang = (-2).dp,
) {
    Image(
        painter = avatarPainter,
        contentDescription = "Avatar",
        modifier = Modifier.size(40.dp).clip(CircleShape),
    )
}

Properties

Badge

PropertyTypeDescriptionDefault ValueRequired
modifierModifierModifier applied to the badgeModifierNo
countIntNumber shown in the badge; values <= 0 show a dot0No
strokeBooleanWhether to draw a white outlinefalseNo
colorsBadgeColorsColor configurationBadgeDefaults.badgeColors()No
dotDiameterDpDiameter of the plain dot formBadgeDefaults.DotDiameterNo
heightDpHeight of the number capsule formBadgeDefaults.HeightNo

BadgeBox

PropertyTypeDescriptionDefault ValueRequired
badge@Composable () -> UnitThe badge to anchor-Yes
modifierModifierModifier applied to the layoutModifierNo
overhangDpHow far the badge extends beyond the top end cornerBadgeDefaults.DotOverhangNo
content@Composable () -> UnitThe anchor content, typically an icon-Yes

BadgeDefaults

ConstantTypeDefault Value
DotDiameterDp6.dp
HeightDp16.dp
SmallWidthDp16.dp
MediumWidthDp20.dp
LargeWidthDp26.dp
TextSizeDp10.dp
StrokeWidthDp1.dp
EllipsisDotDiameterDp2.dp
EllipsisSpacingDp2.dp
DotOverhangDp2.dp
CountOverhangDp3.dp
ScaleAnimDurationMillisInt520

badgeColors() factory

ParameterTypeDefault
containerColorColorCOUI additional red (#EB3B2F in light themes, #EB493D in dark)
contentColorColorColor.White
strokeColorColorColor.White

Behavior

  • count <= 0 shows the plain dot; 1..9 a 16dp capsule, 10..99 a 20dp capsule, 100..999 a 26dp capsule; 1000 and above a 20dp capsule with a three-dot ellipsis (COUI red_dot_more).
  • Count changes animate like COUIHintRedDot: the capsule width eases over 517ms (COUIMoveEaseInterpolator) while the old and new numbers crossfade over 150ms.
  • The count text renders at a density-scaled 10dp (sans-serif medium), ignoring the user font scale like the original.
  • stroke = true draws a 1dp white outline; the dot form shrinks its red core by the stroke width, the capsule form insets the red fill inside the white outline.
  • A positive BadgeBox overhang lets the badge stick out beyond the content's top end corner and grows the layout accordingly (COUI rectangular anchors); a negative overhang insets the badge inside the corner (COUI circular anchors such as avatars).
  • To animate badge visibility like COUIHintRedDot's show / hide scale animation, wrap it in AnimatedVisibility with scaleIn / scaleOut over BadgeDefaults.ScaleAnimDurationMillis.

Changelog

Released under the Apache-2.0 License