Skip to content
Protocore Design Systemv1.6.9

/// Data Display

Indicator

Wraps a child and pins a tone-coloured dot or count badge to a corner, with an optional live pulse.

import { Indicator } from "@protocore/pds";
View as Markdown

Dot

Wrap any element — an avatar, an icon button, a nav item — and Indicator pins a small sharp dot to a corner. With no count or label it's a bare presence dot: something is new here.

ALGHAT

Count & overflow

Pass a count to render a number badge. Counts above max (default 99) collapse to {max}+. A count of 0 hides the badge unless you set showZero. Because the overlay is decorative, carry the meaning in an aria-label ("7 unread") so it's announced.

799+

Processing pulse

Add processing to emit a soft expanding ring — a genuinely live signal for a syncing avatar or a running job. Reserve it for real-time state; the animation respects the platform's reduced-motion preference.

SJ

Reindexing the ledger — live

When to use it

Indicator is for an overlay on something else — a badge riding the corner of an avatar or icon button. When the status stands on its own line, use a Badge (a word) or a StatusDot (a dot beside a label) instead; both are cheaper and more legible than an overlay.

The overlay is decorative by design — it never carries an accessible name unless you give it one. Put the real meaning in the wrapped control's label ("Notifications, 7 unread") or pass aria-label on the Indicator. Position uses logical corners (top-end, bottom-start…) so it mirrors correctly under RTL.

Usage

Do

  • Convey the count in the child's accessible name or the `aria-label`.
  • Use `processing` only for live or streaming state.
  • Keep `withBorder` on when the overlay sits over a busy child.

Don't

  • Pair the colored overlay with a label; color alone doesn't convey status.
  • For a standalone count, use a Badge.
  • Use the ring for live signals, not static counts.

Accessibility

  • The overlay is `aria-hidden` decoration by default; give it an `aria-label` to promote it to an announced `role="status"`.
  • Best practice is to keep the count in the wrapped control's own accessible name so it's read as one thing.
  • The processing pulse is decorative and honours `prefers-reduced-motion` (it settles to its final frame).
  • Corners are logical (start/end), so the overlay flips to the correct side under `dir="rtl"`.

Indicator props

PropTypeDefaultDescription
aria-labelstringAccessible label for the overlay itself; when set it becomes `role="status"`.
childrenReactNodeThe element the overlay decorates.
classNamestring
countnumberNumeric count. Renders inside the badge; `0` hides unless `showZero`.
disabledbooleanfalseHide the overlay entirely (keeps the child mounted).
labelReactNodeArbitrary label content (a string/number) — an alternative to `count`.
maxnumber99Cap the count; larger values render as `{max}+`.
positionenumtop-endCorner the overlay pins to.
processingbooleanfalseSoftly pulse the overlay to signal a live/processing state.
showZerobooleanfalseShow the badge when `count` is `0`.
sizeenummdOverlay size: sm 8 · md 10 · lg 12 (dot); grows to fit a label.
styleCSSProperties
toneenumdangerOverlay tone.
withBorderbooleantrueDraw a canvas-coloured ring so the overlay reads clearly over the child.

Related

  • BadgeA static, sentence-case status indicator with a tone-tinted fill — never interactive, never color-only.
  • StatusDotA small sharp square that encodes a status tone, with an optional live pulse.
  • ThemeIconAn icon in a sized, sharp square container with a filled / light / outline / ghost treatment.
  • AvatarSquare user image with a mono-initials fallback.