brainstate

bvaughn/react-window · source

Snapshot 0 · 2026-11-04T12:47:25Z · TypeScript · MIT

Content fingerprint9c7bc48cf75572022c8714014f9a8baf0a22466a8f3b3a0359d4c1f5c526a85a

GitHub description at capture

React components for efficiently rendering large lists and tabular data

README at capture

<img src="https://react-window.vercel.app/og.png" alt="react-window logo" width="400" height="210" />

`react-window` is a component library that helps render large lists of data quickly and without the performance problems that often go along with rendering a lot of data. It's used in a lot of places, from React DevTools to the Replay browser.

## Support

If you like this project there are several ways to support it:

- [Become a GitHub sponsor](https://github.com/sponsors/bvaughn/)
- [Become an Open Collective sponsor](https://opencollective.com/react-window#sponsor)
- or [buy me a coffee](http://givebrian.coffee/)

The following wonderful companies and individuals have sponsored react-window:

<a href="https://opencollective.com/react-window/sponsor/0/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/0/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/1/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/1/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/2/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/2/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/3/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/3/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/4/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/4/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/5/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/5/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/6/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/6/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/7/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/7/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/8/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/8/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/9/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/9/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/10/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/10/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/11/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/11/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/12/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/12/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/13/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/13/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/14/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/14/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/15/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/15/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/16/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/16/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/17/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/17/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/18/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/18/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/19/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/19/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/20/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/20/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/21/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/21/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/22/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/22/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/23/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/23/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/24/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/24/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/25/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/25/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/26/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/26/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/27/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/27/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/28/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/28/avatar.svg"></a> <a href="https://opencollective.com/react-window/sponsor/29/website" target="_blank"><img src="https://opencollective.com/react-window/sponsor/29/avatar.svg"></a>

<a href="https://opencollective.com/react-window/backer/0/website" target="_blank"><img src="https://opencollective.com/react-window/backer/0/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/1/website" target="_blank"><img src="https://opencollective.com/react-window/backer/1/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/2/website" target="_blank"><img src="https://opencollective.com/react-window/backer/2/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/3/website" target="_blank"><img src="https://opencollective.com/react-window/backer/3/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/4/website" target="_blank"><img src="https://opencollective.com/react-window/backer/4/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/5/website" target="_blank"><img src="https://opencollective.com/react-window/backer/5/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/6/website" target="_blank"><img src="https://opencollective.com/react-window/backer/6/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/7/website" target="_blank"><img src="https://opencollective.com/react-window/backer/7/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/8/website" target="_blank"><img src="https://opencollective.com/react-window/backer/8/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/9/website" target="_blank"><img src="https://opencollective.com/react-window/backer/9/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/10/website" target="_blank"><img src="https://opencollective.com/react-window/backer/10/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/11/website" target="_blank"><img src="https://opencollective.com/react-window/backer/11/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/12/website" target="_blank"><img src="https://opencollective.com/react-window/backer/12/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/13/website" target="_blank"><img src="https://opencollective.com/react-window/backer/13/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/14/website" target="_blank"><img src="https://opencollective.com/react-window/backer/14/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/15/website" target="_blank"><img src="https://opencollective.com/react-window/backer/15/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/16/website" target="_blank"><img src="https://opencollective.com/react-window/backer/16/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/17/website" target="_blank"><img src="https://opencollective.com/react-window/backer/17/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/18/website" target="_blank"><img src="https://opencollective.com/react-window/backer/18/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/19/website" target="_blank"><img src="https://opencollective.com/react-window/backer/19/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/20/website" target="_blank"><img src="https://opencollective.com/react-window/backer/20/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/21/website" target="_blank"><img src="https://opencollective.com/react-window/backer/21/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/22/website" target="_blank"><img src="https://opencollective.com/react-window/backer/22/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/23/website" target="_blank"><img src="https://opencollective.com/react-window/backer/23/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/24/website" target="_blank"><img src="https://opencollective.com/react-window/backer/24/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/25/website" target="_blank"><img src="https://opencollective.com/react-window/backer/25/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/26/website" target="_blank"><img src="https://opencollective.com/react-window/backer/26/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/27/website" target="_blank"><img src="https://opencollective.com/react-window/backer/27/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/28/website" target="_blank"><img src="https://opencollective.com/react-window/backer/28/avatar.svg"></a> <a href="https://opencollective.com/react-window/backer/29/website" target="_blank"><img src="https://opencollective.com/react-window/backer/29/avatar.svg"></a>

## Installation

Begin by installing the library from NPM:

```sh
npm install react-window
```

## TypeScript types

TypeScript definitions are included within the published `dist` folder

## FAQs

Frequently asked questions can be found [here](https://react-window.vercel.app/common-questions).

## Documentation

Documentation for this project is available at [react-window.vercel.app](https://react-window.vercel.app/).

### List

<!-- List:description:begin -->
Renders data with many rows.
<!-- List:description:end -->

#### Required props

<!-- List:required-props:begin -->

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>rowComponent</td>
      <td><p>React component responsible for rendering a row.</p>
<p>This component will receive an <code>index</code> and <code>style</code> prop by default.
Additionally it will receive prop values passed to <code>rowProps</code>.</p>
<p>ℹ️ Spread <code>ariaAttributes</code> onto the row element; they identify it as a row (e.g. so that dynamic row heights are measured reliably)</p>
<p>ℹ️ The prop types for this component are exported as <code>RowComponentProps</code></p>
</td>
    </tr>
    <tr>
      <td>rowCount</td>
      <td><p>Number of items to be rendered in the list.</p>
</td>
    </tr>
    <tr>
      <td>rowHeight</td>
      <td><p>Row height; the following formats are supported:</p>
<ul>
<li>number of pixels (number)</li>
<li>percentage of the list&#39;s current height (string)</li>
<li>function that returns the row height (in pixels) given an index and <code>rowProps</code></li>
<li>dynamic row height cache returned by the <code>useDynamicRowHeight</code> hook</li>
</ul>
<p>ℹ️ Percentage heights can&#39;t be resolved during server rendering unless a <code>defaultHeight</code> (or a pixel height via the <code>style</code> prop) is specified.</p>
<p>⚠️ Dynamic row heights are not as efficient as predetermined sizes.
It&#39;s recommended to provide your own height values if they can be determined ahead of time.</p>
</td>
    </tr>
    <tr>
      <td>rowProps</td>
      <td><p>Additional props to be passed to the row-rendering component.
List will automatically re-render rows when values in this object change.</p>
<p>⚠️ This object must not contain <code>ariaAttributes</code>, <code>index</code>, or <code>style</code> props.</p>
</td>
    </tr>
  </tbody>
</table>

<!-- List:required-props:end -->

#### Optional props

<!-- List:optional-props:begin -->

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>className</td>
      <td><p>CSS class name.</p>
</td>
    </tr>
    <tr>
      <td>style</td>
      <td><p>Optional CSS properties.
The list of rows will fill the height defined by this style.</p>
</td>
    </tr>
    <tr>
      <td>children</td>
      <td><p>Additional content to be rendered within the list (above rows).
This property can be used to render things like overlays or tooltips.</p>
</td>
    </tr>
    <tr>
      <td>defaultHeight</td>
      <td><p>Default height of list (in pixels) for initial render, before its actual height has been measured.</p>
<p>ℹ️ Lists can&#39;t be measured during server rendering, so this value determines how many rows are server rendered.
It&#39;s recommended to set this to the expected height of the list (or to specify a pixel height via the <code>style</code> prop).</p>
</td>
    </tr>
    <tr>
      <td>defaultScrollOffset</td>
      <td><p>Initial scroll offset (in pixels) of the list.
This value is only applied once, when the list first mounts with at least one row.</p>
<p>ℹ️ Server-rendered HTML can&#39;t be pre-scrolled, so server rendering always starts at the first row;
the default scroll offset is applied once the list hydrates.</p>
<p>⚠️ If the list can&#39;t be scrolled that far when the offset is applied (e.g. it is hidden with <code>display: none</code>,
or uses percentage row heights before its height has been measured), the offset is clamped or ignored and not retried.
Specify a <code>defaultHeight</code> (or a pixel height via the <code>style</code> prop) when using percentage row heights.</p>
</td>
    </tr>
    <tr>
      <td>listRef</td>
      <td><p>Ref used to interact with this component&#39;s imperative API.</p>
<p>This API has imperative methods for scrolling and a getter for the outermost DOM element.</p>
<p>ℹ️ The <code>useListRef</code> and <code>useListCallbackRef</code> hooks are exported for convenience in TypeScript projects.</p>
</td>
    </tr>
    <tr>
      <td>onResize</td>
      <td><p>Callback notified when the List&#39;s outermost HTMLElement resizes.
This may be used to (re)scroll a row into view.</p>
</td>
    </tr>
    <tr>
      <td>onRowsRendered</td>
      <td><p>Callback notified when the range of visible rows changes.</p>
</td>
    </tr>
    <tr>
      <td>overscanCount</td>
      <td><p>How many additional rows to render outside of the visible area.
This can reduce visual flickering near the edges of a list when scrolling.</p>
</td>
    </tr>
    <tr>
      <td>rowKey</td>
      <td><p>Lists use the row index as a <code>key</code> by default.
This prop can provide a custom <code>key</code> value.</p>
<p>ℹ️ Custom keys can ensure better UX for sortable or filterable lists,
particularly if your row components are stateful.
Refer to the <a href="https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key">React documentation</a> for more info.</p>
<p>⚠️ This prop cannot be auto-memoized because it is called during render.
It is important to always <code>useCallback</code> for this prop; do not use an inline function.</p>
</td>
    </tr>
    <tr>
      <td>scrollElement</td>
      <td><p>Element that scrolls the list, for lists that scroll along with other content (e.g. the page):</p>
<ul>
<li>&quot;window&quot; to scroll with the page</li>
<li>an ancestor element that scrolls (e.g. stored with a <code>useState</code> ref callback); <code>null</code> until it has mounted</li>
</ul>
<p>The list renders at its full height and only renders the rows visible within the scroll element&#39;s viewport.
Its position within the scroll element is measured whenever it renders, scrolls, or resizes,
and whenever content before it is resized, inserted, or removed (e.g. an image loading above the list).</p>
<ul>
<li><code>scrollToRow</code> scrolls the scroll element</li>
<li><code>defaultHeight</code> is used as the viewport height until the scroll element has been measured (e.g. during server rendering)</li>
<li>percentage row heights are relative to the scroll element&#39;s viewport height</li>
<li><code>defaultScrollOffset</code> is ignored</li>
</ul>
<p>ℹ️ While the scroll element is <code>null</code>, the list renders the first rows (as it does during server rendering).</p>
<p>⚠️ The list itself doesn&#39;t scroll, so its <code>onScroll</code> handler isn&#39;t called;
listen to the scroll element&#39;s &quot;scroll&quot; events instead (or use the <code>useIsScrolling</code> hook).</p>
</td>
    </tr>
    <tr>
      <td>tagName</td>
      <td><p>Can be used to override the root HTML element rendered by the List component.
The default value is &quot;div&quot;, meaning that List renders an HTMLDivElement as its root.</p>
<p>⚠️ In most use cases the default ARIA roles are sufficient and this prop is not needed.</p>
</td>
    </tr>
  </tbody>
</table>

<!-- List:optional-props:end -->

### Grid

<!-- Grid:description:begin -->
Renders data with many rows and columns.

ℹ️ Unlike `List` rows, `Grid` cell sizes must be known ahead of time.
Either static sizes or something that can be derived (from the data in `CellProps`) without rendering.
<!-- Grid:description:end -->

#### Required props

<!-- Grid:required-props:begin -->

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>cellComponent</td>
      <td><p>React component responsible for rendering a cell.</p>
<p>This component will receive <code>columnIndex</code>, <code>rowIndex</code>, and <code>style</code> props by default.
Additionally it will receive prop values passed to <code>cellProps</code>.</p>
<p>ℹ️ The prop types for this component are exported as <code>CellComponentProps</code></p>
</td>
    </tr>
    <tr>
      <td>cellProps</td>
      <td><p>Additional props to be passed to the cell-rendering component.
Grid will automatically re-render cells when values in this object change.</p>
<p>⚠️ This object must not contain <code>ariaAttributes</code>, <code>columnIndex</code>, <code>rowIndex</code>, or <code>style</code> props.</p>
</td>
    </tr>
    <tr>
      <td>columnCount</td>
      <td><p>Number of columns to be rendered in the grid.</p>
</td>
    </tr>
    <tr>
      <td>columnWidth</td>
      <td><p>Column width; the following formats are supported:</p>
<ul>
<li>number of pixels (number)</li>
<li>percentage of the grid&#39;s current width (string)</li>
<li>function that returns the column width (in pixels) given an index and <code>cellProps</code></li>
</ul>
<p>ℹ️ Percentage widths can&#39;t be resolved during server rendering unless a <code>defaultWidth</code> (or a pixel width via the <code>style</code> prop) is specified.</p>
</td>
    </tr>
    <tr>
      <td>rowCount</td>
      <td><p>Number of rows to be rendered in the grid.</p>
</td>
    </tr>
    <tr>
      <td>rowHeight</td>
      <td><p>Row height; the following formats are supported:</p>
<ul>
<li>number of pixels (number)</li>
<li>percentage of the grid&#39;s current height (string)</li>
<li>function that returns the row height (in pixels) given an index and <code>cellProps</code></li>
</ul>
<p>ℹ️ Percentage heights can&#39;t be resolved during server rendering unless a <code>defaultHeight</code> (or a pixel height via the <code>style</code> prop) is specified.</p>
</td>
    </tr>
  </tbody>
</table>

<!-- Grid:required-props:end -->

#### Optional props

<!-- Grid:optional-props:begin -->

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>className</td>
      <td><p>CSS class name.</p>
</td>
    </tr>
    <tr>
      <td>dir</td>
      <td><p>Indicates the directionality of grid cells.</p>
<p>ℹ️ The directionality of an ancestor element can&#39;t be detected during server rendering;
specify this prop explicitly for server-rendered right-to-left grids.</p>
<p>ℹ️ See HTML <code>dir</code> <a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/dir">global attribute</a> for more information.</p>
</td>
    </tr>
    <tr>
      <td>style</td>
      <td><p>Optional CSS properties.
The grid of cells will fill the height and width defined by this style.</p>
</td>
    </tr>
    <tr>
      <td>children</td>
      <td><p>Additional content to be rendered within the grid (above cells).
This property can be used to render things like overlays or tooltips.</p>
</td>
    </tr>
    <tr>
      <td>columnKey</td>
      <td><p>Grids use the column index as a <code>key</code> by default.
This prop can be used along with the <code>rowKey</code> prop to provide a custom <code>key</code> value.</p>
<p>ℹ️ Custom keys can ensure better UX for sortable or filterable grids,
particularly if your cell components are stateful.
Refer to the <a href="https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key">React documentation</a> for more info.</p>
<p>⚠️ This prop cannot be auto-memoized because it is called during render.
It is important to always <code>useCallback</code> for this prop; do not use an inline function.</p>
</td>
    </tr>
    <tr>
      <td>defaultHeight</td>
      <td><p>Default height of grid (in pixels) for initial render, before its actual height has been measured.</p>
<p>ℹ️ Grids can&#39;t be measured during server rendering, so this value determines how many rows are server rendered.
It&#39;s recommended to set this to the expected height of the grid (or to specify a pixel height via the <code>style</code> prop).</p>
</td>
    </tr>
    <tr>
      <td>defaultScrollLeft</td>
      <td><p>Initial horizontal scroll offset (in pixels) of the grid.
This value is only applied once, when the grid first mounts with at least one column.</p>
<p>ℹ️ Server-rendered HTML can&#39;t be pre-scrolled, so server rendering always starts at the first column;
the default scroll offset is applied once the grid hydrates.</p>
<p>⚠️ If the grid can&#39;t be scrolled that far when the offset is applied (e.g. it is hidden with <code>display: none</code>,
or uses percentage column widths before its width has been measured), the offset is clamped or ignored and not retried.
Specify a <code>defaultWidth</code> (or a pixel width via the <code>style</code> prop) when using percentage column widths.</p>
</td>
    </tr>
    <tr>
      <td>defaultScrollTop</td>
      <td><p>Initial vertical scroll offset (in pixels) of the grid.
This value is only applied once, when the grid first mounts with at least one row.</p>
<p>ℹ️ Server-rendered HTML can&#39;t be pre-scrolled, so server rendering always starts at the first row;
the default scroll offset is applied once the grid hydrates.</p>
<p>⚠️ If the grid can&#39;t be scrolled that far when the offset is applied (e.g. it is hidden with <code>display: none</code>,
or uses percentage row heights before its height has been measured), the offset is clamped or ignored and not retried.
Specify a <code>defaultHeight</code> (or a pixel height via the <code>style</code> prop) when using percentage row heights.</p>
</td>
    </tr>
    <tr>
      <td>defaultWidth</td>
      <td><p>Default width of grid (in pixels) for initial render, before its actual width has been measured.</p>
<p>ℹ️ Grids can&#39;t be measured during server rendering, so this value determines how many columns are server rendered.
It&#39;s recommended to set this to the expected width of the grid (or to specify a pixel width via the <code>style</code> prop).</p>
</td>
    </tr>
    <tr>
      <td>gridRef</td>
      <td><p>Imperative Grid API.</p>
<p>ℹ️ The <code>useGridRef</code> and <code>useGridCallbackRef</code> hooks are exported for convenience in TypeScript projects.</p>
</td>
    </tr>
    <tr>
      <td>onCellsRendered</td>
      <td><p>Callback notified when the range of rendered cells changes.</p>
</td>
    </tr>
    <tr>
      <td>onResize</td>
      <td><p>Callback notified when the Grid&#39;s outermost HTMLElement resizes.
This may be used to (re)scroll a cell into view.</p>
</td>
    </tr>
    <tr>
      <td>overscanCount</td>
      <td><p>How many additional rows/columns to render outside of the visible area.
This can reduce visual flickering near the edges of a grid when scrolling.</p>
</td>
    </tr>
    <tr>
      <td>rowKey</td>
      <td><p>Grids use the row index as a <code>key</code> by default.
This prop can be used along with the <code>columnKey</code> prop to provide a custom <code>key</code> value.</p>
<p>ℹ️ Custom keys can ensure better UX for sortable or filterable grids,
particularly if your cell components are stateful.
Refer to the <a href="https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key">React documentation</a> for more info.</p>
<p>⚠️ This prop cannot be auto-memoized because it is called during render.
It is important to always <code>useCallback</code> for this prop; do not use an inline function.</p>
</td>
    </tr>
    <tr>
      <td>scrollElement</td>
      <td><p>Element that scrolls the grid, for grids that scroll along with other content (e.g. the page):</p>
<ul>
<li>&quot;window&quot; to scroll with the page</li>
<li>an ancestor element that scrolls (e.g. stored with a <code>useState</code> ref callback); <code>null</code> until it has mounted</li>
</ul>
<p>The grid renders at its full height and only renders the rows (and columns) visible within the scroll element&#39;s viewport.
Its position within the scroll element is measured whenever it renders, scrolls, or resizes,
and whenever content before it is resized, inserted, or removed (e.g. an image loading above the grid).</p>
<ul>
<li>columns scroll with the scroll element too if the grid is as wide as its content (e.g. <code>style={{ width: &quot;max-content&quot; }}</code>);
otherwise the grid fills the width of its parent and its columns scroll within it</li>
<li><code>scrollToCell</code>, <code>scrollToColumn</code> and <code>scrollToRow</code> scroll whichever element scrolls each axis</li>
<li><code>defaultHeight</code> and <code>defaultWidth</code> are used as the viewport size until the scroll element has been measured (e.g. during server rendering)</li>
<li>percentage row heights and column widths are relative to the scroll element&#39;s viewport</li>
<li><code>defaultScrollLeft</code> and <code>defaultScrollTop</code> are ignored</li>
</ul>
<p>ℹ️ While the scroll element is <code>null</code>, the grid renders the first rows (as it does during server rendering).</p>
<p>⚠️ The grid&#39;s <code>onScroll</code> handler is only called when the grid scrolls its own columns;
listen to the scroll element&#39;s &quot;scroll&quot; events instead (or use the <code>useIsScrolling</code> hook).</p>
</td>
    </tr>
    <tr>
      <td>tagName</td>
      <td><p>Can be used to override the root HTML element rendered by the Grid component.
The default value is &quot;div&quot;, meaning that Grid renders an HTMLDivElement as its root.</p>
<p>⚠️ In most use cases the default ARIA roles are sufficient and this prop is not needed.</p>
</td>
    </tr>
  </tbody>
</table>

<!-- Grid:optional-props:end -->