Timeline
Vertical dated events on one hairline, newest first.
npx shadcn@latest add https://ui.goodtabs.co/r/timeline.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/timeline
Dark theme shipped
Registry opened
First sketch
Readable at 250px, dates in mono.
With detail
Version 1.4 released
Forty new components, including data display and feedback.
Registry installs passed 1,000
Most installs came from the form and navigation sets.
Switched to the new palette
Near-black surfaces, one indigo accent, hairline borders.
A quiet line under each title, inside a bordered box.
Usage
import { Timeline, TimelineItem } from "@/components/ui/timeline"
<Timeline>
<TimelineItem title="Registry opened" date="22 Oct" dateTime="2026-10-22" />
</Timeline>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | ReactNode | TimelineItem: what happened. | |
| date | string | TimelineItem: the date as people read it. | |
| dateTime | string | TimelineItem: machine-readable date for the time element. | |
| description | string | TimelineItem: one quiet line of detail. |
Source
timeline/timeline.tsx
import * as React from "react";
import { cn } from "@/lib/utils";
type TimelineProps = React.ComponentProps<"ol">;
/** A vertical list of dated events on one hairline. */
export function Timeline({ className, ...props }: TimelineProps) {
return <ol className={cn("m-0 flex list-none flex-col p-0", className)} {...props} />;
}
type TimelineItemProps = Omit<React.ComponentProps<"li">, "title"> & {
/** What happened, one line. */
title: React.ReactNode;
/** A machine-readable date, for example 2026-10-29. */
dateTime: string;
/** The date as people read it, for example "29 Oct". */
date: string;
/** One quiet line of detail. */
description?: string;
};
export function TimelineItem({ title, dateTime, date, description, className, ...props }: TimelineItemProps) {
return (
<li
className={cn(
"relative grid grid-cols-[1rem_1fr] gap-x-3 pb-5 last:pb-0",
"before:absolute before:top-3 before:bottom-0 before:left-[calc(0.5rem-0.5px)] before:w-px before:bg-border last:before:hidden",
className,
)}
{...props}
>
<span
aria-hidden="true"
className="mt-1.5 size-2 place-self-start justify-self-center rounded-full border-2 border-foreground bg-background"
/>
<div className="flex min-w-0 flex-col gap-0.5">
<p className="m-0 text-sm text-foreground">{title}</p>
<time dateTime={dateTime} className="font-mono text-xs text-muted-foreground">
{date}
</time>
{description && <p className="m-0 mt-1 text-sm text-muted-foreground">{description}</p>}
</div>
</li>
);
}
For AI agents
Hand your agent this page, the markdown at /components/timeline/prompt.md, or the Copy AI prompt button above.
When to use
- Changelogs, project history, order or build history
- A short run of dated events
When not to use
- Who did what: use activity-feed
- Steps in a flow: use stepper
Agent notes
- Pass items in the order to show; it does not sort
- The line stops at the last item
- Renders an ol, so screen readers announce the count