A live status indicator for services and deploys: the dot blends between colours and pulses softly only when something needs attention.
Customize
Usage
import { StatusDot } from "@/components/motionkit/status-dot";
<StatusDot status="degraded" />Motion
The exact curves this component runs, plotted with Motion's own maths.
Colour change
Status changes
Pulse
Needs attention
Status pages, service lists in dashboards, deploy and build states, footers with an "All systems operational" link, and presence indicators.
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.
Works in the App Router as is. Requires Tailwind CSS v4.
One command adds the file and installs its dependencies. Needs a components.json (run npx shadcn@latest init once if you don't have one).
npx shadcn@latest add https://motionkitui.com/r/status-dot.jsonnpm install motionSave as components/motionkit/status-dot.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>
);
}
| 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. |
How we audit: the WCAG 2.2 animation checklist and respecting reduced motion in React.
Yes. The file starts with "use client", so you can import it straight into a Server Component page or layout. It works in Vite as is, and in Astro as a React island.
Only the motion package, beside React and Tailwind CSS v4. There is no MotionKit package and no Tailwind config to add.
Yes. Run npx shadcn@latest add https://motionkitui.com/r/status-dot.json in any project with a components.json. It saves the file to components/motionkit and installs its dependencies.
With reduced motion on, the pulse stops; operational never pulses at all.
Deploy Pipeline
Build, test and deploy steps run in turn with live timers and a filling line, ending on a pulsing Live badge or a clear failure with a retry.
Toast
Stacking notifications with swipe-to-dismiss, hover-to-pause and variants.
Stepper
Progress through steps: the line fills, and each finished step draws its own tick.