Dice UI
Components

Status

A flexible status indicator component with animated ping effect and color variants for displaying system states, user presence, and service health.

API
import {
  Status,
  StatusIndicator,
  StatusLabel,
} from "@/components/ui/status";
 
export function StatusDemo() {
  return (
    <div className="flex flex-wrap items-center gap-2.5">
      <Status variant="success">
        <StatusIndicator />
        <StatusLabel>Online</StatusLabel>
      </Status>
 
      <Status variant="error">
        <StatusIndicator />
        <StatusLabel>Offline</StatusLabel>
      </Status>
 
      <Status variant="warning">
        <StatusIndicator />
        <StatusLabel>Away</StatusLabel>
      </Status>
 
      <Status variant="info">
        <StatusIndicator />
        <StatusLabel>Idle</StatusLabel>
      </Status>
 
      <Status variant="default">
        <StatusIndicator />
        <StatusLabel>Unknown</StatusLabel>
      </Status>
    </div>
  );
}

Installation

CLI

npx shadcn@latest add @diceui/status

Manual

Copy and paste the following code into your project.

import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils";
 
interface DivProps extends React.ComponentProps<"div"> {}
 
const statusVariants = cva(
  "inline-flex w-fit shrink-0 items-center gap-1.5 overflow-hidden whitespace-nowrap rounded-full border px-2.5 py-1 font-medium text-xs transition-colors",
  {
    variants: {
      variant: {
        default:
          "border-transparent bg-muted text-muted-foreground **:data-[slot=status-indicator]:bg-muted-foreground",
        success:
          "border-green-500/20 bg-green-500/10 text-green-600 **:data-[slot=status-indicator]:bg-green-600 dark:text-green-400 **:data-[slot=status-indicator]:dark:bg-green-400",
        error:
          "border-destructive/20 bg-destructive/10 text-destructive **:data-[slot=status-indicator]:bg-destructive",
        warning:
          "border-orange-500/20 bg-orange-500/10 text-orange-600 **:data-[slot=status-indicator]:bg-orange-600 dark:text-orange-400 **:data-[slot=status-indicator]:dark:bg-orange-400",
        info: "border-blue-500/20 bg-blue-500/10 text-blue-600 **:data-[slot=status-indicator]:bg-blue-600 dark:text-blue-400 **:data-[slot=status-indicator]:dark:bg-blue-400",
      },
    },
    defaultVariants: {
      variant: "default",
    },
  },
);
 
interface StatusProps extends VariantProps<typeof statusVariants>, DivProps {
  asChild?: boolean;
}
 
function Status(props: StatusProps) {
  const { className, variant = "default", asChild, ...rootProps } = props;
 
  const RootPrimitive = asChild ? Slot : "div";
 
  return (
    <RootPrimitive
      data-slot="status"
      data-variant={variant}
      {...rootProps}
      className={cn(statusVariants({ variant }), className)}
    />
  );
}
 
function StatusIndicator(props: DivProps) {
  const { className, ...indicatorProps } = props;
 
  return (
    <div
      data-slot="status-indicator"
      {...indicatorProps}
      className={cn(
        "relative flex size-2 shrink-0 rounded-full",
        "before:absolute before:inset-0 before:animate-ping before:rounded-full before:bg-inherit",
        "after:absolute after:inset-[2px] after:rounded-full after:bg-inherit",
        className,
      )}
    />
  );
}
 
function StatusLabel(props: DivProps) {
  const { className, ...labelProps } = props;
 
  return (
    <div
      data-slot="status-label"
      {...labelProps}
      className={cn("leading-none", className)}
    />
  );
}
 
export {
  Status,
  StatusIndicator,
  StatusLabel,
  //
  statusVariants,
};

Layout

Import the parts, and compose them together.

import {
  Status,
  StatusIndicator,
  StatusLabel,
} from "@/components/ui/status";

return (
  <Status variant="success">
    <StatusIndicator />
    <StatusLabel>Online</StatusLabel>
  </Status>
);

Examples

Variants

Status supports five color variants to represent different states.

import {
  Status,
  StatusIndicator,
  StatusLabel,
} from "@/components/ui/status";
 
