Vertical Timeline
A free animated vertical timeline component for React and Next.js.
Our story
Six years of shipping, one milestone at a time
How Northbound went from three engineers and a prototype to a deployment platform 40,000 teams rely on every day.
2019
Company founded
Three engineers ship the first prototype from a rented studio and sign the earliest design partners.
12Design partners
2020
Seed round closed
A focused seed round funds the first full-time team and the move to a dedicated platform architecture.
$4.2MSeed round
2021
Public launch
The product opens to everyone, reaching ten thousand active teams in the first quarter after launch.
10,400Teams in Q1
2023
Series A and global expansion
New funding opens offices on three continents and brings enterprise support to regulated industries.
$28MSeries A
2025
Platform and public API
An extensible platform and public API let customers build their own integrations on top of the core.
1,900+Integrations built
Vertical Timeline is a free React timeline component for Next.js, built with Motion and styled with Tailwind. It renders your chronology as a semantic ordered list under its own section heading, then, as the section scrolls into view, fills a spine between the date rail and the entries while each entry and its node light up once in sequence.
You pass a heading and an array of items, and the component owns both the composition and the choreography. Each row places the date in a right-aligned left rail, the entry title and body in the centre, and an optional supporting figure in a fixed right rail, so equivalent parts line up across every entry however long the copy runs. The spine fill is a single scrubbed transform, and every entry reveals itself once at a fixed scroll position with its node scaling in and lighting from idle to accent. The full list is authored into the page as real ordered-list markup, so crawlers, keyboard users and reduced-motion visitors always read the complete chronology in order, with the spine shown fully filled and every node lit.
Install
Add the @te registry to your components.json once:
{
"registries": {
"@te": "https://templateempire.io/r/{name}.json"
}
}Then install the component:
npx shadcn@latest add @te/timeline-verticalUsage
import { TimelineVertical } from "@/components/timeline-vertical";
export default function Page() {
return (
<TimelineVertical
eyebrow="Since 2019"
heading="Six years of shipping, one milestone at a time"
lead="How the company went from three engineers and a prototype to a platform 40,000 teams rely on."
items={[
{ id: "founded", meta: "2019", title: "Company founded", description: "The first prototype ships.", metric: { value: "12", label: "Design partners" } },
{ id: "launch", meta: "2021", title: "Public launch", description: "The product opens to everyone.", metric: { value: "10,400", label: "Teams in Q1" } },
{ id: "series-a", meta: "2023", title: "Series A", description: "New funding opens three offices.", metric: { value: "$28M", label: "Series A" } },
]}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | { id: string; title: string; description: string; meta?: string; metric?: { value: string; label: string } }[] | required | The chronology, 3 to 8 entries, in display order. Each id is the stable React key and is used to detect a reorder; meta is an optional date or short label rendered in the left rail on the title's baseline, and metric is an optional supporting figure rendered in the right rail. The right rail is reserved as soon as any one entry supplies a figure, and then on every row so the figures align; a timeline with no figures at all gives the whole row to its copy. |
| eyebrow | string | undefined | Small label above the section heading, rendered in the accent text colour. |
| heading | string | undefined | Section heading, rendered as the h2 that leads the section so the entry titles read as subordinate h3s. |
| lead | string | undefined | Standfirst paragraph, rendered beside the heading from the lg breakpoint up and below it on smaller viewports. |
| className | string | undefined | Additional classes merged onto the section root. |
Customisation
Vertical Timeline exposes four Tier 3 tokens, each defaulting to a semantic token so it themes with the rest of your site out of the box: timeline-line for the hairline spine track, timeline-fill for the accent fill that scrubs in, timeline-marker for a node the scroll has reached, and timeline-marker-idle for a node it has not. Override any of them from your own CSS without touching the component:
:root {
--timeline-fill: var(--color-accent-400);
--timeline-marker: var(--color-accent-400);
}
<TimelineVertical items={items} className="max-w-2xl" />Frequently asked questions
- Is Vertical Timeline free for commercial use?
- Yes. Vertical Timeline is MIT licensed, so you can use it in personal and commercial projects without attribution.
- Does the timeline stay accessible and fast?
- Yes. The chronology is rendered as a real ordered list, so the full sequence is in the accessibility tree before any entry is reached, and the reveal never changes DOM order or visibility. The spine and nodes are decorative and hidden from assistive technology. Only transform and opacity are animated, inside space the list has already reserved, so there is no layout shift, and with reduced motion enabled nothing is animated or listens to scroll: every entry is visible, every node is lit and the spine is shown fully filled. Entries waiting below the fold are set to their starting state before the page first paints, so none is ever seen visible and then hidden, and the layout follows the section's own width rather than the viewport's.
- How do I recolour the spine and markers?
- Set the Tier 3 tokens from your own CSS. timeline-fill controls the accent fill that scrubs in as you scroll, timeline-line sets the hairline track behind it, timeline-marker sets the colour and halo of a node the scroll has reached, and timeline-marker-idle sets the colour of one it has not reached yet. Each one defaults to a semantic token, so the timeline matches your theme until you choose to override it.