A composable sequence of milestones with current and complete states, dates, and connectors.
Brief approved
Scope and success criteria confirmed.
Design review
Components are ready for feedback.
Publish
Ship the approved experience.
import {
Timeline,
TimelineItem,
TimelineMarker,
TimelineContent,
TimelineTitle,
TimelineDescription,
TimelineTime,
TimelineConnector,
} from "@/components/ballmac/timeline"
export default function TimelineDemo() {
return (
<Timeline className="w-full max-w-sm">
<TimelineItem complete>
<TimelineMarker>✓</TimelineMarker>
<TimelineConnector />
<TimelineContent>
<TimelineTitle>Brief approved</TimelineTitle>
<TimelineDescription>
Scope and success criteria confirmed.
</TimelineDescription>
<TimelineTime dateTime="2026-09-25">Sep 25</TimelineTime>
</TimelineContent>
</TimelineItem>
<TimelineItem current>
<TimelineMarker>2</TimelineMarker>
<TimelineConnector />
<TimelineContent>
<TimelineTitle>Design review</TimelineTitle>
<TimelineDescription>
Components are ready for feedback.
</TimelineDescription>
<TimelineTime dateTime="2026-09-30">Today</TimelineTime>
</TimelineContent>
</TimelineItem>
<TimelineItem>
<TimelineMarker>3</TimelineMarker>
<TimelineContent>
<TimelineTitle>Publish</TimelineTitle>
<TimelineDescription>
Ship the approved experience.
</TimelineDescription>
</TimelineContent>
</TimelineItem>
</Timeline>
)
}Installation
$ pnpm dlx shadcn@latest add @ballmac/timelineCopy the source into your project.
components/ballmac/timeline.tsx// Ballmac UI: Timeline. https://ui.ballmac.com/components/timeline import * as React from "react" import { cn } from "@/lib/utils" type TimelineProps = React.ComponentProps<"ol"> & { /** Use a dense layout for log-like content. */ compact?: boolean } type TimelineItemProps = React.ComponentProps<"li"> & { /** Whether this item is the current step. */ current?: boolean /** Whether this item has completed. */ complete?: boolean } function Timeline({ className, compact = false, ...props }: TimelineProps) { return ( <ol data-slot="timeline" data-compact={compact} className={cn("group/timeline flex min-w-0 flex-col", className)} {...props} /> ) } function TimelineItem({ className, current = false, complete = false, ...props }: TimelineItemProps) { return ( <li data-slot="timeline-item" data-current={current || undefined} data-complete={complete || undefined} aria-current={current ? "step" : undefined} className={cn( "group/timeline-item relative grid min-w-0 grid-cols-[1.5rem_minmax(0,1fr)] gap-x-3 pb-6 last:pb-0 group-data-[compact=true]/timeline:pb-4", className, )} {...props} /> ) } function TimelineMarker({ className, children, ...props }: React.ComponentProps<"span">) { return ( <span data-slot="timeline-marker" aria-hidden="true" className={cn( "border-border bg-card text-muted-foreground z-10 flex size-6 items-center justify-center rounded-full border text-xs font-semibold group-data-[complete]/timeline-item:border-primary group-data-[complete]/timeline-item:bg-primary group-data-[complete]/timeline-item:text-primary-foreground group-data-[current]/timeline-item:border-primary group-data-[current]/timeline-item:text-primary", className, )} {...props} > {children} </span> ) } function TimelineContent({ className, ...props }: React.ComponentProps<"div">) { return ( <div data-slot="timeline-content" className={cn("min-w-0 pt-0.5", className)} {...props} /> ) } function TimelineTitle({ className, ...props }: React.ComponentProps<"h3">) { return ( <h3 data-slot="timeline-title" className={cn("text-sm font-medium leading-5", className)} {...props} /> ) } function TimelineDescription({ className, ...props }: React.ComponentProps<"p">) { return ( <p data-slot="timeline-description" className={cn( "text-muted-foreground mt-1 text-sm leading-relaxed", className, )} {...props} /> ) } function TimelineTime({ className, ...props }: React.ComponentProps<"time">) { return ( <time data-slot="timeline-time" className={cn( "text-muted-foreground mt-1 block text-xs tabular-nums", className, )} {...props} /> ) } function TimelineConnector({ className, ...props }: React.ComponentProps<"span">) { return ( <span data-slot="timeline-connector" aria-hidden="true" className={cn( "bg-border absolute bottom-0 start-[11px] top-6 w-px group-last/timeline-item:hidden", className, )} {...props} /> ) } export { Timeline, TimelineItem, TimelineMarker, TimelineContent, TimelineTitle, TimelineDescription, TimelineTime, TimelineConnector, type TimelineProps, type TimelineItemProps, }Update the import paths to match your project setup.
Usage
import { Timeline, TimelineItem, TimelineMarker, TimelineContent, TimelineTitle, TimelineDescription, TimelineTime, TimelineConnector } from "@/components/ballmac/timeline"The full example is in the Code tab above.
Examples
States and variants
Build passed
Deploying preview
import {
Timeline,
TimelineItem,
TimelineMarker,
TimelineContent,
TimelineTitle,
TimelineTime,
TimelineConnector,
} from "@/components/ballmac/timeline"
export default function TimelineStates() {
return (
<Timeline compact className="w-full max-w-xs">
<TimelineItem complete>
<TimelineMarker>✓</TimelineMarker>
<TimelineConnector />
<TimelineContent>
<TimelineTitle>Build passed</TimelineTitle>
<TimelineTime>11:42</TimelineTime>
</TimelineContent>
</TimelineItem>
<TimelineItem current>
<TimelineMarker>2</TimelineMarker>
<TimelineContent>
<TimelineTitle>Deploying preview</TimelineTitle>
<TimelineTime>11:45</TimelineTime>
</TimelineContent>
</TimelineItem>
</Timeline>
)
}API reference
<Timeline>
| Prop | Type | Default |
|---|---|---|
compactUse a dense layout for log-like content. | boolean | false |
<TimelineItem>
| Prop | Type | Default |
|---|---|---|
currentWhether this item is the current step. | boolean | false |
completeWhether this item has completed. | boolean | false |
Also accepts the standard attributes of its root element.
Accessibility
| Key | Action |
|---|---|
| None | Static content is announced with semantic structure |
Use with AI
A composable sequence of milestones with current and complete states, dates, and connectors. With the shadcn MCP server set up (guide), ask your agent:
Add the Ballmac UI Timeline (@ballmac/timeline) to this project with the shadcn MCP, then use it where it fits.
Use it for
- Show milestones or a chronological process
Not for
- Use Activity Feed for a compact actor log
Registry JSON: https://ui.ballmac.com/r/timeline.json
Credits
Free to use in personal and commercial projects.
- npm
- None
- Registry
- shadcn/utils
Pairs well with
Activity Feed
A compact actor and action feed with timestamps and an empty state.
Audio Player
A podcast-style audio player: play and pause, skip back and forward, a scrubber with chapter ticks, a named current chapter and a speed control. Works with a real file or as a silent demo.
Avatar Circles
Overlapping avatars that spread on hover, lift individually with a name and role tooltip, show presence, fall back to initials and end in a +N count that can be a button.
Avatar Stack
An accessible compact row of people with initials, image support, and an overflow count.