Skip to content

Lenticular Image

Two images shift through fine optical ridges as the angle changes.

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 LenticularImage from "./LenticularImage";
export default function Example() {
return (
<LenticularImage
front={"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"}
back={"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"}
frontAlt={"Sculptural blue arches framing a pale gold sphere"}
backAlt={"A polished silver loop against charcoal"}
defaultValue={20}
strips={28}
aspectRatio={1.25}
borderRadius={14}
interactive={true}
label={"Viewing angle"}
/>
);
}

Using Lenticular Image

Use front and back images with compatible crops so the optical transition feels deliberate. Provide frontAlt and backAlt for the two views.

Use value and onChange to coordinate the viewing angle externally. Set interactive to false when the angle should be fixed or controlled elsewhere.

Props

NameTypeRequiredDefaultDescription
frontstringNo""Image source for the first viewing angle.
backstringNo""Image source for the second viewing angle.
frontAltstringNo""Accessible description of the first image.
backAltstringNo""Accessible description of the second image.
valuenumberNoundefinedOptional controlled viewing angle, from 0 to 100.
defaultValuenumberNo0Initial viewing angle when uncontrolled.
onChangefunctionNoundefinedCalled with the new angle on pointer, touch, or native range keyboard input.
stripsnumberNo24Number of optical ridges, clamped from 4 to 60.
aspectRationumberNo1.25Container width divided by height.
borderRadiusnumberNo12Corner radius in pixels.
interactivebooleanNotrueEnable pointer and range-input control.
labelstringNo"Viewing angle"Accessible label for the viewing-angle slider.
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.