Skip to content
All Taste components

Data display

Timeline

The steps of an order or booking in time order, with what has happened and what is next.

done · current · upcoming · time · note

  1. Booking confirmed14 Oct, 09:12
    Deep clean · 2BHK for Sat, 18 Oct.
  2. Advance paid14 Oct, 09:15
    ₹1,000 by UPI.
  3. Team assignedToday
    Sunita and Ravi will arrive at 10:00.
  4. Service daySat, 18 Oct
import { Check, Clock } from "lucide-react";
import { cn } from "@/lib/utils";

type Entry = { title: string; time: string; note?: string; state: "done" | "current" | "upcoming" };

export function Timeline({ label, entries }: { label: string; entries: Entry[] }) {
  return (
    <ol aria-label={label} className="w-full max-w-[420px]">
      {entries.map((e, i) => {
        const last = i === entries.length - 1;
        return (
          <li key={e.title} aria-current={e.state === "current" ? "step" : undefined}
            className={cn("relative grid grid-cols-[28px_minmax(0,1fr)] gap-3", !last && "pb-5")}>
            {!last && (
              <span aria-hidden className={cn("absolute bottom-0.5 left-[13px] top-[30px] w-0.5 rounded-full",
                e.state === "done" ? "bg-success" : "bg-border")} />
            )}
            <span className={cn(
              "grid size-7 place-items-center rounded-full border-[1.5px] bg-bg",
              e.state === "done" && "border-transparent bg-success-soft text-success-fg",
              e.state === "current" && "border-primary text-primary ring-4 ring-primary/15",
              e.state === "upcoming" && "border-border-strong text-fg-subtle",
            )}>
              {e.state === "done" && <Check className="size-3.5" aria-hidden />}
              {e.state === "current" && <span className="size-2 rounded-full bg-current" />}
              {e.state === "upcoming" && <Clock className="size-3.5" aria-hidden />}
            </span>
            <div>
              <div className="flex flex-wrap items-baseline justify-between gap-x-3 gap-y-0.5 pt-1">
                <p className={cn("text-[13.5px] font-medium", e.state === "upcoming" && "text-fg-muted")}>{e.title}</p>
                <p className="text-[12.5px] tabular-nums text-fg-subtle">{e.time}</p>
              </div>
              {e.note && <p className="mt-0.5 text-[13px] text-fg-muted">{e.note}</p>}
            </div>
          </li>
        );
      })}
    </ol>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.