Hazine

Status Badge

A badge with a colored status dot and optional pulse animation for live states.

OperationalDegradedDownIdle

Installation

npx shadcn@latest add @hazine/status-badge

Source

import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"

import { cn } from "@/lib/utils"

const statusBadgeVariants = cva(
  "inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium",
  {
    variants: {
      status: {
        online: "border-emerald-500/30 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
        degraded: "border-amber-500/30 bg-amber-500/10 text-amber-600 dark:text-amber-400",
        offline: "border-red-500/30 bg-red-500/10 text-red-600 dark:text-red-400",
        idle: "border-border bg-muted text-muted-foreground",
      },
    },
    defaultVariants: {
      status: "online",
    },
  }
)

const dotColor: Record<string, string> = {
  online: "bg-emerald-500",
  degraded: "bg-amber-500",
  offline: "bg-red-500",
  idle: "bg-muted-foreground",
}

interface StatusBadgeProps
  extends React.ComponentProps<"span">,
    VariantProps<typeof statusBadgeVariants> {
  pulse?: boolean
}

export function StatusBadge({
  status = "online",
  pulse = false,
  className,
  children,
  ...props
}: StatusBadgeProps) {
  return (
    <span className={cn(statusBadgeVariants({ status }), className)} {...props}>
      <span className="relative flex size-2">
        {pulse && (
          <span
            className={cn(
              "absolute inline-flex size-full animate-ping rounded-full opacity-60 motion-reduce:hidden",
              dotColor[status ?? "online"]
            )}
          />
        )}
        <span
          className={cn(
            "relative inline-flex size-2 rounded-full",
            dotColor[status ?? "online"]
          )}
        />
      </span>
      {children}
    </span>
  )
}

Dependencies