Client Stories

Stories

Ordinarypeople.Quiet,stubbornchange.

Nobody here arrived with a plan. They arrived tired, or lost, or simply curious, and stayed long enough for something to shift.

All stories
A rocky cove with wildflowers above turquoise water

Learning to stop at the end of the day

I came in because I could not switch off. Six months later I still work hard, but the work stays at the desk. Nobody fixed me. I just slowly stopped needing to be fixed.

Agnes Obel

Eighteen months with the practice

Read the full story
A long sandy beach with a boat on the horizon

Starting again at forty-three

After the divorce I did not know which parts of me were mine. The sessions gave me somewhere to lay everything out and pick up only what I wanted to carry.

Nils Frahm

Weekly sessions, online

Read the full story
About this block

Client StoriesPRO

Long-form testimonials told as stories: a serif heading settling in word by word beside the intro and a pill action, then alternating rows that pair a drifting portrait photograph with a story title, a serif quote, the person, and a link to the full account.

Testimonial48: Client Stories

Client stories as alternating rows: each pairs a portrait that drifts inside its frame with a small-caps story title, a serif quote, an attribution and a link to the full account.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/testimonial48?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/testimonial48?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/testimonial48.tsx plus the button22 sliding-marker pill and the text1 word stagger it uses.

Quick start

The installed file exports testimonial48Demo alongside the block: the exact props behind the preview above. Spread it to get a working stories section in one line.

tsx
import { Testimonial48, testimonial48Demo } from "@/components/beste/block/testimonial48";

export default function Page() {
  return <Testimonial48 {...testimonial48Demo} />;
}

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsx
import { Testimonial48 } from "@/components/beste/block/testimonial48";

export default function Page() {
  return (
    <Testimonial48
      eyebrow="Stories"
      heading="Ordinary people. Quiet, stubborn change."
      description="Nobody here arrived with a plan."
      button={{ label: "All stories", href: "/stories", tone: "outline" }}
      stories={[
        {
          title: "Learning to stop at the end of the day",
          quote: "I came in because I could not switch off. Six months later the work stays at the desk.",
          name: "Agnes Obel",
          context: "Eighteen months with the practice",
          href: "/stories/agnes",
          image: { src: "/people/agnes.jpg", alt: "Portrait of a client" },
        },
      ]}
      labels={{ readStory: "Read the story" }}
    />
  );
}

Props

PropTypeDefaultDescription
eyebrowstringSmall-caps line above the heading
headingstringSection heading, rendered as an h2 through Text1
descriptionstringIntro beside the heading
buttonActionButtonPill action under the intro
storiesStory[][]Story rows, alternating sides
labels{ readStory?: string }{}Link wording; the link is dropped when unset
classNamestringExtra classes for the outer <section>
ts
type Story = {
  title: string;
  quote: string;
  name: string;
  context: string;
  href: string;
  image: { src: string; alt: string };
};

type ActionButton = {
  label: string;
  href: string;
  tone?: "primary" | "light" | "dark" | "outline";
};

Behavior notes

  • The alternation uses explicit md:col-start values on index % 2 while both cells stay in md:row-start-1, so the sides flip without the DOM order changing; the portrait always comes first in the markup, which keeps the reading order sane on every row.
  • Below md those column starts drop away and every row stacks portrait-then-quote, so the alternation never produces an inconsistent order on a phone.
  • Quotes are real blockquote elements inside article wrappers, so the words are marked up as quoted material rather than as styled paragraphs.
  • Each title is a separate small-caps line above the quote, so a long story can be summarised without turning the quote itself into a heading.
  • Every portrait owns its own scroll listener, so the rows do not drift in lockstep.
  • Rows are spaced with a gap-20 growing to gap-32 rather than rules, so the section reads as a sequence of scenes.
  • The story link's arrow lifts only under motion-safe:, so the affordance is dropped for reduced motion while the link keeps working.

More Testimonial blocks

View all Testimonial
PRO

testimonial53

Portrait and Long Quote

One long testimonial beside a portrait: the photograph drifts inside its frame on the left while a serif quote settles in word by word on the right, closed by a ruled row with the speaker's name, context and a sliding-marker pill.

PRO

testimonial51

Single Voice

One centred testimonial: a long serif quote that settles in word by word, the speaker's portrait, name and context beneath it, and a sliding-marker pill.

PRO

testimonial54

Three Ruled Quotes

Three short testimonials in ruled columns, each a serif quote with a name and context, under a serif heading that settles in word by word and a sliding-marker pill.

PRO

testimonial44

Portrait Customer Story

A single customer story that sets a tall portrait with a gradient name card beside an oversized light quote, a hairline row of three proof figures, and a link into the full write-up.

PRO

testimonial50

Three Voices

A rotating testimonial: a portrait on the left and a large serif quote on the right blur out and in together every six seconds, pause on hover, and can be chosen directly from a row of round portrait buttons, with a pill action beneath.

PRO

testimonial31

Stats With Testimonial Gallery

Centered header above a stats rail beside an expanding portrait gallery — hovering a person widens their frame and reveals their quote while the others contract.