# Swap grid

A shadcn/ui product gallery block for shops and studios: tap a photo card and it grows into a pane with its story while the others swap into a rail.

> For the complete documentation index, see [llms.txt](/llms.txt). Markdown variants are available for the docs, pricing and about pages: append `.md` to the URL or send an `Accept: text/markdown` header (the home page answers the header too). An agent skill is available at [/.well-known/agent-skills/site-skill.md](/.well-known/agent-skills/site-skill.md).

## At a glance

- **Good for:** Product collections and lookbooks for small shops; Studio and agency project indexes; Team, speaker and cast pages with a bio for each person; Menus, rooms or destinations with a story behind each one
- **Category:** E-commerce, Portfolio · **Type:** Gallery · **Style:** Motion, Minimal, Dark mode
- **See it:** [Live preview](https://www.craftui.space/docs/blocks/swap-grid) · [Video](https://pub-52b0d9cec7c64f638ba3f33a29718fa6.r2.dev/Videos_product_cards/gallery-swap-grid.74a310b6.mp4)

## Install

```bash
pnpm dlx shadcn@latest add https://www.craftui.space/r/swap-grid.json
```

This is a paid item (BLK-JNF3JR): the install needs a craftUI plan or a purchase of it. Signed in, the docs page gives your personal install command. Plans: https://www.craftui.space/pricing

## Usage

```tsx
import SwapGrid from "@/components/blocks/swap-grid";

export default function Page() {
  return <SwapGrid />;
}
```

With no props it renders with demo content; pass your own through the props below.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `items` | `SwapGridItem[]` | `built-in demo content` | The cards, in order. Four to six fit best. Defaults to `swapGridItems`, a ceramics shop's collection. |
| `defaultOpen` | `number` | — | The card that's open at first, by its place in `items` (from 0). Defaults to none: all the cards side by side. |
| `onOpenChange` | `(index: number \| null) => void` | — | Called with the open card's place in `items`, or null when all are side by side again. |
| `backLabel` | `string` | `"Back to all"` | What the back button says to screen readers. Defaults to "Back to all". |

It also accepts every `<div>` attribute (`className`, `id`, `aria-*` and so on).

### `SwapGridItem`

| Field | Type | Description |
| --- | --- | --- |
| `image` (required) | `string` | The photo's URL. Portrait photos (about 3:4) fit best; it's cropped to fill each card. |
| `alt` (required) | `string` | What the photo shows, for screen readers. |
| `focus` | `string` | Which part of the photo to keep in view when it's cropped, like CSS `object-position`, e.g. "50% 25%" for a face near the top. Defaults to "50% 50%", the centre. |
| `title` (required) | `string` | The name: a product, a project or a person. Must be unique in the list. |
| `subtitle` | `string` | A short line under the name, e.g. a price, a role or "Residential · Lisbon". |
| `description` | `string` | A sentence or two shown in the pane. |
| `href` | `string` | A link at the bottom of the pane, e.g. a product or case study page. |
| `linkLabel` | `string` | The link's text. Defaults to "Learn more". |

## Files

The install adds:

- `components/blocks/swap-grid.tsx`

npm dependencies (installed for you): `motion`.