# Product Gallery

Swipeable photo gallery for product and listing pages, with thumbnails, page dots that stretch with your finger and double-tap zoom. Colour swatches jump straight to the matching photos.

> Composed · Pro · Data Display — React Native, Expo Go compatible.

## Install

```bash
npx @lumioui/cli add pro/product-gallery
```

## Import

```tsx
import { useProductGallery, ProductGallery } from "@/components/ui/product-gallery/product-gallery";
```

## Variants

- `fashion` — Colour-linked swatches: `npx @lumioui/cli add pro/product-gallery-fashion`
- `hotel` — Full-bleed parallax hero: `npx @lumioui/cli add pro/product-gallery-hotel`
- `marketplace` — Thumbnail rail: `npx @lumioui/cli add pro/product-gallery-marketplace`
- `property` — Room chips and photo count: `npx @lumioui/cli add pro/product-gallery-property`

## Props

### ProductGallery

| Prop | Type | Notes |
| --- | --- | --- |
| `images` | `ProductGalleryImage[]` | — |
| `index?` | `number` | Controlled page (0-based). |
| `defaultIndex?` | `number` | Uncontrolled initial page. Default 0. |
| `onIndexChange?` | `(index: number) => void` | Fires when the visible page changes (swipe, thumbnail, swatch, group). |
| `className?` | `string` | — |
| `children?` | `React.ReactNode` | — |

### ProductGalleryPager

| Prop | Type | Notes |
| --- | --- | --- |
| `height?` | `number` | Page height in points. Default 440. |
| `zoom?` | `boolean` | Double-tap to zoom. Default true. |
| `onImagePress?` | `(index: number) => void` | Tap (not double-tap) on a photo — open a full-screen viewer. |
| `scrollY?` | `SharedValue<number>` | Vertical offset of the page's outer scroll view (UI-thread). When set, pulling down stretches the photo from its top edge and scrolling up moves it at half speed — the full-bleed detail-page hero. |
| `className?` | `string` | Container classes — rounding, margins. |
| `imageClassName?` | `string` | Classes for every photo. |
| `children?` | `React.ReactNode` | Overlay parts (Count, Indicator, ZoomHint, buttons) floating on the photo. |

### ProductGalleryIndicator

| Prop | Type | Notes |
| --- | --- | --- |
| `variant?` | `"pill" | "dot"` | "pill" stretches the active dot; "dot" is the plain page control. |
| `className?` | `string` | — |

### ProductGalleryCount

| Prop | Type | Notes |
| --- | --- | --- |
| `icon?` | `IconName` | Leading glyph, e.g. "image" for a listing's photo count. |
| `className?` | `string` | — |

### ProductGalleryZoomHint

| Prop | Type | Notes |
| --- | --- | --- |
| `label?` | `string` | — |
| `className?` | `string` | — |

### ProductGalleryThumbnails

| Prop | Type | Notes |
| --- | --- | --- |
| `size?` | `number` | Thumbnail edge in points. Default 64. |
| `inset?` | `number` | Horizontal inset of the rail's content. Default 16. |
| `className?` | `string` | — |

### ProductGallerySwatches

| Prop | Type | Notes |
| --- | --- | --- |
| `swatches` | `ProductGallerySwatch[]` | — |
| `label?` | `string` | Header label. Default "Colour". |
| `onSwatchChange?` | `(value: string) => void` | Fires when a swatch is picked (the gallery pages to it). |
| `headerAction?` | `React.ReactNode` | Right side of the header (size guide link…). |
| `className?` | `string` | — |

### ProductGalleryStage

| Prop | Type | Notes |
| --- | --- | --- |
| `strength?` | `number` | Wash strength override (0–1). Default 0.2 light / 0.3 dark. |
| `className?` | `string` | — |
| `children?` | `React.ReactNode` | — |

### ProductGalleryGroups

| Prop | Type | Notes |
| --- | --- | --- |
| `showCount?` | `boolean` | Show the photo count after each label ("Kitchen 4"). Default true. |
| `inset?` | `number` | Horizontal inset of the chip row. Default 16. |
| `className?` | `string` | — |

## Icons rendered

- `maximize` — /icons.html?i=maximize

Source: https://lumioui.com/components/product-gallery