# Slice Gallery: Hero

> A travel hero that plays on its own: the open slice's strip fills like a story timer, then the next place opens. Hovering pauses it. The counter above follows along through `index` and `onIndexChange`.

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

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

## Install

```bash
npx shadcn@latest add https://keyframeui.com/r/slice-gallery-hero-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/slice-gallery.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/slice-gallery#slice-gallery-hero-demo

## Files

### `registry/demos/slice-gallery-hero-demo.tsx`

```tsx
"use client";

import * as React from "react";

import { SliceGallery, SliceGalleryItem } from "@/components/ui/slice-gallery";

const stays = [
  {
    place: "Kyoto",
    country: "Japan",
    nights: 6,
    price: "€1,480",
    note: "A machiya on a lane behind Yasaka, breakfast in the garden.",
    photo: "1493976040374-85c8e12f0c0e",
    accent: "#f6b38e",
  },
  {
    place: "Banff",
    country: "Canada",
    nights: 5,
    price: "€1,320",
    note: "A lake cabin with canoes at the dock and no signal at all.",
    photo: "1493246507139-91e8fad9978e",
    accent: "#8fd3e6",
  },
  {
    place: "Vík",
    country: "Iceland",
    nights: 4,
    price: "€1,150",
    note: "Black sand, a grey sea and a turf-roofed guesthouse above it.",
    photo: "1500043357865-c6b8827edf10",
    accent: "#d3dbe2",
  },
  {
    place: "Lisbon",
    country: "Portugal",
    nights: 4,
    price: "€890",
    note: "Tiled rooms in Alfama, a short tram ride from the river.",
    photo: "1536663815808-535e2280d2c2",
    accent: "#ffcf8a",
  },
  {
    place: "Big Sur",
    country: "USA",
    nights: 5,
    price: "€1,690",
    note: "Redwoods above the cove and the Pacific under the deck.",
    photo: "1510414842594-a61c69b5ae57",
    accent: "#8fe0c9",
  },
];

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

const pad = (n: number) => String(n).padStart(2, "0");

export function SliceGalleryHeroDemo() {
  const [index, setIndex] = React.useState(0);
  const stay = stays[index];

  return (
    <section className="w-full max-w-5xl">
      <div className="mb-8 grid gap-6 sm:grid-cols-[1fr_auto] sm:items-end">
        <div>
          <p className="font-mono text-xs tracking-widest text-zinc-500 uppercase">
            Small stays, slow trips
          </p>
          <h2 className="mt-3 text-4xl font-semibold tracking-tight text-balance text-zinc-900 sm:text-5xl dark:text-zinc-50">
            Go somewhere quiet.
          </h2>
          <p className="mt-3 max-w-md text-pretty text-zinc-600 dark:text-zinc-400">
            Five places we keep going back to, each with one house we&apos;d book again.
          </p>
        </div>
        <div className="flex items-center gap-5">
          <p aria-live="polite" className="font-mono text-xs text-zinc-500 tabular-nums">
            {pad(index + 1)} / {pad(stays.length)}
            <span className="ml-2 text-zinc-900 dark:text-zinc-100">{stay.place}</span>
          </p>
          <a
            href="#plan"
            className="rounded-full bg-zinc-900 px-5 py-2.5 text-sm font-medium text-white transition-colors outline-none hover:bg-zinc-700 focus-visible:ring-2 focus-visible:ring-zinc-400 focus-visible:ring-offset-2 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-300 dark:focus-visible:ring-offset-zinc-950"
          >
            Plan a trip
          </a>
        </div>
      </div>

      <SliceGallery
        index={index}
        onIndexChange={setIndex}
        autoPlay={5000}
        className="h-[34rem] sm:h-[30rem]"
      >
        {stays.map((item) => (
          <SliceGalleryItem
            key={item.place}
            title={item.place}
            label={item.country}
            image={photo(item.photo)}
            accent={item.accent}
          >
            <p className="max-w-xs text-[15px] leading-snug text-pretty text-white/90">{item.note}</p>
            <p className="mt-3 flex items-baseline gap-2 text-sm text-white/70">
              <span>{item.nights} nights from</span>
              <span className="text-lg font-medium text-white">{item.price}</span>
            </p>
          </SliceGalleryItem>
        ))}
      </SliceGallery>
    </section>
  );
}
```
