Command Palette

Search for a command to run...

Docs
Case Study Tabs

Case Study Tabs

A tabbed customer-testimonial block with embossed stars, brand-logo tabs, an animated underline indicator that adopts each brand's accent color, a featured case-study paragraph with CTA, and a pull-quote with author.

Installation

Usage

import {
  CaseStudyTabs,
  type CaseStudy,
} from "@/components/ruixen/case-study-tabs";
 
const cases: CaseStudy[] = [
  {
    brand: {
      id: "stripe",
      name: "Stripe",
      logo: <StripeLogo />,
      accentColor: "#635BFF",
    },
    headline:
      "Stripe leveraged our platform to streamline payment processing workflows, resulting in a 40% reduction in integration time for new merchants.",
    cta: { label: "Read Case Study", href: "/case-studies/stripe" },
    quote:
      "The platform has dramatically improved our payment processing capabilities. The developer experience is exceptional.",
    author: {
      name: "Bernard Ngandu",
      role: "Backend Engineer, Stripe",
      avatarUrl: "https://avatars.githubusercontent.com/u/31113941?v=4",
    },
  },
  // ...more cases
];
 
export default function Page() {
  return <CaseStudyTabs cases={cases} />;
}

Props

PropTypeDefaultDescription
casesCaseStudy[]RequiredOne tab per case study. The first case is active by default.
defaultCaseIdstringFirst case idPre-select a specific tab on mount.
starCountnumber5Embossed white-on-white stars rendered above the tabs. 0 hides them.
classNamestring-Extra classes appended to the outer <section>.

CaseStudy

FieldTypeDescription
brandCaseStudyTabsBrandTab id, name, logo node, and optional accentColor.
headlineReactNode (optional)Large featured paragraph for the active case. Omit to render testimonial-only.
cta{ label: string; href: string }Optional "Read case study" link.
quoteReactNodePull-quote rendered with curly-quote pseudo-elements.
authorCaseStudyAuthorName, role, and avatarUrl or avatarFallback.

CaseStudyTabsBrand

FieldTypeDescription
idstringUnique tab id used by Radix Tabs.
namestringAccessible label for screen readers.
logoReactNodeLogo node — usually an inline SVG sized via h-auto w-12.
accentColorstringCSS color for the animated underline. Defaults to currentColor.

Features

  • Animated underline indicator — measures the active tab's offsetLeft and offsetWidth with a useLayoutEffect + ResizeObserver, then slides between tabs via a single absolutely-positioned <span> with a 300 ms transform/width transition. The line takes on each brand's accentColor.
  • Embossed stars — white-on-white stars with a soft drop-shadow give a subtle "5-star" header. Set starCount={0} to hide.
  • Masked border — the top/bottom border around the tab bar fades to transparent at both ends using a linear-gradient mask. Works in both Tailwind v3 and v4 via arbitrary [mask-image:...] syntax.
  • Brand-tinted active tab — only the underline carries the brand color; the tab itself stays neutral, keeping the layout calm.
  • Curly pull-quotes — the quote paragraph uses ::before and ::after pseudo-elements with literal " / " curly quotes.
  • Theme adaptive — uses bg-background, text-foreground, text-muted-foreground, bg-card, border-foreground/10 and friends; light/dark inversion is automatic. Brand logo colors are baked into the SVGs you pass in.
  • Single shadcn dep — only tabs from registryDependencies; lucide-react is the only npm dep.