Data display
Status
A colored dot with a label for system and record states, with an optional live pulse and a pill appearance for tables.
npx prodular-ui add statusVariants
Plain for headers and lists, pill for table cells where it has to stand out from neighbouring text.
OperationalDegradedSyncingOutagePaused
PaidPast dueDeployingFailedDraft
import { Status } from "@/components/ui/status"
export default function StatusVariants() { return ( <div className="flex flex-col items-center gap-6"> <div className="flex flex-wrap items-center justify-center gap-x-6 gap-y-3"> <Status variant="success">Operational</Status> <Status variant="warning">Degraded</Status> <Status variant="info" pulse> Syncing </Status> <Status variant="destructive">Outage</Status> <Status variant="neutral">Paused</Status> </div> <div className="flex flex-wrap items-center justify-center gap-2"> <Status variant="success" appearance="pill"> Paid </Status> <Status variant="warning" appearance="pill"> Past due </Status> <Status variant="info" appearance="pill" pulse> Deploying </Status> <Status variant="destructive" appearance="pill"> Failed </Status> <Status variant="neutral" appearance="pill"> Draft </Status> </div> </div> )}System status
Live states pulse. The pulse is removed when the person prefers reduced motion.
Platform statusUpdated 2 minutes ago
Partial outage- REST APIus-east-199.99%Operational
- Webhooksus-east-199.71%Degraded
- DashboardGlobal100%Operational
- Data warehouse synceu-west-199.95%Syncing
- SMS notificationsGlobal98.40%Outage
import { Status } from "@/components/ui/status"
const components = [ { name: "REST API", region: "us-east-1", status: "success", label: "Operational", uptime: "99.99%" }, { name: "Webhooks", region: "us-east-1", status: "warning", label: "Degraded", uptime: "99.71%" }, { name: "Dashboard", region: "Global", status: "success", label: "Operational", uptime: "100%" }, { name: "Data warehouse sync", region: "eu-west-1", status: "info", label: "Syncing", uptime: "99.95%", pulse: true }, { name: "SMS notifications", region: "Global", status: "destructive", label: "Outage", uptime: "98.40%" },] as const
export default function StatusSystem() { return ( <div className="w-full max-w-lg rounded-xl border bg-card shadow-xs"> <div className="flex items-center justify-between gap-4 border-b px-4 py-3"> <div className="flex flex-col"> <span className="text-sm font-medium">Platform status</span> <span className="text-[13px] text-muted-foreground">Updated 2 minutes ago</span> </div> <Status variant="warning" appearance="pill"> Partial outage </Status> </div> <ul className="divide-y"> {components.map((c) => ( <li key={c.name} className="flex items-center gap-4 px-4 py-3"> <div className="flex min-w-0 flex-1 flex-col"> <span className="truncate text-sm text-foreground">{c.name}</span> <span className="text-[13px] text-muted-foreground">{c.region}</span> </div> <span className="hidden text-[13px] text-muted-foreground tabular-nums sm:inline">{c.uptime}</span> <Status variant={c.status} size="sm" pulse={"pulse" in c} className="w-24"> {c.label} </Status> </li> ))} </ul> </div> )}Anatomy
<Status variant="success">Operational</Status><Status variant="info" appearance="pill" pulse>Syncing</Status>Guidance
Use it when
- The state of a system, a sync, a deploy or a record: Operational, Degraded, Syncing, Paid, Failed.
- pulse for states that are actively changing right now: Syncing, Deploying, Live.
Avoid
- Color as the only signal. Always keep the label.
- Pulsing more than one or two items in a view. Motion stops meaning anything when everything moves.
- Badge for states. Badge is for counts and tags; Status is for state.
Rules for AI agents
Published in llms-full.txt and the registry, so coding agents follow them when they build with this component.
- Map states to variants consistently: success for healthy or done, warning for degraded or needs attention, destructive for failed or down, info for in progress, neutral for paused, draft or archived.
- Always pass a text label as children. Use StatusIndicator alone only next to text that already names the state.
- Use appearance="pill" inside data table cells and appearance="plain" in headers, lists and sentences.
- Use pulse only for live or in-progress states. It is motion-reduce safe; do not add your own animation.
- Use size="xs" on Status for dense toolbars and inspectors instead of overriding its height.
API
Status
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "success" | "warning" | "info" | "destructive" | "neutral" | "neutral" | Color of the dot, and of the tint for pills. |
| appearance | "plain" | "pill" | "plain" | plain is a dot and text. pill adds a tinted rounded background. |
| size | "default" | "sm" | "xs" | "default" | sm uses 13px text. |
| pulse | boolean | false | A soft ping around the dot. Hidden with prefers-reduced-motion. |
| indicator | boolean | true | Set false to place StatusIndicator yourself. |
StatusIndicator
| Prop | Type | Default | Description |
|---|---|---|---|
| variant / pulse | StatusVariant / boolean | The dot on its own, for filter options or next to text that already names the state. |