# Stretch Index: Customer Stories

> A product site's customer stories. Move down the list: a row opens once the pointer settles, so a quick sweep doesn't make the list ripple. Each company's tab warms to its own color and opens into a photo, and the whole row links to the story.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/stretch-index-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/stretch-index-demo
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/keyframeui/stretch-index-demo-light-3062401b6290e0f3.png
- Registry item: https://keyframeui.com/r/stretch-index-demo.json
- Categories: list, hover, layout
- Listed: 2026-10-14, source last changed 2026-10-15

## Install

```bash
npx shadcn@latest add https://keyframeui.com/r/stretch-index-demo.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://keyframeui.com/r/stretch-index.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/stretch-index#stretch-index-demo

## Files

### `registry/demos/stretch-index-demo.tsx`

```tsx
import { StretchIndex, StretchIndexItem } from "@/components/ui/stretch-index";

const stories = [
  {
    title: "A bank that now ships every Friday",
    company: "Halcyon Bank",
    text: "Thirty engineers moved from quarterly release trains to weekly ones, without a rollback in the first year.",
    result: "52 releases in 2025",
    photo: "1460925895917-afdab827c52f",
    accent: "#5b8def",
  },
  {
    title: "One booking system for forty restaurants",
    company: "Common Table",
    text: "Hosts used to juggle three tools a night. Now every table, waitlist and deposit runs through one screen.",
    result: "38% fewer no-shows",
    photo: "1517248135467-4c7edcad34c4",
    accent: "#e08a4f",
  },
  {
    title: "Checkout, rebuilt for the phone first",
    company: "Fern & Pilot",
    text: "Two thirds of orders come from phones. A one-page checkout took paying from three minutes to forty seconds.",
    result: "21% more completed orders",
    photo: "1586953208448-b95a79798f07",
    accent: "#3fae7a",
  },
  {
    title: "Eleven designers, one library",
    company: "Northstar",
    text: "Six drifting UI kits became one shared library that engineers pull from directly, so mockups and code finally match.",
    result: "6 kits down to 1",
    photo: "1558655146-d09347e92766",
    accent: "#a77df0",
  },
  {
    title: "Code review in half the time",
    company: "Relay",
    text: "A team across nine time zones switched to smaller pull requests and recorded walkthroughs, and stopped waiting a day for review.",
    result: "Reviews 2× faster",
    photo: "1519389950473-47ba0277781c",
    accent: "#e5b93f",
  },
];

const photo = (id: string) =>
  `https://images.unsplash.com/photo-${id}?auto=format&fit=crop&w=480&h=360&q=80`;

const slug = (company: string) => company.toLowerCase().replace(/[^a-z0-9]+/g, "-");

export function StretchIndexDemo() {
  return (
    <section className="w-full max-w-3xl text-zinc-900 dark:text-zinc-50">
      <div className="mb-6 flex items-end justify-between gap-4">
        <div>
          <p className="font-mono text-xs tracking-widest text-zinc-500 uppercase">
            Customer stories
          </p>
          <h3 className="mt-2 text-2xl font-semibold tracking-tight">
            What changed after they switched
          </h3>
        </div>
        <p className="hidden font-mono text-xs text-zinc-500 tabular-nums sm:block">
          {stories.length} stories
        </p>
      </div>

      <StretchIndex defaultIndex={0} className="border-t border-current/10">
        {stories.map((story) => (
          <StretchIndexItem
            key={story.company}
            title={story.title}
            meta={story.company}
            href={`#${slug(story.company)}`}
            image={photo(story.photo)}
            accent={story.accent}
          >
            <p className="max-w-md text-pretty text-zinc-600 dark:text-zinc-400">{story.text}</p>
            <div className="mt-3 flex flex-wrap items-center gap-x-4 gap-y-1 text-sm">
              <span className="font-medium tabular-nums">{story.result}</span>
              <a
                href={`#${slug(story.company)}`}
                className="rounded-sm font-medium text-zinc-500 underline-offset-4 outline-none hover:text-current hover:underline focus-visible:ring-2 focus-visible:ring-current"
              >
                Read the story <span aria-hidden>→</span>
              </a>
            </div>
          </StretchIndexItem>
        ))}
      </StretchIndex>
    </section>
  );
}
```
