Skip to content

Polaroid Fan

A fan of paper photographs lifts into focus.

LIVE PREVIEWInteract with the component
Just React. No extra dependencies.

Copy the component and its CSS module into your project.

CSS Modules

Usage

Matches your current playground settings.

jsx
import PolaroidFan from "./PolaroidFan";
export default function Example() {
return (
<PolaroidFan
items={[
{
"id": "arch",
"title": "Blue hour",
"description": "Light / Architecture",
"image": "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%20700%22%3E%3Cdefs%3E%3CradialGradient%20id%3D%22s%22%20cx%3D%22.3%22%20cy%3D%22.2%22%20r%3D%22.9%22%3E%3Cstop%20stop-color%3D%22%23f6eee1%22%2F%3E%3Cstop%20offset%3D%22.35%22%20stop-color%3D%22%23b9bec9%22%2F%3E%3Cstop%20offset%3D%22.65%22%20stop-color%3D%22%23505360%22%2F%3E%3Cstop%20offset%3D%22.82%22%20stop-color%3D%22%23d9d2ca%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2364636d%22%2F%3E%3C%2FradialGradient%3E%3ClinearGradient%20id%3D%22b%22%20x2%3D%22.8%22%20y2%3D%221%22%3E%3Cstop%20stop-color%3D%22%23adc7f5%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%23718ac1%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%233d5184%22%2F%3E%3C%2FlinearGradient%3E%3Cfilter%20id%3D%22n%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%22.7%22%20numOctaves%3D%223%22%20stitchTiles%3D%22stitch%22%2F%3E%3C%2Ffilter%3E%3C%2Fdefs%3E%3Cpath%20fill%3D%22%23c9cec8%22%20d%3D%22M0%200h600v700H0z%22%2F%3E%3Cpath%20d%3D%22M100%20700V290a200%20200%200%200%201%20400%200v410%22%20fill%3D%22url(%23b)%22%2F%3E%3Cpath%20d%3D%22M165%20700V300a135%20135%200%200%201%20270%200v400%22%20fill%3D%22%23d5d7cf%22%2F%3E%3Cpath%20d%3D%22M225%20700V320a75%2075%200%200%201%20150%200v380%22%20fill%3D%22%23647ba7%22%2F%3E%3Ccircle%20cx%3D%22300%22%20cy%3D%22318%22%20r%3D%2248%22%20fill%3D%22%23f0d8af%22%2F%3E%3Cpath%20d%3D%22M0%20565h600v135H0%22%20fill%3D%22%23b9b9b0%22%20opacity%3D%22.2%22%2F%3E%3Cpath%20d%3D%22M0%200h600v700H0z%22%20filter%3D%22url(%23n)%22%20opacity%3D%22.045%22%2F%3E%3C%2Fsvg%3E",
"alt": "Sculptural blue arches framing a pale gold sphere"
},
{
"id": "chrome",
"title": "Liquid metal",
"description": "Material / Reflection",
"image": "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%20700%22%3E%3Cdefs%3E%3CradialGradient%20id%3D%22s%22%20cx%3D%22.3%22%20cy%3D%22.2%22%20r%3D%22.9%22%3E%3Cstop%20stop-color%3D%22%23f6eee1%22%2F%3E%3Cstop%20offset%3D%22.35%22%20stop-color%3D%22%23b9bec9%22%2F%3E%3Cstop%20offset%3D%22.65%22%20stop-color%3D%22%23505360%22%2F%3E%3Cstop%20offset%3D%22.82%22%20stop-color%3D%22%23d9d2ca%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2364636d%22%2F%3E%3C%2FradialGradient%3E%3ClinearGradient%20id%3D%22b%22%20x2%3D%22.8%22%20y2%3D%221%22%3E%3Cstop%20stop-color%3D%22%23adc7f5%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%23718ac1%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%233d5184%22%2F%3E%3C%2FlinearGradient%3E%3Cfilter%20id%3D%22n%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%22.7%22%20numOctaves%3D%223%22%20stitchTiles%3D%22stitch%22%2F%3E%3C%2Ffilter%3E%3C%2Fdefs%3E%3Cpath%20fill%3D%22%2325252e%22%20d%3D%22M0%200h600v700H0z%22%2F%3E%3Cellipse%20cx%3D%22310%22%20cy%3D%22603%22%20rx%3D%22155%22%20ry%3D%2230%22%20fill%3D%22%230002%22%2F%3E%3Crect%20x%3D%22150%22%20y%3D%22115%22%20width%3D%22300%22%20height%3D%22450%22%20rx%3D%22150%22%20fill%3D%22url(%23s)%22%20transform%3D%22rotate(20%20300%20350)%22%2F%3E%3Crect%20x%3D%22240%22%20y%3D%22208%22%20width%3D%22120%22%20height%3D%22265%22%20rx%3D%2260%22%20fill%3D%22%23272731%22%20transform%3D%22rotate(20%20300%20350)%22%2F%3E%3Cpath%20d%3D%22M0%200h600v700H0z%22%20filter%3D%22url(%23n)%22%20opacity%3D%22.045%22%2F%3E%3C%2Fsvg%3E",
"alt": "A polished silver loop against charcoal"
},
{
"id": "coral",
"title": "Warm geometry",
"description": "Form / Colour",
"image": "data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20600%20700%22%3E%3Cdefs%3E%3CradialGradient%20id%3D%22s%22%20cx%3D%22.3%22%20cy%3D%22.2%22%20r%3D%22.9%22%3E%3Cstop%20stop-color%3D%22%23f6eee1%22%2F%3E%3Cstop%20offset%3D%22.35%22%20stop-color%3D%22%23b9bec9%22%2F%3E%3Cstop%20offset%3D%22.65%22%20stop-color%3D%22%23505360%22%2F%3E%3Cstop%20offset%3D%22.82%22%20stop-color%3D%22%23d9d2ca%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%2364636d%22%2F%3E%3C%2FradialGradient%3E%3ClinearGradient%20id%3D%22b%22%20x2%3D%22.8%22%20y2%3D%221%22%3E%3Cstop%20stop-color%3D%22%23adc7f5%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%23718ac1%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%233d5184%22%2F%3E%3C%2FlinearGradient%3E%3Cfilter%20id%3D%22n%22%3E%3CfeTurbulence%20type%3D%22fractalNoise%22%20baseFrequency%3D%22.7%22%20numOctaves%3D%223%22%20stitchTiles%3D%22stitch%22%2F%3E%3C%2Ffilter%3E%3C%2Fdefs%3E%3Cpath%20fill%3D%22%23ead4b8%22%20d%3D%22M0%200h600v700H0z%22%2F%3E%3Ccircle%20cx%3D%22440%22%20cy%3D%22150%22%20r%3D%2276%22%20fill%3D%22%23f1d9b8%22%2F%3E%3Cpath%20d%3D%22M85%20615V365a215%20215%200%200%201%20430%200v250%22%20fill%3D%22%23bf6658%22%2F%3E%3Cpath%20d%3D%22M150%20615V372a150%20150%200%200%201%20300%200v243%22%20fill%3D%22%23d99079%22%2F%3E%3Cpath%20d%3D%22M215%20615V380a85%2085%200%200%201%20170%200v235%22%20fill%3D%22%23edb594%22%2F%3E%3Cpath%20d%3D%22M280%20615V385a20%2020%200%200%201%2040%200v230%22%20fill%3D%22%23593e42%22%2F%3E%3Cpath%20d%3D%22M0%200h600v700H0z%22%20filter%3D%22url(%23n)%22%20opacity%3D%22.045%22%2F%3E%3C%2Fsvg%3E",
"alt": "Nested terracotta arches and a pale sun"
}
]}
defaultIndex={1}
cardWidth={190}
spread={64}
rotation={14}
paperColor={"#eee6d9"}
inkColor={"#473d3b"}
height={360}
/>
);
}

