Milestones block
BlockA history read top to bottom. One line fills as the list scrolls through the window and each marker settles when it is reached, using native scroll only.
pnpm dlx shadcn@latest add https://caliperui.site/r/milestones-block.jsonOur story
Six years of quieter month-ends
March 2020
Two accountants and a spreadsheet
Halden starts as a set of macros for a 12-person agency's close.
January 2021
First bank feed
Mercury and Stripe connect directly; matching saves our first customers a day a month.
October 2022
Rules and approvals
Teams write their own rules, and large payments wait for sign-off.
1,000 teams
June 2024
Multi-entity close
Groups with several companies close them together, with eliminations.
May 2026
The close reads itself
A written summary of what changed and why, generated from the ledger.
$40B reconciled
When to use #
Use it for
- About pages, a product's story, a funding history.
- Five to ten dated events.
Skip it when
- Release notes; use the changelog.
- Anything people need to scan quickly; use a table.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/milestones-block.json
Adds its 4 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.
Usage #
This is the code behind the preview above.
import { MilestonesBlock } from "@/components/ui/milestones-block" export function MilestonesBlockDemo() { return ( <MilestonesBlock eyebrow="Our story" title="Six years of quieter month-ends" milestones={[ { date: "March 2020", title: "Two accountants and a spreadsheet", body: "Halden starts as a set of macros for a 12-person agency's close." }, { date: "January 2021", title: "First bank feed", body: "Mercury and Stripe connect directly; matching saves our first customers a day a month." }, { date: "October 2022", title: "Rules and approvals", body: "Teams write their own rules, and large payments wait for sign-off.", figure: "1,000 teams" }, { date: "June 2024", title: "Multi-entity close", body: "Groups with several companies close them together, with eliminations." }, { date: "May 2026", title: "The close reads itself", body: "A written summary of what changed and why, generated from the ledger.", figure: "$40B reconciled" }, ]} /> ); } const teams = [120, 180, 260, 310, 420, 540, 610, 590, 720, 980, 1240, 1380, 1520, 1880, 2310, 2640].map((value, i) => ({ label: `Q${(i % 4) + 1} ${2023 + Math.floor(i / 4)}`, value }));
API reference #
MilestonesBlock
component
Accessibility #
It is built on native elements and keeps aria-hidden in step with state.
No custom key handling; Tab and the native activation keys do the work.
Motion #
It checks prefers-reduced-motion itself and settles immediately instead of travelling. Every state is still reachable.