Timeline
freeTimeline arranges activity, history, and milestone entries in chronological order.
Monday, 28 February
Camila Simmonsmentioned you in a commentPost08:34 PM@Carolyn There are two ways to write error-free programs; only the third one works.
Angelina Gotelliaddedtranslation.xlsto ticketPD-109208:09 PM
Angelina Gotellimentioned you in a commentPost08:06 PM@Carolyn Don't worry if it doesn't work right. If everything did, you'd be out of a job.
import Timeline from '@/components/ui/Timeline';
import Avatar from '@/components/ui/Avatar';
import Tag from '@/components/ui/Tag';
import { PiPaperclip } from 'react-icons/pi'
const EVENTS = [
{
id: 'first-comment',
avatar: '/img/avatars/thumb-2.jpg',
name: 'Camila Simmons',
action: 'mentioned you in a comment',
object: 'Post',
time: '08:34 PM',
mention: '@Carolyn',
comment:
'There are two ways to write error-free programs; only the third one works.',
},
{
id: 'file-added',
avatar: '/img/avatars/thumb-3.jpg',
name: 'Angelina Gotelli',
action: 'added',
object: 'translation.xls',
ticket: 'PD-1092',
time: '08:09 PM',
},
{
id: 'second-comment',
avatar: '/img/avatars/thumb-3.jpg',
name: 'Angelina Gotelli',
action: 'mentioned you in a comment',
object: 'Post',
time: '08:06 PM',
mention: '@Carolyn',
comment:
"Don't worry if it doesn't work right. If everything did, you'd be out of a job.",
},
] as const;
export default function UsageDemo() {
return (
<div className="w-full max-w-2xl">
<p className="mb-4 text-sm font-semibold uppercase text-muted-foreground">
Monday, 28 February
</p>
<Timeline>
{EVENTS.map((event) => (
<Timeline.Item
key={event.id}
media={
<Avatar
size={24}
src={event.avatar}
alt={event.name}
/>
}
>
<div className="grid gap-4">
<div className="flex flex-wrap items-center gap-2 text-sm">
<span className="font-medium">
{event.name}
</span>
<span className="text-muted-foreground">
{event.action}
</span>
{event.id === 'file-added' ? (
<span className="inline-flex items-center gap-2 text-foreground">
<PiPaperclip className="size-3.5" />
{event.object}
</span>
) : (
<span className="font-semibold text-foreground">
{event.object}
</span>
)}
{'ticket' in event ? (
<>
<span className="text-muted-foreground">to ticket</span>
<Tag
size="sm"
className="bg-card"
>
{event.ticket}
</Tag>
</>
) : null}
<span className="text-muted-foreground">{event.time}</span>
</div>
{'comment' in event ? (
<div className="rounded-control border bg-card px-4 py-3 text-sm text-foreground">
<Tag
size="sm"
className="border-transparent bg-palette-blue-soft text-palette-blue-soft-foreground"
>
{event.mention}
</Tag>{' '}
{event.comment}
</div>
) : null}
</div>
</Timeline.Item>
))}
</Timeline>
</div>
);
}Installation
Add this component with the NateUI CLI.
npx nateui@latest add TimelineExamples
Basic
Brief received
Requirements were collected and attached to the project.
Design reviewed
The team approved the main layout and edge cases.
Ready for build
Implementation can start once the branch is created.
import Timeline from '@/components/ui/Timeline';
export default function BasicDemo() {
return (
<Timeline className="max-w-md">
<Timeline.Item>
<p className="font-medium text-foreground">Brief received</p>
<p className="text-sm text-muted-foreground">
Requirements were collected and attached to the project.
</p>
</Timeline.Item>
<Timeline.Item>
<p className="font-medium text-foreground">Design reviewed</p>
<p className="text-sm text-muted-foreground">
The team approved the main layout and edge cases.
</p>
</Timeline.Item>
<Timeline.Item>
<p className="font-medium text-foreground">Ready for build</p>
<p className="text-sm text-muted-foreground">
Implementation can start once the branch is created.
</p>
</Timeline.Item>
</Timeline>
);
}Custom Media
Import completed
Completed18,432 customer rows were validated.
QA review
In reviewTwo edge cases are waiting for product approval.
Launch handoff
QueuedSupport notes are queued for the release channel.
import Timeline from '@/components/ui/Timeline';
import { PiCheck, PiClock, PiFlag } from 'react-icons/pi'
const STEPS = [
{
title: 'Import completed',
description: '18,432 customer rows were validated.',
status: 'Completed',
icon: PiCheck,
mediaClassName:
'bg-palette-emerald-soft text-palette-emerald-soft-foreground',
},
{
title: 'QA review',
description: 'Two edge cases are waiting for product approval.',
status: 'In review',
icon: PiClock,
mediaClassName:
'bg-palette-blue-soft text-palette-blue-soft-foreground',
},
{
title: 'Launch handoff',
description: 'Support notes are queued for the release channel.',
status: 'Queued',
icon: PiFlag,
mediaClassName:
'bg-muted text-muted-foreground',
},
] as const;
export default function CustomMediaDemo() {
return (
<Timeline className="max-w-xl">
{STEPS.map((step) => {
const Icon = step.icon;
return (
<Timeline.Item
key={step.title}
media={
<span
className={`flex size-6 items-center justify-center rounded-full border ${step.mediaClassName}`}
>
<Icon className="size-3.5" />
</span>
}
>
<div className="grid gap-2">
<div className="flex flex-wrap items-center gap-2">
<p className="font-medium text-foreground">
{step.title}
</p>
<span className="text-xs text-muted-foreground">
{step.status}
</span>
</div>
<p className="text-sm text-muted-foreground">
{step.description}
</p>
</div>
</Timeline.Item>
);
})}
</Timeline>
);
}API
Timeline renders a list of ordered entries and hides the connector after the last item. Timeline.Item renders the marker column plus the content column for one entry. The exported types extend native ul and li props, but the current implementation only forwards the props listed below.
Timeline
| Prop | Description | Type | Default |
|---|---|---|---|
children | Items rendered in sequence. Use Timeline.Item children so the final connector can be derived. | ReactNode | - |
className | Extra classes for the root ul. | string | - |
ref | Ref forwarded to the root ul. | Ref<HTMLUListElement> | - |
Timeline.Item
| Prop | Description | Type | Default |
|---|---|---|---|
children | Content rendered beside the marker. | ReactNode | - |
media | Custom marker content. When omitted, the item renders the default dot. | string | ReactNode | - |
isLast | Hides the connector and bottom padding. Usually derived by Timeline from item position. | boolean | Derived from position |
className | Extra classes for the root li. | string | - |
ref | Ref forwarded to the root li. | Ref<HTMLLIElement> | - |