Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

masonic

jaredLunde117.4kMIT4.1.0TypeScript support: included


🧱 masonic

grid component, infinite, infinite list, infinite masonry, infinite scrolling, list, masonic, masonry, masonry component, masonry grid, react, react component, react grid, react masonry component, react masonry grid, reactjs, scrolling, virtual, virtualized

readme


🧱 masonic

Supported by FlexStack

Bundlephobia Types Code coverage Build status NPM Version MIT License

npm i masonic

A performant and versatile virtualized masonry grid for React based on Brian Vaughn's react-virtualized and further inspired by react-window.

Using Masonic, you're not just getting a component. You're getting the implementation details, as well, meaning advanced usage requiring little code is possible.

Features

  • <input checked="" disabled="" type="checkbox"> Easy to use It takes two minutes to start creating your own masonry grid with this component.
    [For real, check out the demo on **CodeSandbox**](https://codesandbox.io/s/0oyxozv75v).
  • <input checked="" disabled="" type="checkbox"> Blazing™ fast This component can seamlessly render tens of thousands of grid cells
    without lag via its virtualization algorithm and underlying
    [data structures](https://www.scaler.com/topics/data-structures/what-is-data-structure/). For example, it uses
    a [red black interval tree](https://www.geeksforgeeks.org/interval-tree/) to determine which cells to
    render, based upon the scroll position and size of the window the grid is rendered in. Interval trees
    have `O(log n + m)` search performance 😱.
  • <input checked="" disabled="" type="checkbox"> TypeScript Intellisense and type safety mean fewer bugs in your implementation.
  • <input checked="" disabled="" type="checkbox"> Versatility All of <Masonry>'s implementation details (hooks, utilities) are exported,
    so you're not locked into to the default implementation. As you advance, it will be useful to have access
    to those internals. It's also possible to kick the virtualization out of the equation by providing an
    `Infinity` value to the `overscanBy` prop, though this would be a terrible idea for large lists.
  • <input checked="" disabled="" type="checkbox"> Autosizing The default <Masonry> component will automatically resize itself and its
    items if the content of the grid cells changes or resizes. For example, when an image lazily loads this
    component will automatically do the work of recalculating the size of that grid cell. That said, you
    should try to premeasure things (including images) as often as possible in order to achieve the best
    user experience.

Quick Start

Check out the demo on CodeSandbox

`jsx harmony import * as React from "react"; import { Masonry } from "masonic";

let i = 0; const items = Array.from(Array(5000), () => ({ id: i++ }));

const EasyMasonryComponent = (props) => ( <Masonry items={items} render={MasonryCard} /> );

const MasonryCard = ({ index, data: { id }, width }) => (

Index: {index}
ID: {id}
Column width: {width}
);


## Documentation

### Components

| Component                               | Description                                                                                                                                                                                                                                                                                                                                                                            |
| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`<Masonry>`](#masonry)                 | A "batteries included" masonry grid which includes all of the implementation details below. This component is the easiest way to get off and running in your app, before switching to more advanced implementations, if necessary. It will change its column count to fit its container's width and will decide how many rows to render based upon the height of the browser `window`. |
| [`<MasonryScroller>`](#masonryscroller) | A heavily-optimized component that updates [`useMasonry()`](#usemasonryoptions) when the scroll position of the browser `window` changes. This bare-metal component is used by [`<Masonry>`](#masonry) above.                                                                                                                                                                          |
| [`<List>`](#list)                       | This is just a single-column [`<Masonry>`](#masonry) component with no `columnGutter` prop, only `rowGutter`.                                                                                                                                                                                                                                                                          |

### Hooks

| Hook                                                             | Description                                                                                                                                                                                                                                                                                           |
| ---------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`useMasonry()`](#usemasonryoptions)                             | This hook handles the render phases of the masonry layout and returns the grid as a React element.                                                                                                                                                                                                    |
| [`usePositioner()`](#usepositioneroptions-deps)                  | This hook creates the grid cell positioner and cache required by [`useMasonry()`](#usemasonryoptions). This is the meat of the grid's layout algorithm, determining which cells to render at a given scroll position, as well as where to place new items in the grid.                                |
| [`useResizeObserver()`](#useresizeobserverpositioner)            | Creates a resize observer that forces updates to the grid when mutations are made to the grid cells affecting their size.                                                                                                                                                                             |
| [`useContainerPosition()`](#usecontainerpositionelementref-deps) | A hook for measuring the width of the grid container, as well as its distance from the top of the document. These values are necessary to correctly calculate the number/width of columns to render, as well as the number of rows to render.                                                         |
| [`useScroller()`](#usescrolleroffset-fps)                        | A hook for tracking whether the `window` is currently being scrolled and it's scroll position on the y-axis. These values are used for determining which grid cells to render and when to add styles to the grid container that maximize scroll performance.                                          |
| [`useScrollToIndex()`](#usescrolltoindexpositioner-options)      | A hook that creates a callback for scrolling to a specific index in the "items" array.                                                                                                                                                                                                                |
| [`useInfiniteLoader()`](#useinfiniteloaderloadmoreitems-options) | A utility hook for seamlessly adding infinite scroll behavior to the [`useMasonry()`](#usemasonryoptions) hook. This hook invokes a callback each time the last rendered index surpasses the total number of items in your items array or the number defined in the `totalItems` option of this hook. |

### Utilities

| Utility                                                                                 | Description                                                                                                                                                                                              |
| --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`createPositioner()`](#createpositionercolumncount-columnwidth-columngutter-rowgutter) | Creates a cell positioner for the [`useMasonry()`](#usemasonryoptions) hook. The [`usePositioner()`](#usepositioneroptions-deps) hook uses this utility under the hood.                                  |
| [`createResizeObserver()`](#createresizeobserverpositioner-updater)                     | Creates a resize observer that fires an `updater` callback whenever the height of one or many cells change. The [`useResizeObserver()`](#useresizeobserverpositioner) hook is using this under the hood. |

### Recipes

- [Add infinite scrolling behavior to your Masonry component.](https://codesandbox.io/s/useinfiniteloader-example-vn30p?file=/src/index.js)
- [Cells don't resize once they're measured? Build a Masonry grid without the resize observer.](https://codesandbox.io/s/usemasonry-example-3pcg9?file=/src/index.js)
- [Reset `<Masonry>` layout when switching between routes within the same <Route> component.](https://codesandbox.io/s/masonic-w-react-router-example-2b5f9?file=/src/index.js)
  - [Do the same with an advanced custom implementation using the `usePositioner()` hook.](https://codesandbox.io/s/masonic-w-react-router-and-advanced-config-example-8em42?file=/src/index.js)
- [Render a Masonry component relative to a scrollable HTML element rather than the browser `window`.](https://codesandbox.io/s/masonic-inside-of-a-scrollable-div-example-k9l6c?file=/src/index.js)
- [Add an `isScrolling` prop to cells](https://codesandbox.io/s/usemasonry-example-3pcg9?file=/src/index.js)

---

### &lt;Masonry&gt;

An autosizing masonry grid that only renders items currently visible in the browser `window`. This
component will change its column count to fit its container's width and will decide how many rows
to render based upon the height of the browser `window`. To facilitate this, it uses [`useMasonry()`](#usemasonryoptions),
[`usePositioner()`](#usepositioneroptions-deps), [`useResizeObserver()`](#useresizeobserverpositioner),
[`useContainerPosition()`](#usecontainerpositionelementref-deps), and [`useScroller()`](#usescrolleroffset-fps) under the hood.

This is the "batteries included" option. It's the easiest way to get off and running with your app and a
great stepping stone to more advanced implementations, should you need them.

[Check out an example on **CodeSandbox**](https://codesandbox.io/s/0oyxozv75v)

```jsx harmony
import * as React from "react";
import { Masonry } from "masonic";

let i = 0;
const items = Array.from(Array(5000), () => ({ id: i++ }));

const EasyMasonryComponent = (props) => (
  <Masonry items={items} render={MasonryCard} />
);

const MasonryCard = ({ index, data: { id }, width }) => (
  <div>
    <div>Index: {index}</div>
    <pre>ID: {id}</pre>
    <div>Column width: {width}</div>
  </div>
);

Props

Required props

Prop Type Required? Description
items any[] Yes An array containing the data used by the grid items.
render React.ComponentType<RenderComponentProps> Yes This component is rendered for each item of your items prop array. It should accept three props: index, width, and data. See RenderComponentProps for more detail on those props.

Column props

Props for tuning the column width, count, and gutter of your component.

Prop Type Default Required? Description
columnWidth number 240 No This is the minimum column width. Masonic will automatically size your columns to fill its container based on your provided columnWidth and columnGutter values. It will never render anything smaller than this defined width unless its container is smaller than its value.
columnGutter number 0 No This sets the horizontal space between grid columns in pixels. If rowGutter is not set, this also sets the vertical space between cells within a column in pixels.
rowGutter number Same as columnGutter No This sets the vertical space between cells within a column in pixels.
columnCount number | No By default, Masonic derives the column count from the columnWidth prop. However, in some situations it is nice to be able to override that behavior e.g. when creating a <List>.
maxColumnCount number | No Limits the number of columns used by Masonic. Useful for implementing responsive layouts.
maxColumnWidth number | No Limits the calculated width of columns rendered by Masonic.

Grid container props

These props customize how the grid container element is rendered.

Prop Type Default Required? Description
as keyof JSX.IntrinsicElements | React.ComponentType<any> "div" No This is the type of element the grid container will be rendered as.
id string | No Gives the grid container an id.
className string | No Gives the grid container a className.
style React.CSSProperties | No Adds extra style attributes to the container in addition to those created by the useMasonry() hook.
role "grid" | "list" "grid" No Optionally swap out the accessibility role prop of the container and its items.
tabIndex number 0 No Change the tabIndex of the grid container.

Grid item props

Props that customize how individual grid item containers are rendered.

Prop Type Default Required? Description
itemAs keyof JSX.IntrinsicElements | React.ComponentType<any> "div" No This is the type of element the grid items will be rendered as.
itemStyle React.CSSProperties | No Adds extra style attributes to the grid items in addition to those created by the useMasonry() hook.
itemHeightEstimate number 300 No This value is used for estimating the initial height of the masonry grid. It is important for the UX of the scrolling behavior and in determining how many items to render in a batch, so it's wise to set this value with some level accuracy, though it doesn't need to be perfect.
itemKey (data: any, index: number) => string | number (data, index) => index No The value returned here must be unique to the item. By default, the key is the item's index. This is ok if your collection of items is never modified. Setting this property ensures that the component in render is reused each time the masonry grid is reflowed. A common pattern would be to return the item's database ID here if there is one, e.g. data => data.id

Callbacks

Prop Type Default Required? Description
onRender (startIndex: number, stopIndex: number, items: any[]) => void | No This callback is invoked any time the items currently being rendered by the grid change. See onRender() arguments.

Other props

Prop Type Default Required? Description
overscanBy number 2 No This number is used for determining the number of grid cells outside of the visible window to render. The default value is 2 which means "render 2 windows worth (2 * height) of content before and after the items in the visible window". A value of 3 would be 3 windows worth of grid cells, so it's a linear relationship. Overscanning is important for preventing tearing when scrolling through items in the grid, but setting too high of a value may create too much work for React to handle, so it's best that you tune this value accordingly.
scrollToIndex number | {index: number, align: "top" | "center" | "bottom"} | No Scrolls to a given index within the grid. The grid will re-scroll any time the index changes.

onRender() arguments

Argument Type Description
startIndex number The index of the first item currently being rendered in the window
stopIndex number The index of the last item currently being rendered in the window
items any[] The array of items you provided to the items prop

RenderComponentProps

Prop Type Description
index number The index of the cell in the items prop array.
width number The rendered width of the cell's column.
data any The data at items[index] of your items prop array..

<MasonryScroller>

A heavily-optimized component that updates useMasonry() when the scroll position of the browser window changes. This bare-metal component is used by <Masonry> above.

When would you use this? If you're building an advanced masonry grid implementation, but you don't want to deal with figuring out how to optimize the exchange between scroll position changes in the browser window and the useMasonry() hook.

Check out an example on CodeSandbox

`jsx harmony import * as React from "react"; import { MasonryScroller, usePositioner, useContainerPosition } from "masonic"; import { useWindowSize } from "@react-hook/window-size";

const MyMasonry = (props) => { const containerRef = React.useRef(null); const [windowWidth, windowHeight] = useWindowSize(); const { offset, width } = useContainerPosition(containerRef, [ windowWidth, windowHeight, ]); const positioner = usePositioner({ width, columnWidth: 320 });

return ( <MasonryScroller positioner={positioner} // The distance in px between the top of the document and the top of the // masonry grid container offset={offset} // The height of the virtualization window height={windowHeight} // Forwards the ref to the masonry container element containerRef={containerRef} {...props} /> ); };


#### Props

In addition to these props, this component accepts all of the props outlined in [`<Masonry>`](#masonry)
with exception to `columnGutter`, `rowGutter`, `columnWidth`, `columnCount`, `maxColumntCount`, `ssrWidth`, and `ssrHeight`.

| Prop           | Type                                                                | Default | Required? | Description                                                                                                                                                                                                                                                                                                             |
| -------------- | ------------------------------------------------------------------- | ------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| offset         | `number`                                                            | `0`     | No        | The vertical space in pixels between the top of the grid container and the top of the browser `document.documentElement`.                                                                                                                                                                                               |
| height         | `number`                                                            |         | Yes       | This is the height of the window. If you're rendering the grid relative to the browser `window`, the current `document.documentElement.clientHeight` is the value you'll want to set here. If you're rendering the grid inside of another HTML element, you'll want to provide the current `element.offsetHeight` here. |
| positioner     | [`Positioner`](#positioner)                                         |         | Yes       | A grid cell positioner and cache created by the [`usePositioner()`](#usepositioneroptions-deps) hook or [`createPositioner()`](#createpositionercolumncount-columnwidth-columngutter-rowgutter) utility.                                                                                                                |
| containerRef   | <code>React.MutableRefObject&lt;HTMLElement &#0124; null&gt;</code> |         | No        | Forwards a React ref to the grid container.                                                                                                                                                                                                                                                                             |
| resizeObserver | `ResizeObserver`                                                    |         | No        | A resize observer that tracks mutations to the grid cells and forces the Masonry grid to recalculate its layout if any cells affect column heights change. Check out the [`useResizeObserver()`](#useresizeobserverpositioner) hook and [`createResizeObserver()`](#createresizeobserverpositioner-updater) utility.    |

---

### &lt;List&gt;

This is a single-column [`<Masonry>`](#masonry) component. That is, it uses the [`useMasonry()`](#usemasonryoptions) hook
and other utilities to create a virtualized list.

[Check out an example on **CodeSandbox**](https://codesandbox.io/s/list-example-3g0tc?file=/src/index.js)

```jsx harmony
import * as React from "react";
import { List } from "masonic";

let i = 0;
const items = Array.from(Array(5000), () => ({ id: i++ }));

const EasyListComponent = (props) => (
  <List items={items} rowGutter={32} render={ListCard} />
);

const ListCard = ({ index, data: { id }, width }) => (
  <div>
    <div>Index: {index}</div>
    <pre>ID: {id}</pre>
    <div>Column width: {width}</div>
  </div>
);

Props

In addition to these props, this component accepts all of the props outlined in <Masonry> with exception to columnGutter, columnWidth, columnCount, and maxColumnCount.

Prop Type Default Required? Description
rowGutter number 0 No The amount of vertical space in pixels to add between list item cards.

useMasonry(options)

This hook handles the render phases of the masonry layout and returns the grid as a React element.

Check out an example on CodeSandbox

`jsx harmony import * as React from "react"; import { useWindowSize } from "@react-hook/window-size"; import { useMasonry, usePositioner, useContainerPosition, useScroller, } from "masonic";

const MyMasonry = (props) => { const containerRef = React.useRef(null); const [windowWidth, height] = useWindowSize(); const { offset, width } = useContainerPosition(containerRef, [ windowWidth, height, ]); const { scrollTop, isScrolling } = useScroller(offset); const positioner = usePositioner({ width });

return useMasonry({ positioner, scrollTop, isScrolling, height, containerRef, ...props, }); };


#### Arguments

| Argument | Type                                        | Description                                                                                  |
| -------- | ------------------------------------------- | -------------------------------------------------------------------------------------------- |
| options  | [`UseMasonryOptions`](#usemasonryoptions-1) | The distance in pixels between the top of your masonry container and the top of the document |

#### UseMasonryOptions

**Required options**

| Prop       | Type                                                                 | Required? | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| ---------- | -------------------------------------------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| items      | `any[]`                                                              | Yes       | An array containing the data used by the grid items.                                                                                                                                                                                                                                                                                                                                                                                                         |
| positioner | [`Positioner`](#positioner)                                          | Yes       | A grid cell positioner and cache created by the [`usePositioner()`](#usepositioneroptions-deps) hook or [`createPositioner()`](#createpositionercolumncount-columnwidth-columngutter-rowgutter) utility.                                                                                                                                                                                                                                                     |
| height     | `number`                                                             | Yes       | This is the height of the window. If you're rendering the grid relative to the browser `window`, the current `document.documentElement.clientHeight` is the value you'll want to set here. If you're rendering the grid inside of another HTML element, you'll want to provide the current `element.offsetHeight` here.                                                                                                                                      |
| scrollTop  | `number`                                                             | Yes       | The current scroll progress in pixel of the window the grid is rendered in. If you're rendering the grid relative to the browser `window`, you'll want the most current `window.scrollY` here. If you're rendering the grid inside of another HTML element, you'll want the current `element.scrollTop` value here. The `useScroller()` hook and `<MasonryScroller>` components will help you if you're rendering the grid relative to the browser `window`. |
| render     | [`React.ComponentType<RenderComponentProps>`](#rendercomponentprops) | Yes       | This component is rendered for each item of your `items` prop array. It should accept three props: `index`, `width`, and `data`. See [`RenderComponentProps`](#rendercomponentprops).                                                                                                                                                                                                                                                                        |

**Grid container options**

| Prop         | Type                                                                            | Default  | Required? | Description                                                                                                                   |
| ------------ | ------------------------------------------------------------------------------- | -------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- |
| as           | <code>keyof JSX.IntrinsicElements &#0124; React.ComponentType&lt;any&gt;</code> | `"div"`  | No        | This is the type of element the grid container will be rendered as.                                                           |
| id           | `string`                                                                        |          | No        | Optionally gives the grid container an `id` prop.                                                                             |
| className    | `string`                                                                        |          | No        | Optionally gives the grid container a `className` prop.                                                                       |
| style        | `React.CSSProperties`                                                           |          | No        | Adds extra `style` attributes to the container in addition to those created by the [`useMasonry()`](#usemasonryoptions) hook. |
| role         | <code>"grid" &#124; "list"</code>                                               | `"grid"` | No        | Optionally swap out the accessibility `role` prop of the container and its items.                                             |
| tabIndex     | `number`                                                                        | `0`      | No        | Change the `tabIndex` of the grid container.                                                                                  |
| containerRef | <code>React.MutableRefObject&lt;HTMLElement &#0124; null&gt;</code>             |          | No        | Forwards a React ref to the grid container.                                                                                   |

**Grid item options**

| Prop               | Type                                                                            | Default                  | Required? | Description                                                                                                                                                                                                                                                                                                                                                                   |
| ------------------ | ------------------------------------------------------------------------------- | ------------------------ | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| itemAs             | <code>keyof JSX.IntrinsicElements &#0124; React.ComponentType&lt;any&gt;</code> | `"div"`                  | No        | This is the type of element the grid items will be rendered as.                                                                                                                                                                                                                                                                                                               |
| itemStyle          | `React.CSSProperties`                                                           |                          | No        | Adds extra `style` attributes to the grid items in addition to those created by the [`useMasonry()`](#usemasonryoptions) hook.                                                                                                                                                                                                                                                |
| itemHeightEstimate | `number`                                                                        | `300`                    | No        | This value is used for estimating the initial height of the masonry grid. It is important for the UX of the scrolling behavior and in determining how many `items` to render in a batch, so it's wise to set this value with some level accuracy, though it doesn't need to be perfect.                                                                                       |
| itemKey            | <code>(data: any, index: number) => string &#124; number</code>                 | `(data, index) => index` | No        | The value returned here must be unique to the item. By default, the key is the item's index. This is ok if your collection of items is never modified. Setting this property ensures that the component in `render` is reused each time the masonry grid is reflowed. A common pattern would be to return the item's database ID here if there is one, e.g. `data => data.id` |

**Callbacks**

| Prop     | Type                                                                                        | Default | Required? | Description                                                                              |
| -------- | ------------------------------------------------------------------------------------------- | ------- | --------- | ---------------------------------------------------------------------------------------- |
| onRender | <code>(startIndex: number, stopIndex: number &#124; undefined, items: any[]) => void</code> |         | No        | This callback is invoked any time the items currently being rendered by the grid change. |

**Other options**

| Prop           | Type             | Default | Required? | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| -------------- | ---------------- | ------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| overscanBy     | `number`         | `2`     | No        | This number is used for determining the number of grid cells outside of the visible window to render. The default value is `2` which means "render 2 windows worth (2 \* `height`) of content before and after the items in the visible window". A value of `3` would be 3 windows worth of grid cells, so it's a linear relationship. Overscanning is important for preventing tearing when scrolling through items in the grid, but setting too high of a value may create too much work for React to handle, so it's best that you tune this value accordingly. |
| resizeObserver | `ResizeObserver` |         | No        | A resize observer that tracks mutations to the grid cells and forces the Masonry grid to recalculate its layout if any cells affect column heights change. Check out the [`useResizeObserver()`](#useresizeobserverpositioner) hook and [`createResizeObserver()`](#createresizeobserverpositioner-updater) utility.                                                                                                                                                                                                                                               |

---

### usePositioner(options, deps?)

This hook creates the grid cell positioner and cache required by [`useMasonry()`](#usemasonryoptions). This is
the meat of the grid's layout algorithm, determining which cells to render at a given scroll
position, as well as where to place new items in the grid.

[Check out an example on **CodeSandbox**](https://codesandbox.io/s/usemasonry-example-3pcg9?file=/src/index.js)

```jsx harmony
import * as React from "react";
import { usePositioner, useContainerPosition, MasonryScroller } from "masonic";

const MyMasonry = ({ columnWidth = 300, columnGutter = 16, ...props }) => {
  const { width, offset } = useContainerPosition();
  const positioner = usePositioner({ width, columnWidth, columnGutter });
  return <MasonryScroller positioner={positioner} offset={offset} {...props} />;
};

Arguments

Argument Type Default Required? Description
options UsePositionerOptions | Yes Properties that determine the number of columns in the grid, as well as their widths.
deps React.DependenciesList [] No This hook will create a new positioner, clearing all existing cached positions, whenever the dependencies in this list change.

UsePositionerOptions

Argument Type Default Required? Description
width number | Yes The width of the container you're rendering the grid within, e.g. the container element's element.offsetWidth. That said, you can provide any width here.
columnWidth number 200 No The minimum column width. The usePositioner() hook will automatically size the columns to fill their container based upon the columnWidth and columnGutter values. It will never render anything smaller than this width unless its container itself is smaller than its value. This property has no effect if you're providing a columnCount.
columnGutter number 0 No This sets the horizontal space between grid columns in pixels. If rowGutter is not set, this also sets the vertical space between cells within a column in pixels.
rowGutter number Same as columnGutter No This sets the vertical space between cells within a column in pixels.
columnCount number | No By default, usePositioner() derives the column count from the columnWidth, columnGutter, and width props. However, in some situations it is nice to be able to override that behavior (e.g. creating a <List>-like component).
maxColumnCount number | No Limits the number of columns used by usePositioner(). Useful for implementing responsive layouts.

Returns a Positioner

Positioner

export interface Positioner {
  /**
   * The number of columns in the grid
   */
  columnCount: number;
  /**
   * The width of each column in the grid
   */
  columnWidth: number;
  /**
   * Sets the position for the cell at `index` based upon the cell's height
   */
  set: (index: number, height: number) => void;
  /**
   * Gets the `PositionerItem` for the cell at `index`
   */
  get: (index: number) => PositionerItem | undefined;
  /**
   * Updates cells based on their indexes and heights
   * positioner.update([index, height, index, height, index, height...])
   */
  update: (updates: number[]) => void;
  /**
   * Searches the interval tree for grid cells with a `top` value in
   * betwen `lo` and `hi` and invokes the callback for each item that
   * is discovered
   */
  range: (
    lo: number,
    hi: number,
    renderCallback: (index: number, left: number, top: number) => void
  ) => void;
  /**
   * Returns the number of grid cells in the cache
   */
  size: () => number;
  /**
   * Estimates the total height of the grid
   */
  estimateHeight: (itemCount: number, defaultItemHeight: number) => number;
  /**
   * Returns the height of the shortest column in the grid
   */
  shortestColumn: () => number;
  /**
   * Returns all `PositionerItem` items
   */
  all: () => PositionerItem[];
}

export interface PositionerItem {
  /**
   * This is how far from the top edge of the grid container in pixels the
   * item is placed
   */
  top: number;
  /**
   * This is how far from the left edge of the grid container in pixels the
   * item is placed
   */
  left: number;
  /**
   * This is the height of the grid cell
   */
  height: number;
  /**
   * This is the column number containing the grid cell
   */
  column: number;
}

useScroller(offset?, fps?)

A hook for tracking whether the window is currently being scrolled and it's scroll position on the y-axis. These values are used for determining which grid cells to render and when to add styles to the masonry container that maximize scroll performance.

Check out an example on CodeSandbox

`jsx harmony import * as React from "react"; import { useMasonry, usePositioner, useScroller } from "masonic";

const MyMasonry = (props) => { const containerRef = React.useRef(null); const { offset, width } = useContainerPosition(containerRef); const positioner = usePositioner({ width }); const { scrollTop, isScrolling } = useScroller(offset);

return useMasonry({ ...props, containerRef, positioner, scrollTop, isScrolling, }); };


#### Arguments

| Argument | Type     | Description                                                                                                                                                                                                                                                                                                                                                      |
| -------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| offset   | `number` | The vertical space in pixels between the top of the grid container and the top of the browser `document.documentElement`.                                                                                                                                                                                                                                        |
| fps      | `number` | This determines how often (in frames per second) to update the scroll position of the browser `window` in state, and as a result the rate the masonry grid recalculates its visible cells. The default value of `12` has been very reasonable in my own testing, but if you have particularly heavy `render` components it may be prudent to reduce this number. |

#### Returns `{scrollTop: number; isScrolling: boolean}`

---

### useContainerPosition(elementRef, deps?)

A hook for measuring the width of the grid container, as well as its distance
from the top of the document. These values are necessary to correctly calculate the number/width
of columns to render, as well as the number of rows to render.

[Check out an example on **CodeSandbox**](https://codesandbox.io/s/usemasonry-example-3pcg9?file=/src/index.js)

```jsx harmony
import * as React from "react";
import { useWindowSize } from "@react-hook/window-size";
import { useContainerPosition, MasonryScroller } from "masonic";

const MyMasonry = (props) => {
  const containerRef = React.useRef(null);
  const [windowWidth, windowHeight] = useWindowSize();
  const { offset, width } = useContainerRect(
    containerRef,
    // In this example, we want to recalculate the `offset` and `width`
    // any time the size of the window changes
    [windowWidth, windowHeight]
  );

  return (
    <MasonryScroller
      width={width}
      height={windowHeight}
      containerRef={containerRef}
      {...props}
    />
  );
};

Arguments

Argument Type Description
elementRef number A ref object created by React.useRef(). That ref should be provided to the containerRef property in useMasonry().
deps React.DependenciesList You can force this hook to recalculate the offset and width whenever this dependencies list changes. A common dependencies list might look like [windowWidth, windowHeight], which would force the hook to recalculate any time the size of the browser window changed.

Returns ContainerPosition

ContainerPosition

export interface ContainerPosition {
  /**
   * The distance in pixels between the top of the element in `elementRef` and the top of
   * the `document.documentElement`.
   */
  offset: number;
  /**
   * The `offsetWidth` of the element in `elementRef`.
   */
  width: number;
}

useScrollToIndex(positioner, options?)

A hook that creates a callback for scrolling to a specific index in the "items" array.

Check out an example on CodeSandbox

`jsx harmony import * as React from "react"; import { useMasonry, usePositioner, useContainerPosition, useScroller, useScrollToIndex, } from "masonic";

const MyMasonry = (props) => { const containerRef = React.useRef(null); const { offset, width } = useContainerPosition(containerRef); const { scrollTop, isScrolling } = useScroller(offset); const positioner = usePositioner({ width }); const scrollToIndex = useScrollToIndex(positioner);

React.useEffect(() => { if (props.scrollToIndex) { scrollToIndex(props.scrollToIndex); } }, [props.scrollToIndex, scrollToIndex]);

return useMasonry({ ...props, containerRef, positioner, scrollTop, isScrolling, }); };


#### Arguments

| Argument   | Type                                                  | Description                                                                       |
| ---------- | ----------------------------------------------------- | --------------------------------------------------------------------------------- |
| positioner | [`Positioner`](#positioner)                           | A positioner created by the [`usePositioner()`](#usepositioner) hook.             |
| options    | [`UseScrollToIndexOptions`](#usescrolltoindexoptions) | Configuration options. See [`UseScrollToIndexOptions`](#usescrolltoindexoptions). |

#### `UseScrollToIndexOptions`

| Option  | Type                                                                  | Description                                                                                    |
| ------- | --------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| element | `Window` \| `HTMLElement` \| `React.RefObject<HTMLElement>` \| `null` | The window element or a React ref for the window element. That is, this is the grid container. |
| align   | `"top"` \| `"center"` \| `"bottom"`                                   | Sets the vertical alignment of the cell within the grid container.                             |
| height  | `number`                                                              | The height of the grid.                                                                        |
| offset  | `number`                                                              | The vertical space in pixels between the top of the grid container and the top of the window.  |

#### Returns `(index: number) => void`

---

### useResizeObserver(positioner)

This hook creates a resize observer that forces updates to the grid cell positions when mutations are
made to cells affecting their height.

[Check out an example on **CodeSandbox**](https://codesandbox.io/s/useresizeobserver-example-w7r9i?file=/src/index.js)

```jsx harmony
import * as React from "react";
import { useMasonry, usePositioner, useResizeObserver } from "masonic";

const MyMasonry = (props) => {
  const positioner = usePositioner({ width: 1024 });
  const resizeObserver = useResizeObserver(positioner);

  return useMasonry({
    positioner,
    resizeObserver,
    scrollTop,
    isScrolling,
    height,
    ...props,
  });
};

Arguments

Argument Type Description
positioner Positioner The cell positioner created by the usePositioner() hook.

Returns a ResizeObserver


useInfiniteLoader(loadMoreItems, options?)

A utility hook for seamlessly adding infinite scroll behavior to the useMasonry() hook and the components that use it. This hook invokes a callback each time the last rendered index surpasses the total number of items in your items array or the number defined in the totalItems option.

Check out an example on CodeSandbox

`jsx harmony import * as React from "react"; import { Masonry, useInfiniteLoader } from "masonic";

const InfiniteMasonry = (props) => { const [items, setItems] = useState([ /* initial items */ ]); const fetchMoreItems = async (startIndex, stopIndex, currentItems) => { const nextItems = await fetch( /api/get-more?after=${startIndex}&limit=${startIndex + stopIndex} );

setItems((current) => [...current, ...nextItems]);

}; const maybeLoadMore = useInfiniteLoader(fetchMoreItems, { isItemLoaded: (index, items) => !!items[index], });

return <Masonry {...props} items={items} onRender={maybeLoadMore} />; }; `

Arguments

Argument Type Description
loadMoreItems (startIndex: number, stopIndex: number, items: any[]) => any This callback is invoked when more rows must be loaded. It will be used to determine when to refresh the list with the newly-loaded data.
options UseInfiniteLoaderOptions Configuration object for your loader, see UseInfiniteLoaderOptions below.

UseInfiniteLoaderOptions

Property Type Default Description

changelog

4.1.0 (2025-04-22)

Features

  • use-positioner: add maxColumnWidth property (#178) (850e21a)

4.0.1 (2024-07-30)

Bug Fixes

4.0.0 (2024-04-26)

Bug Fixes

Features

BREAKING CHANGES

  • removes the resize observer ponyfill.

Moving forward people will have to include their own global polyfill if they need one.

3.7.0 (2022-09-16)

Features

  • use-positioner: add maxColumnCount property (#132) (dbec4ff)

3.6.5 (2022-04-28)

Bug Fixes

  • use-masonry: should update when positioner changes (#113) (55cc606)

3.6.4 (2022-02-26)

Bug Fixes

  • use-positioner: column count calculation (#108) (8d5343b)

3.6.3 (2022-02-26)

Bug Fixes

  • use-resize-observer: resolve type conflict (#100) (38b80bc)

3.6.2 (2022-02-17)

Bug Fixes

  • should update elements' position's height after resized in a short duration (#106) (4384dfb)

3.6.1 (2021-10-23)

Bug Fixes

  • use-scroller: unsubscribe from updates when hook has unmounted (#97) (2117625)

Changelog

All notable changes to this project will be documented in this file. See standard-version for commit guidelines.

3.6.0 (2021-10-23)

Features

3.5.0 (2021-10-14)

Features

  • positioner exposes all API (7529eea), closes #88

3.4.1 (2021-02-26)

Bug Fixes

  • use-masonry: rename griditem to gridcell (45a1e6b)

3.4.0 (2020-12-29)

Features

  • expose createIntervalTree (e0c0a20)

3.3.10 (2020-09-11)

Bug Fixes

  • use-masonry: fix onRender type (1f0af01), closes #43

3.3.9 (2020-09-11)

Bug Fixes

  • use-positioner: re-initialization in StrictMode (ebe6b9c)

3.3.8 (2020-09-09)

Bug Fixes

  • use-resize-observer: fix ResizeObserver loop limit exceeded (140883d), closes #39

3.3.7 (2020-09-09)

Bug Fixes

  • use-positioner: re-initialize positioner instance before render (fbaff55), closes #12

3.3.6 (2020-09-09)

3.3.3 (2020-07-21)

Bug Fixes

  • use-masonry: fix "Cannot assign to readonly property" error (49aad2f), closes #31

3.3.2 (2020-07-17)

Bug Fixes

  • use-resize-observer: fix height measurement in Chrome 84 (ae40ece), closes #28

3.3.1 (2020-07-04)

Bug Fixes

  • masonry: fix loop in scrollToIndex effect (dae9984)

3.3.0 (2020-07-04)

Features

  • masonry: add scrollToIndex (8847c07), closes #19
  • add generic typing to masonry components/hooks (45e0380)

Bug Fixes

  • use-masonry: add a descriptive error message when data is undefined (b69f52f)
  • use-positioner: fix positioner not clearing before DOM updates (d599e62)

3.2.0 (2020-06-17)