export function StatusVariantsDemo() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex flex-col gap-3">
        <h3 className="font-medium text-sm">Success Variants</h3>
        <div className="flex flex-wrap items-center gap-2.5">
          <Status variant="success">
            <StatusIndicator />
            <StatusLabel>Online</StatusLabel>
          </Status>
          <Status variant="success">
            <StatusIndicator />
            <StatusLabel>Active</StatusLabel>
          </Status>
          <Status variant="success" className="hidden sm:inline-flex">
            <StatusIndicator />
            <StatusLabel>Connected</StatusLabel>
          </Status>
        </div>
      </div>
 
      <div className="flex flex-col gap-3">
        <h3 className="font-medium text-sm">Error Variants</h3>
        <div className="flex flex-wrap items-center gap-2.5">
          <Status variant="error">
            <StatusIndicator />
            <StatusLabel>Offline</StatusLabel>
          </Status>
          <Status variant="error">
            <StatusIndicator />
            <StatusLabel>Disconnected</StatusLabel>
          </Status>
          <Status variant="error" className="hidden sm:inline-flex">
            <StatusIndicator />
            <StatusLabel>Failed</StatusLabel>
          </Status>
        </div>
      </div>
 
      <div className="flex flex-col gap-3">
        <h3 className="font-medium text-sm">Warning Variants</h3>
        <div className="flex flex-wrap items-center gap-2.5">
          <Status variant="warning">
            <StatusIndicator />
            <StatusLabel>Away</StatusLabel>
          </Status>
          <Status variant="warning">
            <StatusIndicator />
            <StatusLabel>Busy</StatusLabel>
          </Status>
          <Status variant="warning" className="hidden sm:inline-flex">
            <StatusIndicator />
            <StatusLabel>Pending</StatusLabel>
          </Status>
        </div>
      </div>
 
      <div className="flex flex-col gap-3">
        <h3 className="font-medium text-sm">Info Variants</h3>
        <div className="flex flex-wrap items-center gap-2.5">
          <Status variant="info">
            <StatusIndicator />
            <StatusLabel>Idle</StatusLabel>
          </Status>
          <Status variant="info">
            <StatusIndicator />
            <StatusLabel>In Progress</StatusLabel>
          </Status>
          <Status variant="info" className="hidden sm:inline-flex">
            <StatusIndicator />
            <StatusLabel>Syncing</StatusLabel>
          </Status>
        </div>
      </div>
 
      <div className="flex flex-col gap-3">
        <h3 className="font-medium text-sm">Default Variants</h3>
        <div className="flex flex-wrap items-center gap-2.5">
          <Status variant="default">
            <StatusIndicator />
            <StatusLabel>Unknown</StatusLabel>
          </Status>
          <Status variant="default">
            <StatusIndicator />
            <StatusLabel>Not Set</StatusLabel>
          </Status>
          <Status variant="default" className="hidden sm:inline-flex">
            <StatusIndicator />
            <StatusLabel>N/A</StatusLabel>
          </Status>
        </div>
      </div>
    </div>
  );
}

Text Only

Use status without the indicator for a simpler appearance.

import { Status, StatusLabel } from "@/components/ui/status";
 
export function StatusTextOnlyDemo() {
  return (
    <div className="flex flex-wrap items-center gap-2.5">
      <Status variant="success">
        <StatusLabel>Active</StatusLabel>
      </Status>
 
      <Status variant="error">
        <StatusLabel>Inactive</StatusLabel>
      </Status>
 
      <Status variant="warning">
        <StatusLabel>Pending</StatusLabel>
      </Status>
 
      <Status variant="info">
        <StatusLabel>Processing</StatusLabel>
      </Status>
 
      <Status variant="default">
        <StatusLabel>Draft</StatusLabel>
      </Status>
    </div>
  );
}

Service Status List

Display multiple status items in a list format, ideal for system health dashboards.

import {
  Status,
  StatusIndicator,
  StatusLabel,
} from "@/components/ui/status";
 
const services = [
  { name: "API Server", status: "success" as const, uptime: "99.9%" },
  { name: "Cache Service", status: "warning" as const, uptime: "98.5%" },
  { name: "Message Queue", status: "success" as const, uptime: "99.8%" },
  { name: "CDN", status: "error" as const, uptime: "95.2%" },
  { name: "Email Service", status: "info" as const, uptime: "Updating..." },
];
 
export function StatusListDemo() {
  return (
    <div className="flex w-full max-w-md flex-col gap-2">
      {services.map((service) => (
        <div
          key={service.name}
          className="flex items-center justify-between rounded-lg border bg-card p-3"
        >
          <div className="flex flex-col gap-0.5">
            <span className="font-medium text-sm">{service.name}</span>
            <span className="text-muted-foreground text-xs">
              Uptime: {service.uptime}
            </span>
          </div>
          <Status variant={service.status}>
            <StatusIndicator />
            <StatusLabel className="capitalize">{service.status}</StatusLabel>
          </Status>
        </div>
      ))}
    </div>
  );
}

API Reference

Status

The main container component that provides the badge-style wrapper with color variants.

Prop

Type

Data AttributeValue
[data-variant]"default" | "success" | "error" | "warning" | "info"

StatusIndicator

An animated pulse indicator for the status.

Prop

Type

StatusLabel

The text label for the status.

Prop

Type

Accessibility

The Status component uses semantic HTML and follows best practices for accessibility:

  • Uses div elements with proper ARIA attributes when needed
  • Color is not the only means of conveying information—always include text labels
  • Supports keyboard navigation when used with interactive elements via asChild

Notes

  • The animated ping effect uses Tailwind's built-in animate-ping utility for smooth performance
  • Colors automatically adapt to dark mode
  • The indicator animation runs continuously to draw attention to live status changes
  • Use the asChild prop to render Status as a link or button for interactive use cases

On this page