Theme Playground

Storefront

ProductImage

Product detail media gallery with synced active image state, variant-aware image selection, thumbnail rails, dots, and lightbox-first viewing.

Best for

product detail galleriesvariant imagerylightbox-first product mediashared-element-ready gallery transitions

Import

import { ProductImage } from "@enadhq/enad-react-sdk/client/storefront"

When to use it

Use ProductImage as the main media gallery on a product detail page. It handles the high-importance browsing behavior around product imagery, including thumbnails, lightbox viewing, a consistent hero image frame, synced active-image state, and variant-aware image handoff.

If the page only needs a single static image, a simpler image block is usually enough.

Composition notes

The gallery is prop-driven:

  • images is the required media array.
  • each image can include variant metadata so the gallery knows which simple selector value it belongs to.
  • each image can include variantId metadata so the gallery can also match a resolved backend variant id.
  • activeVariantId takes priority and activates the first image whose variantId matches the selected value.
  • activeVariant activates the first image whose variant matches when no activeVariantId is provided.
  • aspectRatio controls whether the frame reads square or portrait.
  • interaction controls whether the gallery opens the fullscreen lightbox on click or tap. The default is "lightbox".
  • activeIndex, defaultActiveIndex, and onActiveIndexChange control the inline carousel, thumbnail rail, and the lightbox handoff.
  • lightboxOpen, defaultLightboxOpen, and onLightboxOpenChange let a parent own the fullscreen viewer state when needed.
  • showThumbnails, thumbnailPosition, and maxThumbnails shape the secondary navigation rail.
  • arrows chooses whether navigation sits inside or outside the frame.
  • showDots is useful when the layout is tighter and thumbnails would be too heavy.
  • viewTransitions is a progressive-enhancement hook for shared-element continuity between the PDP hero and the fullscreen viewer.

Start with the content and device needs, then choose the navigation affordances that match.

Behavior and theming guidance

Use 4:5 when the product is fashion- or portrait-led. Use 1:1 when the assortment benefits from a more catalog-like square rhythm.

Thumbnail rails add clarity but also visual weight. On compact surfaces, dots plus arrows often give a cleaner result. When the image set is longer than the visible thumbnail count, the rail fades at the edge to hint at overflow without feeling heavy.

classNames now exposes stable hooks for the thumbnail rail, thumbnail buttons, active-thumbnail state, thumbnail images, and overflow indicator. That lets one PDP keep a soft, editorial thumbnail treatment while another uses harder technical framing without reaching into aria labels or private DOM structure.

For variant-heavy PDPs, decide whether your page state is still axis-level or already resolved:

  • use activeVariant when the selector state is still a simple value like "oak" or "black"
  • use activeVariantId when your product logic has already resolved a concrete purchasable variant like "sku-oak-001"

If both are present, ProductImage prioritizes activeVariantId. If several images belong to the same variant or variant id, the gallery activates the first matching image and the visitor can continue browsing from there.

Always keep alt text meaningful because the gallery is a primary part of the PDP experience. If you opt into shared-element continuity, keep image identities stable across variant switches so the transition still feels like the same object going deeper.

Examples

Live examples you can edit directly in the sandbox.

5 examples

PDP gallery with thumbnails

A strong default for product detail pages that need fullscreen viewing and clear image browsing without letting the thumbnail rail take over the layout.

Editorial thumbnails vs technical thumbnails

Use semantic classNames hooks on the thumbnail rail to make the same gallery feel either soft and editorial or sharp and technical.

Controlled gallery and lightbox state

Use controlled state when the inline gallery, external controls, and fullscreen viewer all need to stay in sync.

Variant-linked gallery

Use external selector state to activate the first image that belongs to the selected material or color value.

Resolved variant-id gallery

Use a resolved backend variant id when the product model has already selected a specific purchasable variant.

Slots

rootcarouselthumbnailRailthumbnailButtonthumbnailButtonActivethumbnailImageoverflowIndicator

Component Sets

Preview the first example across the available component-set presets to compare tone, spacing, and structural defaults.

Props

PropTypeDefaultDescription
imagesProductImageAsset[]
No description yet.
activeVariantstring
Active variant key used to select the first matching image in the gallery
activeVariantIdstring
Active resolved variant id used to select the first matching image in the gallery
aspectRatiostring4:5
No description yet.
interactionstringlightbox
Enhanced interaction model for the hero media. "lightbox" opens the fullscreen viewer on click or tap.
activeIndexnumber
Controlled active image index for the carousel, thumbnail rail, and lightbox.
defaultActiveIndexnumber0
Uncontrolled initial active image index.
onActiveIndexChangestring
Callback fired when the active image changes.
lightboxOpenboolean
Controlled lightbox open state.
defaultLightboxOpenbooleanfalse
Uncontrolled initial lightbox open state.
onLightboxOpenChangestring
Callback fired when the lightbox open state changes.
arrowsstringundefined
'inset' — arrows float over the image edges; 'outset' — arrows sit outside the image bounds
showDotsbooleantrue
No description yet.
showThumbnailsbooleanfalse
No description yet.
maxThumbnailsnumber5
Maximum number of thumbnails visible before overflow hinting appears. Default: 5
thumbnailPositionstringleft
Where to place the thumbnail strip when showThumbnails is true. Default: "left"
imageLoadingstring
Loading behavior for main gallery images. By default the active image uses browser loading behavior and inactive rendered slides are lazy.
viewTransitionsstring
Progressive enhancement hook for environments that support shared-element continuity.
classNamesPartial<Record<import("@enadhq/enad-react-sdk/client/storefront/types").ProductImageSlot, string>>
No description yet.
Slot keys
rootcarouselthumbnailRailthumbnailButtonthumbnailButtonActivethumbnailImageoverflowIndicator
classNamestring
No description yet.