useGallery
Hook that manages image gallery navigation, zoom, rotation, flip, and fullscreen state.
Usage#
import { useGallery } from '@primereact/headless/gallery';
import { useGalleryItem } from '@primereact/headless/gallery/item';const gallery = useGallery();
const item = useGalleryItem({ gallery });
<div {...gallery.rootProps}>
<div {...gallery.backdropProps}></div>
<button {...gallery.prevProps}></button>
<button {...gallery.nextProps}></button>
<div {...gallery.headerProps}>
<button {...gallery.zoomInProps}></button>
<button {...gallery.zoomOutProps}></button>
<button {...gallery.downloadProps}></button>
</div>
<div {...gallery.contentProps}>
<div {...item.itemProps}></div>
</div>
<div {...gallery.footerProps}></div>
</div>;useGallery orchestrates navigation, fullscreen, and toolbar state for an image viewer while useGalleryItem handles per-image transforms. See Primitive for a component-based API.
Features#
- Two-hook split —
useGalleryowns navigation and fullscreen;useGalleryItemowns per-image zoom, rotation, flip, and pan - Prev/next and thumbnail navigation — pre-wired button props plus
thumbnailItemProps(index)for clickable previews - Image action toolbar — spread-ready props for zoom in/out/toggle, rotate left/right, flip X/Y, download, and fullscreen
- Transform via CSS variables —
useGalleryItemwrites--scale,--rotation,--flip-x,--flip-y,--position-x,--position-yso templates stay declarative - Imperative controls —
selectItem,handleNext,handlePrev,toggleFullScreenfor custom bindings - Reactive state —
state.activeIndex,state.isFullscreen,state.zoomed,state.rotated,state.flipped,state.pendingAction
Working with callbacks#
Controlled active index#
Use activeIndex with onActiveIndexChange to sync the current image with URL params or adjacent UI like thumbnails.
const [index, setIndex] = React.useState(0);
const gallery = useGallery({
activeIndex: index,
onActiveIndexChange: (e) => setIndex(e.value)
});Toolbar wiring#
The toolbar props manage their own disabled state — zoomInProps disables when already zoomed, zoomOutProps disables when unzoomed.
<button {...gallery.zoomInProps}>Zoom In</button>
<button {...gallery.zoomOutProps}>Zoom Out</button>
<button {...gallery.rotateLeftProps}>Rotate Left</button>
<button {...gallery.rotateRightProps}>Rotate Right</button>
<button {...gallery.flipXProps}>Flip Horizontal</button>
<button {...gallery.downloadProps}>Download</button>
<button {...gallery.fullScreenProps}>Toggle Fullscreen</button>Per-item transforms with useGalleryItem#
Each item instantiates its own transform state. Apply the CSS variables in your transform to compose them.
function GalleryItemView({ image, gallery }) {
const item = useGalleryItem({ gallery });
return (
<div
{...item.itemProps}
style={{
...item.itemProps.style,
display: item.state.isActive ? 'flex' : 'none',
transform: 'translate(var(--px-position-x), var(--px-position-y)) scale(var(--px-scale)) rotate(var(--px-rotation)) scaleX(var(--px-flip-x)) scaleY(var(--px-flip-y))'
}}
>
<img src={image} />
</div>
);
}Thumbnail strip#
thumbnailItemProps(index) attaches the click handler and data-active so thumbnails stay in sync with activeIndex.
{
images.map((src, i) => (
<div key={i} {...gallery.thumbnailItemProps(i)}>
<img src={src} />
</div>
));
}Reacting to fullscreen and transform state#
Read reactive state to show contextual UI or pause background media when the viewer is fullscreen.
const gallery = useGallery();
{
gallery.state.isFullscreen && <span>Fullscreen Mode</span>;
}
{
gallery.state.zoomed && <span>Zoomed</span>;
}Styling with data attributes#
Prop objects include data-scope="gallery" and a data-part for each section, plus state-dependent attributes on the root element.
[data-scope='gallery'][data-fullscreen] {
position: fixed;
inset: 0;
z-index: 9999;
}
[data-scope='gallery'][data-zoomed] {
cursor: zoom-out;
}
[data-scope='gallery'][data-part='item'][data-active='true'] {
display: block;
}
[data-scope='gallery'][data-part='item'][data-active='false'] {
display: none;
}
[data-scope='gallery'][data-part='thumbnailItem'][data-active] {
opacity: 1;
}API#
useGallery#
| Name | Type | Default |
|---|---|---|
activeIndex | number | 0 |
| The index of the active item. | ||
fullscreen | boolean | false |
| Whether the gallery is rendered fullscreen via a portal. When `true` , the gallery escapes its parent layout and covers the viewport — useful for opening a single image in a modal-style viewer. | ||
closeOnEscape | boolean | true |
| Whether pressing Escape closes the gallery when in fullscreen mode. | ||
onFullscreenChange | (value: boolean) => void | — |
| Callback fired when the gallery's fullscreen state changes (via close button, escape key, etc.). | ||
onZoomChange | (scale: number) => void | — |
| Callback fired when the active item's zoom scale changes. | ||
onRotateChange | (rotation: number) => void | — |
| Callback fired when the active item's rotation changes. | ||
onFlipChange | (flip: { x: number; y: number }) => void | — |
| Callback fired when the active item's flip state changes. | ||
onActiveIndexChange | (event: useGalleryChangeEvent) => void | — |
| Callback fired when the gallery's active index changes. | ||
useGalleryItem#
| Name | Type | Default |
|---|---|---|
context | useGalleryItemGalleryRef | — |
| Optional gallery instance for headless usage (without Gallery.Root context). When omitted, the item reads the gallery from the nearest GalleryProvider context. | ||
normalScale | number | 1 |
| The normal scale of the gallery item. | ||
zoomedScale | number | 3 |
| The zoomed scale of the gallery item. | ||
Accessibility#
Arrow keys navigate items, Home/End jump to first/last, and Escape exits fullscreen view. See Primitive for full WAI-ARIA compliance details.