# Horizontal gallery (goodtabs UI)

Vertical scroll moves a pinned horizontal track, a native snap scroller on phones.

## Install

```bash
npx shadcn@latest add https://ui.goodtabs.co/r/horizontal-gallery.json
```

Or, with the @goodtabs namespace configured in components.json: `npx shadcn@latest add @goodtabs/horizontal-gallery`

## Usage

```tsx
import { HorizontalGallery, HorizontalGalleryItem } from "@/components/ui/horizontal-gallery"

<HorizontalGallery aria-label="Recent work">
  <HorizontalGalleryItem src="/one.jpg" title="First piece" meta="2026" />
  <HorizontalGalleryItem src="/two.jpg" title="Second piece" meta="2026" />
</HorizontalGallery>
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| aria-label | `string` |  | Names the focusable region on HorizontalGallery, required. |
| pace | `number` | `1` | Page scroll per pixel of track on HorizontalGallery. |
| src | `string` |  | An image on HorizontalGalleryItem. Leave it out for a text tile. |
| alt | `string` | `""` | Describes the image. |
| title | `ReactNode` |  | The caption under the image. |
| meta | `string` |  | A short mono label at the end of the caption. |
| children | `ReactNode` |  | Anything else in the item, such as the copy in a text tile. |

## When to use

- A sequence of images that reads better as a strip than a grid
- Portfolio work, case studies or a product tour with four to eight stops
- Once on a page, as a change of direction

## When not to use

- For items people need to compare: a grid shows them all at once
- More than twelve items, because the pin gets long
- Inside a scaled or transformed parent, which breaks ScrollTrigger's measuring

## Notes for agents

- GSAP installs from npm under GSAP's own licence. No GSAP code ships in this registry
- aria-label is required: the root is a focusable region with tabIndex 0 so keyboards can scroll it
- Below 768px, under reduced motion and with no script it is a native horizontal scroller with snap
- While pinned, focus inside an unseen item scrolls the page to that item

## The maths

- Pin distance equals track width minus viewport width, so at pace 1 one pixel of wheel moves the track one pixel.
- Images hang 10% past each side of the frame, so a pan of 10 / 120 = 8.33% of the image width is 10% of the frame and shows no edge.

Docs: https://ui.goodtabs.co/components/horizontal-gallery