Browse the docs
ComponentsNo. 76 of 145
Timeline
A vertical list of events with a coloured dot for each status and a line joining them.
Installation
pnpm dlx shadcn@latest add @corsair-ui/timelineNo setup needed: the CLI finds @corsair-ui in the shadcn registry directory. The files land in your project as source: edit them like your own code. More in Installation.
- Also adds
- utils
- npm
clsxtailwind-merge
Examples
Order history
The status colours the dot; the title says it too.
Order placed
Order #4821 for 3 items.
Payment confirmed
Delayed at the warehouse
One item was restocked before packing.
Shipped
Handed to the carrier.
Out for delivery
Deployments
Newest first.
Deploy to production failed
Build step exited with code 1. Rolled back automatically.
Deploy to staging succeeded
Version 2.4.0, 3 minutes.
Deploy to staging started
API
| Prop | Type | Default |
|---|---|---|
statusTimelineItem: colours the dot. | "default" | "success" | "warning" | "destructive" | "default" |
dateTimeTimelineTime: the machine-readable moment; the visible text is yours. | string | — |
Styling
Restyle it in your project: className on each part, the theme variables, and these attributes with arbitrary variants, e.g. className="[&_[data-slot=timeline-connector]]:text-primary".
- Each timeline-item has data-status ("default", "success", "warning", "destructive"); the dot reads it through group-data-[status=…]/timeline-item.
- The dot uses --success, --warning and --destructive, with a ring in --background to cut the line.
- data-slot
timelinetimeline-connectortimeline-contenttimeline-descriptiontimeline-dottimeline-itemtimeline-timetimeline-title
- State
data-statuscomputed
Accessibility
- An ordered list, so the number of events and each one's position are announced.
- The dot and the line are hidden from screen readers: when the status matters, say it in the text.
- TimelineTime is a time element with a machine-readable dateTime.
Compatibility
- Tailwind CSS
- 3.4 and 4, both checked in CI
- React
- 19
- Rendering
- Works in server components
Source
1 file, installed as source you own
timeline.tsxView on GitHubimport type { ComponentProps } from "react";
import { cn } from "@/registry/default/lib/utils";
type TimelineStatus = "default" | "success" | "warning" | "destructive";
/**
* A vertical list of events in order: a ship's log, an order's history, a
* deploy log. It is an ordered list (`<ol>`), so screen readers announce how
* many events there are and where each one sits. Each `TimelineItem` has a
* `status` that colours its dot; the dot and the line joining the dots are
* decorative, so when the status matters, say it in the title or the
* description too. Dates go in `TimelineTime`, a `<time>` with a
* machine-readable `dateTime`; format the visible text for your locale.
* Nothing animates.
*
* @example
* <Timeline>
* <TimelineItem status="success">
* <TimelineDot />
* <TimelineConnector />
* <TimelineContent>
* <TimelineTitle>Left port</TimelineTitle>
* <TimelineTime dateTime="2025-03-02T08:00">2 March, 08:00</TimelineTime>
* <TimelineDescription>Cleared the harbour with a fair wind.</TimelineDescription>
* </TimelineContent>
* </TimelineItem>
* <TimelineItem>
* <TimelineDot />
* <TimelineConnector />
* <TimelineContent>
* <TimelineTitle>At sea</TimelineTitle>
* </TimelineContent>
* </TimelineItem>
* </Timeline>
*/
function Timeline({ className, ...props }: ComponentProps<"ol">) {
return <ol data-slot="timeline" className={cn("flex flex-col", className)} {...props} />;
}
interface TimelineItemProps extends ComponentProps<"li"> {
/** Colours the dot, and is exposed as `data-status` for your own styles. */
status?: TimelineStatus;
}
/** One event. Holds a `TimelineDot`, a `TimelineConnector` and a `TimelineContent`. */
function TimelineItem({ className, status = "default", ...props }: TimelineItemProps) {
return (
<li
data-slot="timeline-item"
data-status={status}
className={cn("group/timeline-item relative flex gap-3 pb-6 last:pb-0", className)}
{...props}
/>
);
}
/** The marker of an event, coloured by the item's `status`. Decorative: hidden from screen readers. */
function TimelineDot({ className, ...props }: ComponentProps<"span">) {
return (
<span
data-slot="timeline-dot"
aria-hidden="true"
className={cn(
"bg-primary ring-background relative z-[1] mt-1.5 size-3 shrink-0 rounded-full ring-4",
"group-data-[status=success]/timeline-item:bg-success",
"group-data-[status=warning]/timeline-item:bg-warning",
"group-data-[status=destructive]/timeline-item:bg-destructive",
className
)}
{...props}
/>
);
}
/**
* The line from this event's dot down to the next one. Decorative: hidden
* from screen readers, and not drawn on the last item.
*/
function TimelineConnector({ className, ...props }: ComponentProps<"span">) {
return (
<span
data-slot="timeline-connector"
aria-hidden="true"
className={cn(
"bg-border absolute top-6 bottom-0 left-[calc(0.375rem-0.5px)] w-px group-last/timeline-item:hidden",
className
)}
{...props}
/>
);
}
function TimelineContent({ className, ...props }: ComponentProps<"div">) {
return (
<div
data-slot="timeline-content"
className={cn("flex min-w-0 flex-1 flex-col gap-1", className)}
{...props}
/>
);
}
function TimelineTitle({ className, ...props }: ComponentProps<"p">) {
return (
<p
data-slot="timeline-title"
className={cn("text-sm leading-6 font-medium", className)}
{...props}
/>
);
}
interface TimelineTimeProps extends ComponentProps<"time"> {
/** The moment in a machine-readable format (`2025-03-02`, `2025-03-02T08:00Z`). */
dateTime: string;
}
/** When the event happened: a `<time>`; its text is yours to format for the reader's locale. */
function TimelineTime({ className, ...props }: TimelineTimeProps) {
return (
<time
data-slot="timeline-time"
className={cn("text-muted-foreground text-xs", className)}
{...props}
/>
);
}
function TimelineDescription({ className, ...props }: ComponentProps<"p">) {
return (
<p
data-slot="timeline-description"
className={cn("text-muted-foreground text-sm", className)}
{...props}
/>
);
}
export {
Timeline,
TimelineConnector,
TimelineContent,
TimelineDescription,
TimelineDot,
TimelineItem,
TimelineTime,
TimelineTitle,
type TimelineItemProps,
type TimelineStatus,
type TimelineTimeProps,
};