Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Milestone Rail Testimonials Block for React

A horizontal rail of five milestones, from Day 1 to Year 1, in a hairline frame: pick one to read what a customer team said at that point, with the milestones already passed checked.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Tell a customer story across time with this testimonials block for React with Base UI. A compact header names the story, Halden Freight's year on a fictional component kit called Tidewell, and ends with a Shine Button to the full case study, the only primary control. Under it, a hairline frame with plus marks on its corners holds a horizontal rail of five milestones (Day 1, Week 2, Month 1, Month 6 and Year 1) and, below a second ruled band, the open milestone's panel: a badge and a short headline on the start side, and a large quote with its speaker beside them. Every milestone before the open one shows a check, as a step that is already behind the team, and the rail's markers are foreground, never the primary colour. The rail is built from Steps, the panel from Avatar and Badge, and the lines from Guides, so every colour comes from your theme's tokens. There is no autoplay and no dates, only relative moments that never go stale. Made for customer stories, onboarding journeys, long-term case studies and any page where how a customer felt over time is the proof.

FAQ

How do I change the milestones and who speaks at each one?

Edit the MILESTONES array at the top of the file. Each milestone has a rail label, a short headline, the quote and the speaker's name, initials and role. The rail grows or shrinks with the array, and OPENING is the index the page opens on; the milestones before it show their check. Keep the labels relative ("Month 6", not a calendar date) so the block never goes out of date.

How do keyboards and screen readers use the rail?

The rail is one tab stop. Arrow keys, Home and End move focus between the milestones, and Enter or Space opens the one that has focus, so a quote never changes just because focus passed over it. Each milestone is a tab that opens a labelled panel, and the panel's headline is an h3 under the section's h2. The numbers in the circles are decoration; the milestone's name is what is read out.

How is the frame drawn?

The page spine (Guides bleed marks="top" rules="top") draws the rails and the top rule. The frame is a box inset from the rails with Guides extend="sm" marks="corners", so its four sides run half a rem past the corners with a plus on each; the line between the rail and the panel is a second Guides marks="top" rules="top" sides={false} on the panel's band. The rail's markers and separators use foreground tones (data-complete:bg-foreground), so the button is the only element in your primary colour.

Why do some milestones show a check?

The check is the Steps component's mark for a step that is behind the current one: opening Month 1 puts a check on Day 1 and Week 2, and opening Day 1 clears them all. It tells the visitor how far into the story they are, and nothing is saved between visits.

How does the rail fit a phone, and a right-to-left page?

Under the sm breakpoint the milestone names are hidden visually and the rail keeps its five numbered circles, so it never scrolls sideways at 320px; the open panel starts with a badge that names the milestone, and screen readers still hear each name on the rail. The panel's two columns stack, and it is the same height for every milestone, so nothing below it moves when you switch. In a right-to-left page, set dir="rtl" and your direction provider: the rail, its separators and the arrow keys mirror, and each quote stays in a bdi, so its quotation marks keep their place.

Does anything animate, and is it safe for reduced motion?

The header and the frame fade up once on load, and a newly opened quote fades in over 300ms. All of it is CSS, and under reduced motion each part simply appears. Nothing plays by itself, so there is nothing to pause.

  • Pro

    A zigzag story rail with four stage bands between the page's rails, from Evaluating to Steady state: a centre line with a dot on each rule, and each stage's name and its quote swapping sides row by row on wide screens, stacked on phones. A Shine Button sits in the header.

  • Pro

    A year in four quarters for a deploy platform, in a card in card: a Q1 to Q4 bar filled up to the chosen quarter, and under it that quarter's quote beside its deploys and uptime.

  • Pro

    Two quotes from one customer, the first week and month six, as two cells with a connector between them that holds the person and what changed, each change worked out from its before and after.

  • Pro

    Icon tabs in the header row that switch customer quotes by industry: four sectors, each a panel of three cells (the typical rollout time and two quotes) above a band with a Shine Button.

  • Pro

    Timeline Hero

    Updates and timelines

    A start-aligned hero with a headline, a Shine Button and an outline action over a closing band of four milestone rows on a vertical hairline, shipped, current and planned.

  • Pro

    Animated Count Testimonials

    Results and figures

    Three headline figures that count up to their totals when the section loads, in one hairline band with a Replay button that runs the count again, and two customer quotes in a second band beneath.