Indicator

A dot or count pinned to the corner of an avatar, icon or button, such as unread messages or someone’s status.
Beta
Web
iOS
Android
@advui/core
Source
Online
JSX
<Indicator label="Online">
  <Avatar shape="square" alt="Ada Lovelace" />
</Indicator>
tone
size
placement
overlap

Installation

pnpm
pnpm add @advui/core
npm
npm install @advui/core

Usage

import { Indicator } from '@advui/core'

<Indicator tone="success" placement="bottom-end" overlap="circle" label="Online">
  <Avatar src={user.photoUrl} alt={user.name} />
</Indicator>

<IconButton
  aria-label="Notifications, 3 unread"
  icon={
    <Indicator count={3} size="sm">
      <BellIcon />
    </Indicator>
  }
/>

Examples

Who is online

Each avatar reads as its name, then “Online”. Sam is offline: no dot.
OnlineOnlineOnline

Counts on icon buttons

Each count is in its button’s name. Press Notifications to mark them read; Messages stops at 9+.

API reference

Indicator

Wraps what it is pinned to and keeps its place in the layout. Takes View props, such as a margin.
PropTypeDefaultDescription
children requiredReactNode—What it is pinned to: an avatar, an icon or a button.
countnumber—A number to show. Without it the indicator is a dot.
maxnumber99Counts above it show as `99+`.
showZerobooleanfalseShow a count of 0, which otherwise hides the indicator.
labelstring—What screen readers read, such as “3 unread messages” or “Online”. Leave it out when the name of what it is pinned to already says it.
visiblebooleantrueFalse hides the indicator and keeps the children in place.
tone'primary' | 'success' | 'warning' | 'error''primary'Fill color. Counts use the matching foreground.
size'sm' | 'md''md'Dots of 8 or 10px and counts 16 or 20px tall, inside a 2px ring.
placement'top-end' | 'top-start' | 'bottom-end' | 'bottom-start''top-end'The corner it is centered on. `end` is the right.
overlap'circle' | 'square''square'The shape of what it is pinned to. `circle` moves it in to the circle’s edge, for round avatars.

Accessibility

  • The dot or count is hidden from screen readers, so “99+” is never read. label is read instead, as hidden text after the children: an avatar reads as its name, then “Online”.
  • On a button, put the count in the button’s name (aria-label="Notifications, 3 unread") and leave out label: the name replaces everything inside the button.
  • Color alone does not say what a dot means (WCAG 1.4.1). A dot that is there or not, such as Online, is fine; when tones tell statuses apart, show the status as text too.
  • A new count is not announced. When it needs attention, show a toast, or call AccessibilityInfo.announceForAccessibility on iOS and Android.
  • The mark takes no presses or clicks, so it never blocks the corner of a button.

Platform notes

Web
Spans throughout, so it fits inside buttons and links. The mark is centered on a zero-size point at the corner by flex layout, with no transform.
iOS
The same layout through Yoga. The label is a separate VoiceOver stop after the child.
Android
Same as iOS; the label keeps a trace of opacity, so TalkBack finds it. With androidRipple a button clips its content for the ripple, so keep counts on its icon short with max.
Since v0.14.0Last updated Nov 2, 2026Edit this page on GitHub