2019
CurrentCompany founded
Three engineers ship the first prototype from a rented studio and sign the earliest design partners.
A free horizontal timeline component for React and Next.js with an accessible scrollable rail.
Company timeline
Seven years of shipping, from a rented studio to the public API teams build on.
2019
CurrentThree engineers ship the first prototype from a rented studio and sign the earliest design partners.
2020
A focused seed round funds the first full-time team and the move to a dedicated platform architecture.
2021
The product opens to everyone, reaching ten thousand active teams in the first quarter after launch.
2023
New funding opens offices on three continents and brings enterprise support to regulated industries.
2025
An extensible platform and public API let customers build their own integrations on top of the core.
<TimelineHorizontal
milestones={[
{ id: "founded", date: "2019", title: "Company founded", description: "The first prototype ships." },
{ id: "launch", date: "2021", title: "Public launch", description: "The product opens to everyone." },
{ id: "series-a", date: "2023", title: "Series A", description: "New funding opens three offices." },
]}
/>Timeline Horizontal is a free horizontal timeline React component for Next.js, built with Motion and styled with Tailwind. On wide screens it renders your milestones as a horizontally scrollable rail with a decorative progress spine, previous and next buttons, and scroll snap, and on narrow screens it renders the same ordered list as a normal vertical chronology with no overflow at all.
You pass an array of milestones and the component owns the rest: buttons, arrow keys and native wheel or touch scrolling all resolve to the same active milestone, tracked by a debounced IntersectionObserver so the progress fill and active marker settle once scrolling stops rather than flickering mid-scroll. Reduced motion keeps every control working, it just swaps smooth scrolling and animated transitions for instant ones, and the mobile layout has no scroll-driven motion to begin with.
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-horizontalimport { TimelineHorizontal } from "@/components/timeline-horizontal";
export default function Page() {
return (
<TimelineHorizontal
milestones={[
{ id: "founded", date: "2019", title: "Company founded", description: "The first prototype ships." },
{ id: "launch", date: "2021", title: "Public launch", description: "The product opens to everyone." },
{ id: "series-a", date: "2023", title: "Series A", description: "New funding opens three offices." },
]}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| milestones | { id: string; date: string; title: string; description: string }[] | required | Three to eight ordered milestones with unique, non-empty ids. Invalid input renders nothing. |
| initialId | string | undefined | Initial active milestone id. Falls back to the first milestone when omitted or unmatched. |
| spacing | number | 280 | Wide-screen milestone width in CSS pixels, clamped to 220 through 380. |
| fillDuration | number | 0.45 | Progress-fill transition duration in seconds, clamped to 0 through 1. |
| markerScale | number | 1.16 | Active marker scale multiplier, clamped to 1 through 1.35. |
| snap | "mandatory" | "proximity" | "none" | "proximity" | Horizontal CSS scroll-snap treatment for the wide-screen rail. |
| railHeight | number | 280 | Wide-screen rail minimum height in CSS pixels, clamped to 220 through 420. |
| radius | number | 22 | Milestone card corner radius in CSS pixels, clamped to 0 through 42. |
| onMilestoneChange | (id: string) => void | undefined | Called with a milestone's id once a button, keyboard, or scroll activation settles on it. |
| label | string | "Milestones" | Accessible name shared by the timeline region and its ordered list. |
| className | string | undefined | Additional classes merged onto the section root. |
Timeline Horizontal exposes four Tier 3 tokens, each defaulting to a semantic token so it themes with the rest of your site out of the box: horizontal-timeline-accent for the completed and active markers and the progress fill, horizontal-timeline-track for the muted rail and connecting line, horizontal-timeline-marker for the outline ring on upcoming markers, and horizontal-timeline-panel for the milestone card surface. Override any of them from your own CSS without touching the component:
:root {
--horizontal-timeline-accent: var(--color-accent-400);
--horizontal-timeline-panel: var(--color-neutral-900);
}
<TimelineHorizontal milestones={milestones} spacing={320} />