Blocks

Testimonial Line Sweep

A paged testimonial pair whose text sweeps out line by line while the portrait irises shut.

A ready-made testimonial section. Two quotes sit side by side, and paging sweeps each line of text up behind its own mask while the portrait irises shut on a circular clip. The incoming quote arrives a beat later the same way, so the two sets never collide. Page with the buttons or the arrow keys. GSAP + SplitText.

New tab

What our clients say about us

Hear from the people who use our platform every day, and see how it's helping them achieve their goals.

We replaced four tools with one workflow, and the team shipped its first release two weeks early. Nobody has asked to go back.

Maya Collins

Maya Collins

Head of Operations

Reporting used to take a full day each month. Now it runs itself and lands in our inbox. That time went straight back into the roadmap.

Ethan Brooks

Ethan Brooks

President of Sales

Onboarding took an afternoon, not a quarter. Every handoff is visible to the whole team, so nothing slips between design and build.

Liam Harper

Liam Harper

Product Lead

Support tickets dropped by a third in one month. Customers find answers before they ask us, and the team finally has room to think.

Ava Sinclair

Ava Sinclair

Marketing Head

Installation

pnpm dlx shadcn@latest add @tween-ui/testimonial-line-sweep

Usage

app/page.tsx
app/page.tsx
import TestimonialLineSweep from '@/components/tweenui/testimonial-line-sweep';
 
export default function Page() {
  return <TestimonialLineSweep />;
}

Pass your own quotes. Each one is split in three so the middle clause can carry the emphasis:

app/page.tsx
app/page.tsx
import TestimonialLineSweep from '@/components/tweenui/testimonial-line-sweep';
 
export default function Page() {
  return (
    <TestimonialLineSweep
      title="What our clients say about us"
      items={[
        {
          quoteStart: 'We replaced four tools with one workflow, and',
          quoteHighlight: 'the team shipped its first release two weeks early.',
          quoteEnd: 'Nobody has asked to go back.',
          name: 'Maya Collins',
          jobTitle: 'Head of Operations',
          image: '/people/maya.jpg',
        },
        {
          quoteStart: 'Reporting used to take a full day each month.',
          quoteHighlight: 'Now it runs itself and lands in our inbox.',
          quoteEnd: 'That time went back into the roadmap.',
          name: 'Ethan Brooks',
          jobTitle: 'President of Sales',
          image: '/people/ethan.jpg',
        },
      ]}
    />
  );
}

Props

PropTypeDefaultDescription
titleReactNodesample headingSection heading.
descriptionstringsample lineSupporting line under the heading.
itemsTestimonialLineSweepItem[]four quotesQuotes to page through, two at a time.

Extends native <section> attributes (className, style, …).

TestimonialLineSweepItem

FieldTypeDescription
quoteStart · quoteHighlight · quoteEndstringThe quote, split so the middle clause reads darker.
name · jobTitlestringReviewer identity.
image · imageAltstringPortrait; imageAlt falls back to name.

Two quotes are shown per page from md up and one below it, so pass an even number of items for full pages on desktop. Four is the default.

Accessibility

Off-page quotes are aria-hidden and unfocusable, so a screen reader only meets the pair on screen. Both paging buttons are labelled, and the arrow keys page only while the section is in view — they never hijack the page from elsewhere. Under prefers-reduced-motion: reduce the lines are not split at all and pages simply cross-fade.