Indicator
Pins a small thing — an unread count, a status dot, a "NEW" ribbon — to the corner of any target: a bell icon, an avatar, a card, a button.
It exists so you stop hand-rolling absolute positioning with negative corner
offsets on every one of them. That pattern is exactly the raw-div scaffolding a
component library is supposed to replace — and it silently breaks in RTL.
The indicator is as wide as its target in any container, a stack and a grid
included, so the badge stays on the target's corner. To have it fill its
container together with a target that does, such as a card in a grid cell, give
both of them class="w-full".
Basic Usage
Corners
position is logical: end is the right corner in LTR and the left
corner in RTL, so the badge follows the reading direction on its own.
Offset
By default the badge is centered on the corner. offset nudges it further out.
Naming the badge
The badge must say what it means. A bare "3" next to a bell tells a screen-reader user nothing.
{{-- 1. A count: name it, and hide the raw number from assistive tech --}}
<x-wirekit::indicator>
<x-wirekit::button aria-label="Notifications">
<x-wirekit::icon name="bell" size="md" />
</x-wirekit::button>
<x-slot:badge>
<x-wirekit::badge intent="danger" size="sm">
<span aria-hidden="true">{{ $unread }}</span>
<span class="sr-only">{{ $unread }} unread notifications</span>
</x-wirekit::badge>
</x-slot:badge>
</x-wirekit::indicator>
{{-- 2. A purely decorative presence dot: without a label it hides itself, so say it elsewhere --}}
<x-wirekit::indicator position="bottom-end">
<x-wirekit::avatar :alt="$user->name" />
<x-slot:badge>
<x-wirekit::status-dot intent="success" size="lg" />
</x-slot:badge>
</x-wirekit::indicator>
<span class="sr-only">{{ $user->name }} is online</span>
Props
| Prop | Type | Default | Description |
|---|---|---|---|
position |
string | 'top-end' |
top-end, top-start, bottom-end, bottom-start — logical, so end follows the reading direction |
offset |
string|null | null |
Nudge the badge further out (any CSS length); default centers it on the corner |
scope |
string|null | null |
Scoped personalization name |
Slots
| Slot | Description |
|---|---|
| default | The target being decorated |
badge |
The thing anchored to the corner |
Accessibility
- The badge carries its own meaning. Indicator only positions it. A count
needs a real name (
3 unread notifications), and a decorative dot needsaria-hiddenplus the state stated elsewhere — see the examples above. - The badge is
pointer-events: none, so it never swallows a click meant for the target underneath. Anything genuinely interactive inside it (a link, a button) gets pointer events back automatically. - The badge is out of flow, so decorating a target never resizes it — no layout shift, no touch target shrinking.
- RTL is automatic: placement uses logical insets, so
endmoves to the left corner underdir="rtl"with no extra rules.
Keyboard Interaction
This component is presentational and does not respond to keyboard input. The target and any control inside the badge keep their own keyboard behavior.
Pitfalls
- Do not leave a bare number as the whole badge. "3" is not an accessible name — say "3 unread notifications".
- Do not put your main action in the badge. It is a decoration on the target, not a second control competing for the same corner.
- Do not hand-roll the absolute-corner-offset pattern. That is what this replaces — and it does not mirror in RTL.
Design Tokens
| Element | Token |
|---|---|
| Corner nudge | --indicator-wk-offset (default 0px) |
The badge's own colors and shape come from whatever you place in the slot — usually Badge.