SIG—15 Signature system
Gallery
A justified photo grid whose photos open from exactly where they sit: swipe to travel, pull down to put one back, pinch or double-tap to look closer.
Live — this one is real
Open a plate and it lifts out of the grid. Swipe or use ← → to travel, pull down or press Esc to put it back; pinch, Ctrl-scroll or double-tap to zoom. Plates are drawn in the browser.
Usage
import { Gallery } from "mizu-ui";
export function Example() {
return (
<Gallery
label="Field studies"
rowHeight={160}
items={[
{
id: "ink",
src: "/images/field.svg",
alt: "Diamond field on ink",
width: 720,
height: 360,
caption: "Field, ink",
},
{
id: "paper",
src: "/images/field-light.svg",
alt: "Diamond field on paper",
width: 720,
height: 360,
caption: "Field, paper",
},
]}
/>
);
}
This code, running — no configuration beyond the data
Keyboard
- ←→
- Previous or next photo, in the grid or viewer
- ↑↓
- The row above or below, in the grid
- HomeEnd
- First or last photo
- +−0
- Zoom in, out, or back to fit
- Esc
- Put the photo back
Source & setup
Add this component to your project with the shadcn CLI. The command copies its source and styles into your configured UI directory.
npx shadcn@latest add 0xuser64bit/mizu/galleryFor npm imports, import mizu-ui/styles.css once. Fonts are optional via mizu-ui/fonts.css. Override --mizu-* tokens or use className for local styling. Requires React and Motion.
Inspect signature/Gallery.tsx
Source is included in the npm package under src/signature/Gallery.tsx.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| label / items | string / GalleryItem[] | — | Region name; each photo has an id, src, alt, width and height, with an optional thumbnail and caption. |
| index / defaultIndex / onIndexChange | number | null | — | The open photo, or null while the viewer is closed. |
| rowHeight / gap | number | — | Rows aim for this height (220) and full rows adjust to fill the width exactly; gap defaults to 6. |
| loading / empty | boolean / ReactNode | — | Skeleton rows with a scan line, or what to show when there are no photos. |
| justifyRows() | (sizes, width, target, gap) => Row[] | — | The layout on its own, for server rendering or grids of your own. |
Accessibility
Photos are buttons named by their alt text, in a list; arrow keys move between them, up and down by row. The viewer is a native modal dialog: the page goes inert and stops scrolling, Escape closes, and focus returns to the photo you closed on. Position and alt text are announced as you travel, and every gesture also has a key or a button.
Motion
A photo flies out of its tile into the viewer, and back into the tile of whichever photo you close on. Swipes follow your finger with resistance at the ends; pulling down shrinks the photo and thins the backdrop until it lets go. Zoom springs around the point you pinch, scroll or double-tap. Reduced motion trades the flight for a short fade.