Indicator
A dot or a count pinned to a corner of an icon button, an avatar or anything else.
- Click the bell: the count drops to zero and the indicator shrinks away. Send a notification brings it back.
- A count above
maxshows asmax+: with the default of 99, the inbox's 128 reads 99+. - On the round avatar,
shape="circle"moves the dot in from the corner onto the rim; on the square deploy tiles it stays on the corner.
Field marks
- Import
import { Indicator } from "cennge-ui";- Size
- 1.1 KB gzip for this import, its dependencies aside
- Pattern
- A
<span>around your element; hidden from screen readers unless you passlabel - State
- None: pass
content, andisInvisibleto hide it - SSR
- Rendered on the server in the Next.js check; hydrates without a warning
- Outline
- A 2 px ring in the page colour parts it from the element under it
- Tests
- Unit tests
- Source
- src/components/indicator
When to use#
Use an Indicator to flag something about one control: unread notifications on a bell, a person's status on their avatar, a new entry on a tab. It sits on the corner without taking space, so the layout around the control does not change when the count appears or goes.
Similar#
- Badge is a label in the flow of the text, with room for words; an Indicator is pinned on top of another element.
- Avatar is often what the Indicator sits on; status dots belong on the avatar, not beside it.
Counts and dots#
content takes a number or a short word. Numbers above max show as max+. Without content it is a plain dot, sized by size. The colour is danger unless you choose another.
import { Button, Indicator } from "cennge-ui";
export default function IndicatorCounts() {
return (
<div className="flex flex-wrap items-center gap-8">
<Indicator content={4} label="4 open pull requests">
<Button variant="flat">Pull requests</Button>
</Indicator>
<Indicator content={12} max={9} color="warning" label="12 failing checks">
<Button variant="flat">Checks</Button>
</Indicator>
<Indicator content="new" color="primary" size="lg" label="New release">
<Button variant="flat">Releases</Button>
</Indicator>
<Indicator color="info" size="sm" label="Unread changes">
<Button variant="flat">Changelog</Button>
</Indicator>
</div>
);
}Status on an avatar#
On a circle the corner of the box is empty space. shape="circle" moves the indicator onto the rim; placement picks the corner. Write the status beside the avatar as well, as here, so it does not rest on colour alone.
- ALAnn LeeOnline
- MHMax HartAway
- ICIra ColeBusy
import { Avatar, Indicator, type CenngeColor } from "cennge-ui";
const people: { name: string; status: string; color: CenngeColor }[] = [
{ name: "Ann Lee", status: "Online", color: "success" },
{ name: "Max Hart", status: "Away", color: "warning" },
{ name: "Ira Cole", status: "Busy", color: "danger" },
];
export default function AvatarStatus() {
return (
<ul className="flex flex-wrap gap-x-8 gap-y-4">
{people.map((person) => (
<li key={person.name} className="flex items-center gap-3">
{/* The status is written beside the avatar, so the dot needs no label of its own. */}
<Indicator color={person.color} shape="circle" placement="bottom-right" size="lg">
<Avatar name={person.name} size="lg" />
</Indicator>
<span className="flex flex-col text-sm">
<span className="font-medium">{person.name}</span>
<span className="text-muted">{person.status}</span>
</span>
</li>
))}
</ul>
);
}Accessibility#
An Indicator is decorative until you give it a label: then screen readers read the label, "3 unread notifications", instead of a bare "3". While isInvisible is on, the label is not read either. Keep the name of the control itself, such as "Notifications", on the control.
Styling#
The ring that parts the indicator from what it sits on is ring-background, the page colour. On a panel or a card, pass the panel's colour in className, such as ring-surface-3, as the bar on the plate does; showOutline={false} removes the ring.
Props#
Also takes every attribute of <span>, except content, color, which mean something else here.