# Badge Status Pulse — React Badge Component

> Status badges with a live dot per state: a calm sonar ring for healthy, a breathing glow for degraded, urgent double rings for down and an orbiting arc for deploying.

- Category: [Badges](https://pixelpapa.com/components/badges.md)
- Tags: badge, status, pulse, live, indicator
- Dependencies: none (plus React and Tailwind CSS v4)
- Last updated: 2026-11-13
- Live preview: https://pixelpapa.com/components/badges/badge-status-pulse

## Install

```bash
npx shadcn@latest add "https://pixelpapa.com/r/badge-status-pulse.json"
```

The file is written to `components/pixelpapa/badge-status-pulse.tsx`. To install manually, copy the source below into your project. It imports `cn` from `@/lib/utils`, which every shadcn project has.

## Source

```tsx
"use client";

import type { ReactNode } from "react";
import { cn } from "@/lib/utils";

type Status = "live" | "degraded" | "down" | "deploying" | "idle";

type StatusBadgeProps = {
  status: Status;
  children: ReactNode;
  /** Render only the dot and label, without the pill. */
  bare?: boolean;
  className?: string;
};

const tones: Record<Status, { pill: string; text: string; dot: string }> = {
  live: { pill: "border-emerald-500/25 bg-emerald-500/10", text: "text-emerald-700 dark:text-emerald-300", dot: "bg-emerald-500" },
  degraded: { pill: "border-amber-500/30 bg-amber-500/10", text: "text-amber-700 dark:text-amber-300", dot: "bg-amber-500" },
  down: { pill: "border-rose-500/30 bg-rose-500/10", text: "text-rose-700 dark:text-rose-300", dot: "bg-rose-500" },
  deploying: { pill: "border-primary/25 bg-primary/10", text: "text-primary", dot: "bg-primary" },
  idle: { pill: "border-border bg-muted", text: "text-muted-foreground", dot: "bg-muted-foreground" },
};

const ring = "absolute inset-0 rounded-full motion-reduce:hidden";

export function StatusDot({ status, className }: { status: Status; className?: string }) {
  const dot = tones[status].dot;
  return (
    <span aria-hidden className={cn("relative flex size-2 shrink-0", className)}>
      <style>{`
        @keyframes pp-badge-status-pulse-sonar { 0% { transform: scale(1); opacity: .7; } 80%, 100% { transform: scale(2.8); opacity: 0; } }
        @keyframes pp-badge-status-pulse-breathe { 0%, 100% { transform: scale(1.2); opacity: .15; } 50% { transform: scale(2.3); opacity: .45; } }
        @keyframes pp-badge-status-pulse-orbit { to { transform: rotate(360deg); } }
      `}</style>
      {status === "live" && <span className={cn(ring, dot)} style={{ animation: "pp-badge-status-pulse-sonar 2s ease-out infinite" }} />}
      {status === "degraded" && (
        <span className={cn(ring, dot)} style={{ animation: "pp-badge-status-pulse-breathe 2.4s ease-in-out infinite" }} />
      )}
      {status === "down" && (
        <>
          <span className={cn(ring, dot)} style={{ animation: "pp-badge-status-pulse-sonar 1s ease-out infinite" }} />
          <span className={cn(ring, dot)} style={{ animation: "pp-badge-status-pulse-sonar 1s ease-out .35s infinite" }} />
        </>
      )}
      {status === "deploying" && (
        <span
          className="absolute -inset-[3px] rounded-full border-[1.5px] border-current border-r-transparent border-b-transparent opacity-70 motion-reduce:animate-none"
          style={{ animation: "pp-badge-status-pulse-orbit .9s linear infinite" }}
        />
      )}
      <span
        className={cn(
          "relative size-2 rounded-full",
          status === "idle" ? "border-[1.5px] border-muted-foreground/70" : dot,
          status === "deploying" && "scale-[0.6]",
        )}
      />
    </span>
  );
}

export function StatusBadge({ status, children, bare = false, className }: StatusBadgeProps) {
  return (
    <span
      className={cn(
        "inline-flex items-center gap-2 text-xs font-medium whitespace-nowrap",
        tones[status].text,
        !bare && cn("rounded-full border py-1 pr-2.5 pl-2", tones[status].pill),
        className,
      )}
    >
      <StatusDot status={status} className={bare ? undefined : "mx-0.5"} />
      {children}
    </span>
  );
}

const services: { name: string; region: string; status: Status; text: string }[] = [
  { name: "API gateway", region: "eu-west", status: "live", text: "Operational" },
  { name: "Dashboard", region: "global", status: "degraded", text: "Slow responses" },
  { name: "Webhooks", region: "us-east", status: "deploying", text: "Rolling out v2.41" },
  { name: "Image pipeline", region: "ap-south", status: "down", text: "Outage" },
];

export default function BadgeStatusPulseDemo() {
  return (
    <div className="flex w-full max-w-md flex-col items-center gap-6">
      <div className="flex flex-wrap items-center justify-center gap-2">
        <StatusBadge status="live">Live</StatusBadge>
        <StatusBadge status="degraded">Degraded</StatusBadge>
        <StatusBadge status="down">Down</StatusBadge>
        <StatusBadge status="deploying">Deploying</StatusBadge>
        <StatusBadge status="idle">Paused</StatusBadge>
      </div>
      <ul className="w-full divide-y divide-border rounded-2xl border border-border bg-card px-4">
        {services.map((s) => (
          <li key={s.name} className="flex items-center justify-between gap-4 py-3">
            <div className="min-w-0">
              <p className="truncate text-sm font-medium text-card-foreground">{s.name}</p>
              <p className="font-mono text-[11px] text-muted-foreground">{s.region}</p>
            </div>
            <StatusBadge status={s.status} bare>
              {s.text}
            </StatusBadge>
          </li>
        ))}
      </ul>
    </div>
  );
}
```

## AI prompt

```text
Add the "Badge Status Pulse" component from PixelPapa UI to this project.

What it is: Status badges with a live dot per state: a calm sonar ring for healthy, a breathing glow for degraded, urgent double rings for down and an orbiting arc for deploying.
Category: Badges. Depends on: no extra packages.

1. Install it with the shadcn CLI:
   npx shadcn@latest add "https://pixelpapa.com/r/badge-status-pulse.json"
   (If the CLI is unavailable, fetch that URL, write files[0].content to components/pixelpapa/badge-status-pulse.tsx and install the listed dependencies.)
2. Import it from "@/components/pixelpapa/badge-status-pulse" and place it where I describe below.
3. Keep its animation timings and accessibility attributes. Replace the demo copy and data with content that fits my product, and use my existing theme tokens (bg-background, text-foreground, bg-primary, border-border) rather than hard-coded colours.

Where to use it: <describe the page and position here>
```

## More badges

- [Badge Count Pop](https://pixelpapa.com/components/badges/badge-count-pop.md) (Pro): A notification count that bumps with a spring whenever it changes, rolls the digits in the direction of the change and pops out at zero.
- [Badge Dismissible Tags](https://pixelpapa.com/components/badges/badge-dismissible-tags.md) (Pro): Removable tags that blur and shrink away while their neighbours glide into the gap with a layout spring.
- [Badge Gradient Outline](https://pixelpapa.com/components/badges/badge-gradient-outline.md): Pill badges with a hairline gradient border and matching gradient text; on hover the colours slide through the outline and a soft tint fills the pill.
- [Badge Shimmer New](https://pixelpapa.com/components/badges/badge-shimmer-new.md): A small "New" label whose text catches a passing highlight on a loop while a tiny spark twinkles beside it.
- [Badge Trend Delta](https://pixelpapa.com/components/badges/badge-trend-delta.md) (Pro): A delta badge that flips its arrow with a spring, cross-fades between green and red and rolls the figure whenever the value changes sign or size.
- [Badge Verified Seal](https://pixelpapa.com/components/badges/badge-verified-seal.md) (Pro): A scalloped verification seal that spins in on a spring, draws its check stroke, takes a single sheen and then keeps turning slowly. Hover replays it.
