# Team Leadership Rows — React Team Section

> Leadership as large typographic rows between hairlines; the hovered or focused row springs open to show a portrait, a quote and a few facts.

- Category: [Team & About](https://pixelpapa.com/components/team.md)
- Tags: team, leadership, rows, accordion, layout
- Dependencies: lucide-react, motion (plus React and Tailwind CSS v4)
- Last updated: 2026-11-13
- Live preview: https://pixelpapa.com/components/team/team-leadership-rows

## Install

```bash
npx shadcn@latest add "https://pixelpapa.com/r/team-leadership-rows.json"
```

The file is written to `components/pixelpapa/team-leadership-rows.tsx`. To install manually, run `npm install lucide-react motion` and copy the source below into your project. It imports `cn` from `@/lib/utils`, which every shadcn project has.

## Source

```tsx
"use client";

import { Plus } from "lucide-react";
import { AnimatePresence, motion } from "motion/react";
import { useState } from "react";
import { cn } from "@/lib/utils";

type Leader = {
  name: string;
  role: string;
  since: string;
  quote: string;
  facts: [string, string][];
  tones: [string, string];
};

const defaultLeaders: Leader[] = [
  {
    name: "Amara Osei",
    role: "Chief Executive",
    since: "2019",
    quote: "We win when a clinic manager goes home at five. Everything else is a vanity metric.",
    facts: [["Before", "Emergency nurse, 8 years"], ["Based in", "Manchester"], ["Ask about", "Night shifts"]],
    tones: ["var(--chart-1)", "var(--chart-3)"],
  },
  {
    name: "Henrik Dahl",
    role: "Chief Technology Officer",
    since: "2019",
    quote: "Boring infrastructure is a feature. Our pager went off four times last year.",
    facts: [["Before", "Payments infrastructure"], ["Based in", "Aarhus"], ["Ask about", "Postgres"]],
    tones: ["var(--chart-2)", "var(--chart-1)"],
  },
  {
    name: "Rosa Calderón",
    role: "Chief Product Officer",
    since: "2021",
    quote: "I sit in a waiting room once a month. It is the best roadmap meeting we have.",
    facts: [["Before", "Design lead, health records"], ["Based in", "Bogotá"], ["Ask about", "Field research"]],
    tones: ["var(--chart-4)", "var(--chart-3)"],
  },
  {
    name: "Wei-Ling Hsu",
    role: "Chief Financial Officer",
    since: "2022",
    quote: "Default alive since month fourteen, and I intend to keep it that way.",
    facts: [["Before", "Audit, then two startups"], ["Based in", "Taipei"], ["Ask about", "Unit economics"]],
    tones: ["var(--chart-5)", "var(--chart-2)"],
  },
];

const initials = (name: string) => name.split(" ").map((p) => p[0]).join("").slice(0, 2);

export default function TeamLeadershipRows({ leaders = defaultLeaders }: { leaders?: Leader[] }) {
  const [active, setActive] = useState(0);

  return (
    <section className="w-full bg-background px-6 py-20">
      <div className="mx-auto max-w-5xl">
        <div className="flex items-baseline justify-between gap-6">
          <h2 className="text-sm font-medium tracking-[0.18em] text-muted-foreground uppercase">Leadership</h2>
          <p className="text-sm text-muted-foreground">Wardly · 4 of 86 people</p>
        </div>

        <ul className="mt-6 border-t border-foreground">
          {leaders.map((l, i) => {
            const open = active === i;
            return (
              <li key={l.name} className="border-b border-border" onPointerEnter={() => setActive(i)}>
                <button
                  type="button"
                  aria-expanded={open}
                  onClick={() => setActive(i)}
                  onFocus={() => setActive(i)}
                  className="grid w-full grid-cols-[2.5rem_1fr_auto] items-center gap-4 py-6 text-left sm:grid-cols-[3.5rem_1.4fr_1fr_auto]"
                >
                  <span className="font-mono text-xs text-muted-foreground">0{i + 1}</span>
                  <motion.span
                    animate={{ x: open ? 8 : 0 }}
                    transition={{ type: "spring", stiffness: 300, damping: 24 }}
                    className={cn(
                      "text-3xl font-semibold tracking-tight transition-colors sm:text-5xl",
                      open ? "text-foreground" : "text-foreground/35",
                    )}
                  >
                    {l.name}
                  </motion.span>
                  <span className="hidden text-sm text-muted-foreground sm:block">{l.role}</span>
                  <motion.span
                    animate={{ rotate: open ? 45 : 0 }}
                    transition={{ type: "spring", stiffness: 300, damping: 20 }}
                    className={cn(
                      "flex size-9 items-center justify-center rounded-full border transition-colors",
                      open ? "border-primary bg-primary text-primary-foreground" : "border-border text-muted-foreground",
                    )}
                  >
                    <Plus className="size-4" />
                  </motion.span>
                </button>
                <AnimatePresence initial={false}>
                  {open && (
                    <motion.div
                      initial={{ height: 0, opacity: 0 }}
                      animate={{ height: "auto", opacity: 1 }}
                      exit={{ height: 0, opacity: 0 }}
                      transition={{ type: "spring", stiffness: 260, damping: 32 }}
                      className="overflow-hidden"
                    >
                      <div className="grid gap-6 pb-8 sm:grid-cols-[3.5rem_10rem_1fr] sm:gap-4">
                        <span className="hidden sm:block" />
                        <motion.div
                          initial={{ scale: 0.85, rotate: -6 }}
                          animate={{ scale: 1, rotate: -2 }}
                          transition={{ type: "spring", stiffness: 200, damping: 16 }}
                          className="relative flex aspect-square w-32 items-end overflow-hidden rounded-2xl p-3 text-white shadow-xl sm:w-36"
                          style={{ background: `linear-gradient(150deg, ${l.tones[0]}, ${l.tones[1]})` }}
                        >
                          <svg viewBox="0 0 100 100" className="absolute inset-0 size-full" aria-hidden>
                            <circle cx="50" cy="42" r="17" fill="white" fillOpacity="0.3" />
                            <path d="M12 104c0-26 16-40 38-40s38 14 38 40Z" fill="white" fillOpacity="0.2" />
                          </svg>
                          <span className="relative font-mono text-xs font-medium">{initials(l.name)}</span>
                        </motion.div>
                        <div>
                          <p className="max-w-xl font-serif text-2xl leading-snug text-foreground italic">“{l.quote}”</p>
                          <dl className="mt-6 flex flex-wrap gap-x-10 gap-y-3 text-sm">
                            {[["Joined", l.since] as [string, string], ...l.facts].map(([k, v]) => (
                              <div key={k}>
                                <dt className="text-xs text-muted-foreground">{k}</dt>
                                <dd className="mt-0.5 font-medium text-foreground">{v}</dd>
                              </div>
                            ))}
                          </dl>
                        </div>
                      </div>
                    </motion.div>
                  )}
                </AnimatePresence>
              </li>
            );
          })}
        </ul>
      </div>
    </section>
  );
}
```

## AI prompt

```text
Add the "Team Leadership Rows" component from PixelPapa UI to this project.

What it is: Leadership as large typographic rows between hairlines; the hovered or focused row springs open to show a portrait, a quote and a few facts.
Category: Team & About. Depends on: lucide-react, motion.

1. Install it with the shadcn CLI:
   npx shadcn@latest add "https://pixelpapa.com/r/team-leadership-rows.json"
   (If the CLI is unavailable, fetch that URL, write files[0].content to components/pixelpapa/team-leadership-rows.tsx and install the listed dependencies.)
2. Import it from "@/components/pixelpapa/team-leadership-rows" and place it where I describe below.
3. Keep its animation timings and accessibility attributes. Replace the demo copy and data with content that fits my product, and use my existing theme tokens (bg-background, text-foreground, bg-primary, border-border) rather than hard-coded colours.

Where to use it: <describe the page and position here>
```

## More team & about

- [About Story Timeline](https://pixelpapa.com/components/team/about-story-timeline.md): Company milestones alternate either side of a centre line that fills as you scroll; each year lights its node and slides its card in from its own side.
- [Team Grid Hover Bio](https://pixelpapa.com/components/team/team-grid-hover-bio.md): A grid of drawn gradient portraits; hovering or focusing a person slides a frosted bio panel up over the portrait while the silhouette drifts back.
- [Team Values And Photos](https://pixelpapa.com/components/team/team-values-and-photos.md) (Pro): A numbered values list that advances on a timer beside a collage of gradient photo tiles; the tiles tied to the active value lift forward while the rest recede.
