@slithy/react-grid-gallery
v0.4.0
Published
React grid gallery component.
Downloads
383
Readme
@slithy/react-grid-gallery
React grid gallery component. Fixed columns, uniform cell size, optional virtualization and keyboard navigation.
Installation
npm install @slithy/react-grid-galleryPeer dependencies: react@^17 || ^18 || ^19
GridGallery
Drop-in component. Pass items, tell it how to render each one.
import { GridGallery } from '@slithy/react-grid-gallery'
type Photo = { src: string; alt: string }
const items = photos.map((p, i) => ({ ...p, key: i }))
<GridGallery
items={items}
columns={4}
gap={8}
aspectRatio={1}
renderItem={(item, { loaded, focused }, { onLoad, onError }) => (
<img
src={item.src}
alt={item.alt}
onLoad={onLoad}
onError={onError}
style={{ width: '100%', height: '100%', objectFit: 'cover', opacity: loaded ? 1 : 0 }}
/>
)}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| items | GalleryItem<T>[] | — | Items to display. Each must have a key property. |
| renderItem | (item, layout, handlers) => ReactNode | — | Render function for each cell. See renderItem. |
| scrollContainerRef | ScrollContainerRef | — | Scroll container for virtualization. See Virtualization. |
| columns | number \| (width) => number | — | Column count. Pass a function for responsive columns. |
| gap | number \| (width) => number | 0 | Gap between cells in pixels. |
| aspectRatio | number \| (width) => number | 1 | Cell width ÷ height. 1 = square, 1.5 = landscape. |
| padding | number | 0 | Padding around the grid in pixels. |
| virtualize | boolean | false | Enable virtual rendering. Only renders visible rows. |
| overscan | number | cellHeight * 4 | Extra pixels to render above and below the viewport. |
| navigable | boolean | false | Enable keyboard navigation with ARIA grid semantics. |
| onActivate | (index, shiftKey) => void | — | Called when a cell is activated via Space or Enter. |
renderItem
The render function receives three arguments:
renderItem(
item, // GalleryItem<T>: your data + key
{ loaded, focused }, // layout state
{ onLoad, onError }, // pass to <img> (or equivalent)
)loaded—trueafteronLoadfires; use to show a placeholder or fade infocused—truewhen this cell has keyboard focus (only meaningful whennavigableis set)onLoad/onError— wire to your image element so the gallery tracks load state
Responsive columns
Pass a function to columns (and gap) to change layout at different widths:
<GridGallery
items={items}
columns={(w) => (w < 600 ? 2 : w < 1000 ? 3 : 4)}
gap={(w) => (w < 600 ? 4 : 8)}
aspectRatio={1}
renderItem={...}
/>Virtualization
Enable with virtualize. Only rows near the viewport are rendered — the rest are replaced by spacer elements.
const scrollRef = useRef<HTMLDivElement>(null)
<div ref={scrollRef} style={{ height: 600, overflowY: 'auto' }}>
<GridGallery
items={items}
columns={4}
gap={8}
aspectRatio={1}
virtualize
scrollContainerRef={scrollRef}
renderItem={...}
/>
</div>When no scrollContainerRef is provided, the gallery virtualizes against the window.
overscan controls how much extra content to render beyond the visible area (default: 4× cell height). Increase it on slower devices to reduce blank-row flicker.
Keyboard navigation
Set navigable to add ARIA grid semantics and arrow-key navigation:
<GridGallery
items={items}
columns={4}
aspectRatio={1}
navigable
onActivate={(index, shiftKey) => openLightbox(index, shiftKey)}
renderItem={(item, { focused }, handlers) => (
<img
src={item.src}
style={{ outline: focused ? '2px solid blue' : 'none' }}
{...handlers}
/>
)}
/>| Key | Action |
|---|---|
| ArrowRight / ArrowLeft | Move one cell right / left |
| ArrowDown / ArrowUp | Move one row down / up |
| Home | First cell in row (Ctrl+Home: first cell) |
| End | Last cell in row (Ctrl+End: last cell) |
| Space / Enter | Activate cell (onActivate) |
Arrow keys with Meta held are ignored (allows OS / browser shortcuts to pass through).
useGridGallery
Headless hook for building a custom renderer. Returns the same layout state GridGallery uses internally.
import { useGridGallery } from '@slithy/react-grid-gallery'
const {
containerRef,
rows,
cellWidth,
cellHeight,
gap,
columns,
onLoad,
onError,
virtualWindow,
focusedIndex,
handleItemFocus,
handleItemKeyDown,
} = useGridGallery(items, options, scrollContainerRef)virtualWindow is null when virtualization is off; otherwise { firstIndex, lastIndex, topSpacerHeight, bottomSpacerHeight }.
computeGridLayout
Lower-level layout utility. Takes items, column count, and cell dimensions; returns rows.
import { computeGridLayout } from '@slithy/react-grid-gallery'
const rows = computeGridLayout(items, columns, cellWidth, cellHeight)
// rows: GridLayoutRow<T>[]Types
import type {
GalleryItem,
GridOptions,
GridRow,
GridLayoutRow,
ScrollContainerRef,
} from '@slithy/react-grid-gallery'GalleryItem<T> — Your item type with a required key:
type GalleryItem<T> = T & { key: string | number }GridOptions — All options accepted by GridGallery and useGridGallery.
ScrollContainerRef — RefObject<HTMLElement | null> | HTMLElement | null
GridRow<T> — A rendered row with per-item loaded state.
GridLayoutRow<T> — A computed layout row (output of computeGridLayout).
