Skip to content

React Hook ​

useMasonry(container, options?) — the low-level escape hatch for when <MasonryGrid>'s render-prop layout doesn't fit. You own the item elements yourself; this only wires the engine to a container and keeps it in sync with options.items.

ts
function useMasonry(container: HTMLElement | null, options?: UseMasonryOptions): UseMasonryReturn

container and options are compared by reference, not by content — core has no live updateOptions(), so a changed reference tears down and recreates the engine. This is a real difference from the Vue composable, which compares options structurally and accepts reactive refs/getters directly:

  • Pass a stable container — from useState, not useRef (a plain ref's value change doesn't itself trigger a re-render, so this hook would never notice the element actually mounted).
  • Memoize options with useMemo if it isn't already a module-level constant — a fresh object literal on every render would otherwise tear the engine down and recreate it every single render.

Options ​

UseMasonryOptions extends MasonryOptions (see Engine API) with one extra field:

items ​

UseMasonryItem[] · optional

ts
interface UseMasonryItem extends Omit<MasonryItemDescriptor, 'el'> {
  el: HTMLElement | null | undefined
}

el is a plain, already-resolved element or null/undefined — not a ref/getter like the Vue composable's equivalent. Drive it from your own state (e.g. a callback ref backed by useState): a plain useRef won't re-trigger this hook's effect when the element actually mounts, for the same by-reference-comparison reason container needs useState too. Items whose el is currently null/undefined are filtered out before being passed to the engine.

Return value ​

engine ​

MasonryEngine | null

The engine instance (see Engine API) — a plain value, not wrapped in anything reactive (React's own re-render is what keeps it current), null until container resolves to a real element.

Example:

tsx
import { useState, useMemo } from 'react'
import { useMasonry } from '@macrulez/masonry-kit-react'

function Board() {
  const [containerNode, setContainerNode] = useState<HTMLElement | null>(null)
  const [cardAEl, setCardAEl] = useState<HTMLElement | null>(null)
  const [cardBEl, setCardBEl] = useState<HTMLElement | null>(null)

  const options = useMemo(
    () => ({
      columns: 'auto' as const,
      minLaneSize: 240,
      items: [
        { id: 'a', el: cardAEl },
        { id: 'b', el: cardBEl, colSpan: 2 },
      ],
    }),
    [cardAEl, cardBEl],
  )

  const { engine } = useMasonry(containerNode, options)

  return (
    <div ref={setContainerNode}>
      <div ref={setCardAEl}>A</div>
      <div ref={setCardBEl}>B</div>
    </div>
  )
}