A horizontal timeline with a dot per milestone, large serif years and short notes, swipeable on phones. React and Tailwind CSS.
DotTimeline.tsx
// Horizontal timeline: a hairline with a dot per milestone (the latest in lime),
// big serif years and short notes; swipes sideways on phones.
// Pure Tailwind, no dependencies. Works with Tailwind v3 and v4.
type Milestone = { year: string; title: string; text?: string };
type Props = {
heading?: string;
milestones?: Milestone[];
};
const DEFAULT_MILESTONES: Milestone[] = [
{ year: "1962", title: "The first field", text: "Our grandparents plant wheat on twelve rented acres." },
{ year: "1988", title: "Going organic", text: "We stop spraying and start rotating every field." },
{ year: "2005", title: "The farm shop", text: "A barn becomes a shop selling straight from the field." },
{ year: "2019", title: "Growers' co-op", text: "Thirty neighbouring farms join us under one label." },
{ year: "2026", title: "Carbon negative", text: "Our soil now stores more carbon than the farm emits." },
];
export default function DotTimeline({ heading = "Sixty harvests and counting", milestones = DEFAULT_MILESTONES }: Props) {
return (
<section className="bg-[#f6f0de] px-4 py-24 font-['Geist',ui-sans-serif,system-ui,sans-serif] text-[#0f1712] antialiased md:px-8 md:py-36">
<div className="mx-auto max-w-7xl">
<h2 className="max-w-3xl font-['Newsreader',Georgia,serif] text-[clamp(2.25rem,4.5vw,4.5rem)] leading-none">{heading}</h2>
<ol className="-mx-4 mt-14 flex snap-x snap-mandatory overflow-x-auto px-4 [scrollbar-width:none] md:mx-0 md:mt-20 md:grid md:auto-cols-fr md:grid-flow-col md:overflow-visible md:px-0 [&::-webkit-scrollbar]:hidden">
{milestones.map((m, i) => (
<li key={m.year} className="w-64 shrink-0 snap-start pr-8 md:w-auto">
<div className="relative h-px bg-[#0f1712]/15">
<span className={`absolute -top-1.5 left-0 h-3 w-3 rounded-full ring-4 ring-[#f6f0de] ${i === milestones.length - 1 ? "bg-lime-500" : "bg-[#035a39]"}`} />
</div>
<p className="mt-10 font-['Newsreader',Georgia,serif] text-[clamp(1.875rem,3.3vw,3.25rem)] leading-none text-[#024b2f]">{m.year}</p>
<h3 className="mt-5 font-medium">{m.title}</h3>
{m.text && <p className="mt-2 text-sm leading-relaxed text-[#0f1712]/60">{m.text}</p>}
</li>
))}
</ol>
</div>
</section>
);
}
How to use it
- Make sure your Next.js or React project has Tailwind CSS set up (v3 or v4 both work).
- Create
components/DotTimeline.tsxand paste the code. - Import it into a page and replace the sample text and images with your own.
