# Status Dot

> A live status indicator for services and deploys: the dot blends between colours and pulses softly only when something needs attention.

Category: Feedback · Free · Updated 2026-10-23 · Live demo: https://motionkitui.com/components/status-dot

## When to use it

Status pages, service lists in dashboards, deploy and build states, footers with an "All systems operational" link, and presence indicators.

## How it works

The dot animates its background colour, so moving from degraded to operational blends rather than jumps. Behind it, a second circle in the same colour scales up and fades out on a loop, which reads as a pulse; it's keyed to the status, so it restarts cleanly on each change, and it never runs for operational, because calm should look calm. The whole thing is a status region, so changes are announced, and the status is always written out in words as well as colour.

## Installation

```bash
npx shadcn@latest add https://motionkitui.com/r/status-dot.json
```

Or copy `components/motionkit/status-dot.tsx` below. Requires react, motion and Tailwind CSS v4.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `status` | `"operational" \| "degraded" \| "outage" \| "maintenance"` |  | The current status. |
| `label` | `string` |  | Text beside the dot. Defaults to a plain description of the status. |
| `dotOnly` | `boolean` | `false` | Show only the dot; the label is still announced. |
| `pulse` | `boolean` | `true` | Pulse while the status needs attention. |

## Accessibility

- **Keyboard: Not applicable.** Informational, nothing to focus.
- **Screen readers: Pass.** A status region, so a change such as "Major outage" is announced. The label stays available when only the dot shows.
- **Reduced motion: Pass.** With reduced motion on, the pulse stops; operational never pulses at all.
- **Colour contrast: Pass.** Labels measure 14.7:1, and the status is always spelt out in words as well as colour.

## Source

```tsx
"use client";

import { motion, useReducedMotion } from "motion/react";

type Status = "operational" | "degraded" | "outage" | "maintenance";

type StatusDotProps = {
  status: Status;
  /** Text beside the dot. Defaults to a plain description of the status. */
  label?: string;
  /** Show only the dot (the label is still announced). */
  dotOnly?: boolean;
  /** Pulse while the status needs attention; operational stays calm. */
  pulse?: boolean;
  className?: string;
};

// status colours from the brand: sage for good, clay for caution, rust for urgent, teal for planned work
const statuses: Record<Status, { color: string; text: string }> = {
  operational: { color: "#7D9E9D", text: "All systems operational" },
  degraded: { color: "#C9A26B", text: "Degraded performance" },
  outage: { color: "#C0603F", text: "Major outage" },
  maintenance: { color: "#5FAEB4", text: "Scheduled maintenance" },
};

/** A live status indicator: a dot that changes colour smoothly and pulses softly when something needs attention. */
export function StatusDot({ status, label, dotOnly = false, pulse = true, className = "" }: StatusDotProps) {
  const reduceMotion = useReducedMotion();
  const { color, text } = statuses[status];
  const pulsing = pulse && status !== "operational" && !reduceMotion;

  return (
    <span role="status" className={`inline-flex items-center gap-2 text-sm text-[#DCE3E2] ${className}`}>
      <span aria-hidden className="relative flex size-2.5">
        {pulsing && (
          <motion.span
            key={status}
            className="absolute inset-0 rounded-full"
            style={{ backgroundColor: color }}
            initial={{ scale: 1, opacity: 0.6 }}
            animate={{ scale: 2.6, opacity: 0 }}
            transition={{ duration: 1.6, repeat: Infinity, ease: "easeOut" }}
          />
        )}
        <motion.span className="relative size-2.5 rounded-full" initial={false} animate={{ backgroundColor: color }} transition={{ duration: 0.4 }} />
      </span>
      <span className={dotOnly ? "sr-only" : undefined}>{label ?? text}</span>
    </span>
  );
}
```
