Timeline
A vertical timeline layout with animated entries that reveal on scroll.
Timeline
A vertical timeline component where each entry animates in from the side as you scroll down the page.
Animation Process
Each timeline entry slides in from alternating sides (left/right) using CSS transforms. The animation is triggered by an IntersectionObserver on each entry element.
"use client";
import { useEffect, useRef } from "react";
const events = [
{ date: "2024-01", title: "Project Kickoff", side: "left" },
{ date: "2024-03", title: "Alpha Release", side: "right" },
{ date: "2024-06", title: "Public Launch", side: "left" },
];
export function Timeline() {
return (
<div className="relative">
<div className="absolute left-1/2 w-px bg-border h-full" />
{events.map((event, i) => (
<TimelineEntry key={event.date} event={event} index={i} />
))}
</div>
);
}
function TimelineEntry({ event, index }: { event: typeof events[0]; index: number }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const el = ref.current;
if (!el) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
el.classList.add("timeline-visible");
observer.unobserve(el);
}
},
{ threshold: 0.1 }
);
observer.observe(el);
return () => observer.disconnect();
}, []);
const isLeft = event.side === "left";
return (
<div
ref={ref}
className={`relative w-1/2 p-8 opacity-0 transition-all duration-700 ${
isLeft ? "mr-auto -translate-x-full" : "ml-auto translate-x-full"
}`}
>
<h3>{event.title}</h3>
<p>{event.date}</p>
</div>
);
}Key steps:
- A vertical line runs down the center of the container
- Each entry is positioned left or right of the line
- Entries start offset (
translateX) and invisible - On intersection, they slide into position with a smooth transition
Source Code
View the full implementation on GitHub.