Photo Album React component
A bound photo album with a linen cover that opens and pages that turn in 3D: drag or tap to turn, the page lifts when you near its edge, line indicators jump between spreads, and a captioned lightbox opens on any photo.
About the Photo Album component
Photo Album presents a set of photos as a bound book. It opens from a linen cover with a photo window, and each page turns around the spine in 3D with shading that follows the fold, so flipping through it feels like handling a real album.
Drag to turn a page (a quick flick finishes the turn), tap the left or right page to step, or use the arrow keys once it has focus. Pages lift slightly when the pointer nears their outer edge, the line indicators under the book jump straight to any spread, and tapping a photo opens a captioned lightbox.
When to use it
Use it for a story told in order: a trip, a wedding, a year in photos, a lookbook or a project diary, where captions and dates matter and the turning itself is part of the charm.
For a large set that people want to scan quickly, a grid or masonry gallery serves better; an album shows two photos at a time.
Installation
Add the Photo Album component to your project with the shadcn CLI. It lands in components/photo-album.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add @reactframe/photo-albumOr copy the source by hand and install its dependencies:
npm install clsx tailwind-mergeProps
<PhotoAlbum /> accepts 12 props, all optional. It also accepts the usual <div> attributes, like className, style, id and aria-*, and passes them to its root element.
| Prop | Type | Default |
|---|---|---|
| photos | { src: string; alt?: string; caption?: string; date?: string }[] | DEFAULT_PHOTOS |
| theme | "dark" | "light" | "dark" |
| title Cover title, repeated on the title page. | string | "Quiet Rooms" |
| subtitle | string | "A year at home · 2026" |
| coverImage Photo shown in the cover window. Defaults to the first photo. | string | — |
| pageWidth Size of one page in px; the album scales down to fit narrower containers. | number | 300 |
| pageHeight | number | 400 |
| smoothing 0–1, how quickly a page settles after it's released. | number | 0.1 |
| peekOnHover Lift the page a little when the pointer nears its outer edge. | boolean | true |
| showLines | boolean | true |
| enableLightbox | boolean | true |
| startOpen Start on the first spread instead of the closed cover. | boolean | false |
- photos{ src: string; alt?: string; caption?: string; date?: string }[]Default: DEFAULT_PHOTOS
- theme"dark" | "light"Default: "dark"
- title
Cover title, repeated on the title page.
stringDefault: "Quiet Rooms" - subtitlestringDefault: "A year at home · 2026"
- coverImage
Photo shown in the cover window. Defaults to the first photo.
string - pageWidth
Size of one page in px; the album scales down to fit narrower containers.
numberDefault: 300 - pageHeightnumberDefault: 400
- smoothing
0–1, how quickly a page settles after it's released.
numberDefault: 0.1 - peekOnHover
Lift the page a little when the pointer nears its outer edge.
booleanDefault: true - showLinesbooleanDefault: true
- enableLightboxbooleanDefault: true
- startOpen
Start on the first spread instead of the closed cover.
booleanDefault: false
Collections
Use-case pages that compare Photo Album with the other components that do a similar job.
npm dependencies
Installed for you by the shadcn CLI.
Photo Album FAQ
- How many photos can it hold?
- Any number. Each photo gets its own page; a blank page is added automatically when needed so the back cover always closes on the right.
- Can it start open?
- Yes, pass startOpen and it begins on the first spread instead of the closed cover.
- Does it work on phones?
- Yes. The whole book scales down to fit the container width, dragging turns pages with touch, and vertical page scrolling still works over it.
- How do I change the cover?
- title, subtitle and coverImage set the cover; coverImage defaults to the first photo.
- Can I make the turns slower or snappier?
- smoothing controls how quickly a released page settles: lower is slower, higher is snappier (0.1 by default).