Skip to content
All Taste components

Testimonials

Testimonial — video story card

A video poster with a play button beside the pull quote, plus links to a few more short customer films.

video poster · play button · duration chip · more stories row

Jonah PiercePierce Bicycle Works
2:14

Customer film

How a two-person bike shop stopped losing Saturdays to paperwork

“Repairs get invoiced from the workbench, and most people have paid before they’ve wheeled the bike out the door.”

Watch the full story
import { ArrowRight, Play } from "lucide-react";

const film = {
  name: "Jonah Pierce",
  company: "Pierce Bicycle Works",
  duration: "2:14",
  durationLabel: "2 minutes 14 seconds",
  title: "How a two-person bike shop stopped losing Saturdays to paperwork",
  quote: "Repairs get invoiced from the workbench, and most people have paid before they’ve wheeled the bike out the door.",
  href: "/customers/pierce-bicycle-works",
  poster: "/films/pierce-poster.jpg",
};

const moreFilms = [
  { label: "Lin & Co", duration: "1:48", href: "/customers/lin-co" },
  { label: "Romero Events", duration: "3:02", href: "/customers/romero-events" },
];

export function TestimonialVideo({ onPlay }: { onPlay?: () => void }) {
  return (
    <section aria-labelledby="film-title" className="bg-surface px-5 py-16 font-sans sm:px-10 sm:py-20">
      <div className="mx-auto grid max-w-6xl items-center gap-8 md:grid-cols-[1.2fr_1fr] md:gap-14">
        <div className="relative aspect-[16/10] overflow-hidden rounded-xl bg-gradient-to-br from-brand-500 to-brand-900 shadow-2xl">
          <img src={film.poster} alt="" className="absolute inset-0 size-full object-cover" />
          <button
            type="button"
            onClick={onPlay}
            aria-label={"Play " + film.name + "’s story, " + film.durationLabel}
            className="absolute inset-0 m-auto grid size-[76px] place-items-center rounded-full bg-neutral-50/95 pl-1 text-neutral-950 shadow-xl ring-[10px] ring-neutral-50/20 transition hover:scale-105"
          >
            <Play className="size-6 fill-current" aria-hidden />
          </button>
          <div className="absolute inset-x-5 bottom-4 flex items-end justify-between gap-2 text-[13px] text-neutral-50">
            <div>
              <p className="text-sm font-semibold">{film.name}</p>
              <p className="text-neutral-50/80">{film.company}</p>
            </div>
            <span className="rounded-full bg-neutral-950/55 px-2 py-0.5 text-xs tabular-nums">{film.duration}</span>
          </div>
        </div>

        <div className="grid justify-items-start gap-5">
          <p className="text-[13px] font-medium text-primary">Customer film</p>
          <h2 id="film-title" className="text-balance text-2xl font-semibold tracking-tight text-fg sm:text-3xl">{film.title}</h2>
          <blockquote className="text-xl font-medium leading-snug tracking-tight text-fg"><p>“{film.quote}”</p></blockquote>
          <a href={film.href} className="inline-flex items-center gap-1.5 text-sm font-medium text-primary hover:underline">
            Watch the full story <ArrowRight className="size-4" aria-hidden />
          </a>
          <ul aria-label="More customer films" className="flex w-full flex-wrap gap-2 border-t border-border pt-4">
            {moreFilms.map((f) => (
              <li key={f.label}>
                <a href={f.href} className="inline-flex items-center gap-2 rounded-full border border-border py-1.5 pl-1.5 pr-3 text-[13px] text-fg hover:border-border-strong">
                  <span className="grid size-[22px] place-items-center rounded-full bg-primary-soft text-primary-soft-fg"><Play className="size-2.5 fill-current" aria-hidden /></span>
                  {f.label} · {f.duration}
                </a>
              </li>
            ))}
          </ul>
        </div>
      </div>
    </section>
  );
}

The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.