Status Indicator
A richer companion to Status Dot. Where Status Dot is a tiny inline glyph for use mid-sentence, Status Indicator pairs a colored dot with a prominent label sized for dashboards, user lists, and system-status panels. Six operational statuses, three sizes, and an optional pulse halo for live signals.
Online
Offline
Idle
Busy
Degraded
Maintenance
Customize
Status & size
online
md
Pulse & label
pulse
Installation
npx shadcn@latest add https://craftbits.dev/r/status-indicator.jsonUsage
import { StatusIndicator } from "@craft-bits/core";
<StatusIndicator status="online" label="Online" pulse="pulse" />A live, pulsing indicator on one line; a calm "offline" row on the next:
<StatusIndicator status="offline" label="Offline" />
<StatusIndicator status="maintenance" label="Scheduled maintenance" size="lg" />The label is optional — drop it and you get just a sized dot:
<StatusIndicator status="busy" aria-label="Busy" />Understanding the component
- Status-driven palette.
statusselects six operational colors:online(success),offline(muted),idle(warning),busy(error),degraded(warning), andmaintenance(accent). The label inherits the dot color so the eye reads dot and word as one signal. - Three sizes.
size="sm"for inline rows,"md"(default) for table cells and lists,"lg"for hero status displays. The dot diameter, gap, and label font scale together so the proportions stay consistent. - Pulse via CSS, not JS. The
@keyframes cb-status-indicator-pulserule is injected once into<head>the first time a pulsing indicator mounts. It's wrapped in@media (prefers-reduced-motion: no-preference)so reduced-motion users see a static dot automatically — no JS branch. - Pulse modes.
pulse="static"(default) paints a solid dot.pulse="pulse"layers an outward-fading halo on top — reserve it for genuinely live signals.pulse="none"hides the dot entirely so a consumer can rebuild the row with its own glyph while keeping the typography. - Sized for chip use.
align-middlekeeps the indicator optically centered against surrounding text;select-noneprevents accidental highlighting when users drag-select rows in a dashboard.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
status | 'online' | 'offline' | 'idle' | 'busy' | 'degraded' | 'maintenance' | required | Operational status — drives dot and label color. |
label | ReactNode | — | Optional text rendered after the dot. When omitted, only the dot renders. |
pulse | 'none' | 'static' | 'pulse' | 'static' | Dot mode. pulse adds a halo that respects prefers-reduced-motion. |
size | 'sm' | 'md' | 'lg' | 'md' | Indicator size — drives dot diameter, gap, and label scale. |
className | string | — | Merged onto the rendered root <div>. |
...rest | HTMLAttributes<HTMLDivElement> | — | Any other div prop (aria-*, data-*, onClick, …). |
Accessibility
- The indicator renders a single
<div>containing the visible label — screen readers announce the label as-is. The dot is markedaria-hidden="true"so assistive tech reads only the label. - For dynamic status updates, wrap the indicator in an element with
role="status"oraria-live="polite"so changes are announced. - When used without a label, supply
aria-labelso the indicator has an accessible name — otherwise it's invisible to assistive tech. - The pulse animation is automatically disabled when
prefers-reduced-motion: reduceis set — the rule is scoped under@media (prefers-reduced-motion: no-preference). Reduced-motion users see a static dot identical topulse="static".
Credits
- Extracted from:
terminal-dreams(src/components/principles/demo-primitives/StatusDot.tsx). Generalized into a richer "indicator" variant distinct from the existing<StatusDot>primitive — operational status names, prominent label typography, and three sizes designed for dashboards rather than inline-with-text use.