Command Palette

Search for a command to run...

Docs
Featured Portrait Testimonial

Featured Portrait Testimonial

An expanding-portrait testimonial carousel where inactive cards show a grayscale portrait with a name strip, and the active card morphs into a full quote card with author, dashed divider, and a row of favorite-feature tags. Width transitions and content crossfade are choreographed for clean, premium movement.

Installation

Usage

import { GitBranch, Workflow, Zap } from "lucide-react";
import {
  FeaturedPortraitTestimonial,
  type FeaturedPortraitItem,
} from "@/components/ruixen/featured-portrait-testimonial";
 
const items: FeaturedPortraitItem[] = [
  {
    id: "sahil",
    quote:
      "Ruixen is the first component library that feels truly modern. It's powerful, flexible, and fast to build with.",
    author: {
      name: "Sahil Mansuri",
      role: "CEO & Head of Finance",
      avatarUrl: "/avatar-images/avatar-04.jpg",
    },
    portraitUrl: "/avatar-images/avatar-04.jpg",
    company: { name: "Pipeliner", logo: <Workflow /> },
    favorites: [
      { icon: <Zap />, label: "Automation" },
      { icon: <GitBranch />, label: "Pipeline" },
    ],
  },
  // ...more items
];
 
export default function Page() {
  return (
    <FeaturedPortraitTestimonial
      eyebrow="Testimonials"
      heading="Their favorites feature"
      description="Leverage insights from your business, customer, and product data to drive and enhance your team's performance and success."
      items={items}
    />
  );
}

Props

PropTypeDefaultDescription
itemsFeaturedPortraitItem[]RequiredOne entry per testimonial slide.
eyebrowReactNode-Small pill rendered above the heading (e.g. "Testimonials").
headingReactNode-Section heading.
descriptionReactNode-Section description.
favoritesLabelReactNode"Favorites Feature"Caption rendered above the favorites tag row in the active card.
activeWidthnumber580Width of the active (expanded) card in pixels on lg+ viewports.
inactiveWidthnumber280Width of inactive (portrait) cards in pixels on lg+ viewports.
cardHeightnumber380Shared card height in pixels.
defaultIndexnumber0Initial active item.
classNamestring-Extra classes appended to the outer <section>.

FeaturedPortraitItem

FieldTypeDescription
idstringStable React key.
quoteReactNodePull-quote rendered in the active card.
author{ name; role; avatarUrl? }Author shown both in the active card body and in the inactive footer strip.
portraitUrlstringLarge portrait image rendered when the card is collapsed (recommend ~3:4 aspect).
company{ name?; logo? }Optional inactive-footer subtitle and a tiny logo bubble drawn to the left of the avatar.
favoritesFeaturedPortraitFavorite[]Feature tags rendered below the dashed divider in the active card. Optional.
accentClassNamestringTailwind class overriding the soft-lavender active-card background.

FeaturedPortraitFavorite

FieldTypeDescription
iconReactNodeLeading icon (e.g. a lucide-react).
labelReactNodeTag label.

Features

  • Expanding portrait — inactive cards render the testimonial as a grayscale portrait with a small footer strip; the active card morphs into a full quote card with avatar, dashed divider, and favorite-feature tags.
  • Choreographed crossfade — portrait fades out, then the quote fades in (250ms stagger). Reversing direction simply mirrors the timing, so consecutive selections never overlap.
  • Translated row — the active card always lands at the left of the viewport via translate3d, so cards before it scroll out and cards after stay visible to the right.
  • Click-to-expand — clicking any inactive card promotes it to the active position. Prev/Next buttons round-trip through the list.
  • Keyboard navigationArrowLeft / ArrowRight cycle through items when the carousel viewport is focused.
  • Responsive widths — cards scale down at sm / md so the carousel never overflows awkwardly on narrow screens.
  • Theme tokens only — uses bg-card, border-border, text-foreground, etc. The active-card lavender wash is overrideable per item via accentClassName.
  • Zero motion deps — pure CSS transitions on width, transform, and opacity with a unified cubic-bezier(0.32, 0.72, 0, 1) easing.