caliper uidocs

Status morph

Free

A status that changes in place: the pill eases to its new width while icon and colour cross over, and the change is announced.

Installs components/ui/status-morph.tsxDepends on lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/status-morph.json

Deploy #418Queued

When to use #

Use it for

  • Deploys, jobs, payments and anything that moves through states.
  • Rows that update while people watch.

Skip it when

  • Static labels; use a badge.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/status-morph.json

Adds its 2 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above.

example.tsx
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { StatusMorph } from "@/components/ui/status-morph"

const deployStates = {
  queued: { label: "Queued", tone: "neutral" },
  building: { label: "Building", tone: "progress" },
  checks: { label: "Running checks", tone: "progress" },
  live: { label: "Live", tone: "success" },
  failed: { label: "Failed: tests", tone: "error" },
} as const;

type DeployState = keyof typeof deployStates;

export function StatusMorphDemo() {
  const order: DeployState[] = ["queued", "building", "checks", "live"];
  const [status, setStatus] = useState<DeployState>("queued");
  const next = () => setStatus((current) => order[(order.indexOf(current) + 1) % order.length] ?? "queued");
  return (
    <div className="grid justify-items-center gap-4">
      <p className="flex items-center gap-3 text-sm"><span className="text-muted-foreground">Deploy #418</span><StatusMorph status={status} states={deployStates} /></p>
      <div className="flex gap-2">
        <Button size="sm" variant="secondary" onClick={next}>Advance</Button>
        <Button size="sm" variant="ghost" onClick={() => setStatus("failed")}>Fail it</Button>
      </div>
    </div>
  );
}

API reference #

StatusMorph

component

Also accepts the native props of its root element and a ref.

PropTypeDefaultDescription
status *T—
states *Readonly<Record<T, StatusMorphState>>—Every status it can show, with its label and tone.

Accessibility #

It exposes status semantics, with aria-live and aria-hidden kept in step with state. Changes that matter are announced through a live region.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.