Using Polaroid Fan

Supply photos through items and use paperColor and inkColor to match their paper frames.

Set cardWidth and spread together so the fan fits its container. Use onIndexChange for selection and onSelect for the action attached to the selected photo.

Props

NameTypeRequiredDefaultDescription
itemsobject[]No[]Array of { id, image, title?, alt? }. Empty arrays render nothing.
activeIndexnumberNoundefinedOptional controlled selected photo index.
defaultIndexnumberNo0Initial selected photo index.
onIndexChangefunctionNoundefinedCalled when a photo gains pointer or keyboard focus.
onSelectfunctionNoundefinedCalled with (item, index) when a photo is activated.
cardWidthnumberNo180Preferred paper width in pixels, capped to 55% of the container.
spreadnumberNo42Horizontal distance between adjacent photographs in pixels.
rotationnumberNo12Rotation step between photographs in degrees.
paperColorstringNo"#eee6d9"Paper border background.
inkColorstringNo"#473d3b"Caption text colour.
heightnumber | stringNo360Height of the fan viewport in pixels or a CSS length.
classNamestringNo""Additional CSS classes, merged with the component styles.
styleCSSPropertiesNoundefinedInline styles for caller-defined sizing and visual overrides.

Related components

Transparent image layers separate in depth as the pointer crosses the scene.

An image separates into polished vertical slivers that shift with the pointer.

An editorial image grid opens into a focused, keyboard-accessible viewing room.