Quote & Result Columns
Static testimonial columns React component, each with a key quote and a results figure; on entry the dividers draw down, the figures count up from zero and the columns appear in sequence, under an optional generative contour backdrop.
Customer testimonials as "one complete case summary per column": each column opens with a large results figure (such as +38%) and its label, followed by a short rule, the quote and an author row. No scrolling, no carousel, no switching — the content sits side by side and the numbers lead. On entry the dividers draw from the top down and the columns appear in sequence, and each figure counts up from 0 once its column has appeared; an optional faint contour backdrop, generated from seed, draws once across the top of the section. Wide screens show 2, 3 or 4 columns; narrow screens stack automatically and switch to horizontal dividers.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add quote-result-columns.enPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<QuoteResultColumns/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
Installation
npx webberui@latest add https://webberui.com/r/quote-result-columns.en.jsonOr, once registries are configured in components.json, install it as @webberui/quote-result-columns.
Usage
import { QuoteResultColumns } from "@/components/ui/quote-result-columns";
<QuoteResultColumns
eyebrow="Results"
title="Let the numbers speak"
columns={3}
testimonials={[
{
quote: "Once checkout flowed smoothly, far fewer carts were abandoned.",
highlight: "checkout flowed smoothly",
name: "Maya Lin",
role: "Head of Ecommerce",
company: "Islet Coffee",
metric: { value: "+38%", label: "Order conversion" },
},
{
quote: "Drivers see reassignments on the road, and steady on-time rates brought us new routes.",
name: "Ethan Chen",
role: "Operations Manager",
company: "Polaris Freight",
metric: { value: "-27%", label: "Average delivery time" },
},
{
quote: "Tutors step in before learners get stuck, and re-enrolment fills earlier.",
name: "Grace Chang",
role: "Director of Studies",
company: "Lumen Academy",
metric: { value: "2.4x", label: "Course completion" },
},
]}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
testimonials | QuoteResultColumnsItem[] | — | Testimonials, one per column; wraps onto new rows past the column count |
eyebrow | ReactNode | — | Small label above the title |
title | ReactNode | "Customer results" | Section title, also the accessible name of the section (the Chinese build defaults to "客戶成效" (customer results)) |
subtitle | ReactNode | — | Supporting text below the title |
columns | 2 | 3 | 4 | 3 | Columns on wide screens; 4 lays out as 2 columns at medium widths, and narrow screens always stack |
seed | number | 2 | Seed for the contour backdrop; the same seed always draws the same curves |
showBackdrop | boolean | true | Whether to show the generative contour backdrop at the top of the section |
stagger | number | — | Delay between columns appearing (ms); falls back to --wb-quote-result-columns-stagger (default 120ms) |
duration | number | — | Entrance duration of each column (ms); falls back to --wb-quote-result-columns-duration (default 600ms) |
className | string | — | Merged into the root section |
QuoteResultColumnsItem
| Field | Type | Default | Description |
|---|---|---|---|
quote | string | — | Full quote text |
name | string | — | Customer name; the avatar shows initials (last two characters for Chinese names, first letters for Latin names) |
role | string | — | Job title |
company | string | — | Company name, joined to the role with " · " |
rating | number | — | Rating (0–5); not rendered here, kept for the shared data shape |
avatarHue | number | — | Avatar gradient hue (0–360); defaults to a golden-angle (137.508°) step based on the index |
highlight | string | — | Fragment of the quote to highlight; must match the quote exactly |
metric | { value: string; label: string } | — | Results figure and label; strongly recommended — without it the column shows a large quote mark instead |
CSS variables
| Variable | Default | Description |
|---|---|---|
--wb-quote-result-columns-accent | #0d9488 (dark #2dd4bf) | Accent for the figures, eyebrow, quote mark and highlight tint |
--wb-quote-result-columns-stagger | 120ms | Delay between columns appearing |
--wb-quote-result-columns-duration | 600ms | Entrance duration of each column |
How it works
- The count-up parses the first number in
metric.valuealong with its prefix and suffix:+38%becomes prefix+,38, suffix%;1,200 hrskeeps its thousands separator;2.4xkeeps one decimal place. Values without a number (such as "Fully live") are shown as-is with no count. - Counting starts only after the column has finished appearing and runs for 1200ms with easeOut; server rendering and the pre-entrance state output the final value, so search engines and no-JavaScript readers get the full figure.
- The contour backdrop builds 6 smooth curves from
seedwith a deterministic pseudo-random generator — noMath.random— so SSR and client match; it draws once over 1600ms on entry and fades out at the bottom with a mask. - Column dividers are vertical on wide screens (drawn top-down over 600ms) and become horizontal when stacked; with
columnsset to4, medium widths use a 2×2 layout and the dividers move to match. - The entrance plays once (
useInViewonce, 20% visible); remount with akeyto replay it.
Accessibility
- The root is a
sectionlabelled by itsh2title viaaria-labelledby - Each column is a
figure, with the quote in ablockquoteand the name, role and company in afigcaption - The counting figure is hidden from assistive tech and the final value is provided as visually hidden text, so screen readers announce only the final result
- Avatar initials, dividers, the quote mark and the contour backdrop are decorative and set
aria-hidden - When the user's system has reduce motion enabled, columns fade in over 150ms with no movement, dividers appear immediately, figures show their final value without counting, and the contours fade in
3D Tilt Review Card
A slightly askew testimonial card that tilts in 3D perspective with a moving sheen as the pointer moves, the quote floating above the surface, flipping over to switch entries.
Numbered Quote Slider
Large 01/02/03 numerals on the left roll digit by digit while the quote on the right slides in from the direction of travel, with drag, arrow-key navigation and a progress fraction.