From 55e5f71ad3063ca28a032792ca13e496831de56c Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 13 Jul 2026 19:38:33 +0400 Subject: [PATCH 1/6] fix: add `rowKey` for `List` Partially addresses https://github.com/bvaughn/react-window/issues/909. Why partially? Because this doesn't add the prop to the `Grid` component. This is basically a (partial) cherry-pick of 3ffd43c69c3067b645ff11284b646fc756725b5d. Co-authored-by: WofWca --- README.md | 14 ++++++++++++++ lib/components/list/List.tsx | 4 +++- lib/components/list/types.ts | 16 ++++++++++++++++ public/generated/docs/List.json | 13 +++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index bebfafbd..d0d1e449 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,20 @@ This may be used to (re)scroll a row into view.

overscanCount

How many additional rows to render outside of the visible area. This can reduce visual flickering near the edges of a list when scrolling.

+ + + + rowKey +

By default, lists will use an item's index as its +key. +This is okay if:

+ +

If your list does not satisfy the above constraints, +use this property to specify your own keys for items.

diff --git a/lib/components/list/List.tsx b/lib/components/list/List.tsx index ae150296..00903077 100644 --- a/lib/components/list/List.tsx +++ b/lib/components/list/List.tsx @@ -37,6 +37,7 @@ export function List< rowComponent: RowComponentProp, rowCount, rowHeight: rowHeightProp, + rowKey, rowProps: rowPropsUnstable, tagName = "div" as TagName, style, @@ -185,7 +186,7 @@ export function List< "aria-setsize": rowCount, role: "listitem" }} - key={index} + key={rowKey ? rowKey(index, rowProps) : index} index={index} style={{ position: "absolute", @@ -206,6 +207,7 @@ export function List< getCellBounds, isDynamicRowHeight, rowCount, + rowKey, rowProps, startIndexOverscan, stopIndexOverscan diff --git a/lib/components/list/types.ts b/lib/components/list/types.ts index ebcbbc1a..6f778faf 100644 --- a/lib/components/list/types.ts +++ b/lib/components/list/types.ts @@ -134,6 +134,22 @@ export type ListProps< | ((index: number, cellProps: RowProps) => number) | DynamicRowHeight; + // TODO add documentation, examples, tests, whatever else, + // and implement this for grid. + // Also check whether the `PureComponent` part still applies. + /** + * By default, lists will use an item's index as its + * [key](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key). + * This is okay if: + * - Your collections of items is never sorted or modified + * - Your item renderer is not stateful and does not extend + * `PureComponent` + * + * If your list does not satisfy the above constraints, + * use this property to specify your own keys for items. + */ + rowKey?: (index: number, data: RowProps) => React.Key; + /** * Additional props to be passed to the row-rendering component. * List will automatically re-render rows when values in this object change. diff --git a/public/generated/docs/List.json b/public/generated/docs/List.json index 9b414ca7..5832751c 100644 --- a/public/generated/docs/List.json +++ b/public/generated/docs/List.json @@ -135,6 +135,19 @@ "name": "rowHeight", "required": true }, + "rowKey": { + "description": [ + { + "content": "

By default, lists will use an item's index as its\nkey.\nThis is okay if:

\n\n" + }, + { + "content": "

If your list does not satisfy the above constraints,\nuse this property to specify your own keys for items.

\n" + } + ], + "html": "
rowKey?: (index: number, data: RowProps) => Key
", + "name": "rowKey", + "required": false + }, "rowProps": { "description": [ { From bf65628423b8d0bf5b1fd774700e0d9da7866605 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 20 Jul 2026 11:42:53 -0400 Subject: [PATCH 2/6] Update inline docs; add unit tests --- README.md | 15 ++-- lib/components/list/List.test.tsx | 113 +++++++++++++++++++++++++++++- lib/components/list/types.ts | 18 ++--- public/generated/docs/List.json | 5 +- public/generated/site-map.json | 2 +- 5 files changed, 127 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index d0d1e449..3282b654 100644 --- a/README.md +++ b/README.md @@ -153,16 +153,11 @@ This can reduce visual flickering near the edges of a list when scrolling.

rowKey -

By default, lists will use an item's index as its -key. -This is okay if:

-
    -
  • Your collections of items is never sorted or modified
  • -
  • Your item renderer is not stateful and does not extend -PureComponent
  • -
-

If your list does not satisfy the above constraints, -use this property to specify your own keys for items.

+

Lists use the row index as a key by default. +This prop allows a custom key to be used instead.

+

ℹ️ Custom keys can ensure better UX for sortable or filterable lists, +particularly if your row components are stateful. +Refer to the React documentation for more info.

diff --git a/lib/components/list/List.test.tsx b/lib/components/list/List.test.tsx index f226209b..f4424924 100644 --- a/lib/components/list/List.test.tsx +++ b/lib/components/list/List.test.tsx @@ -1,5 +1,5 @@ import { act, render, screen } from "@testing-library/react"; -import { createRef, useLayoutEffect } from "react"; +import { createRef, useEffect, useLayoutEffect, useRef } from "react"; import { beforeEach, describe, expect, test, vi } from "vitest"; import { EMPTY_OBJECT } from "../../../src/constants"; import { assert } from "../../utils/assert"; @@ -865,6 +865,117 @@ describe("List", () => { }); }); + describe("rowKey", () => { + test("is used for every rendered row", () => { + const rowKey = vi.fn((index) => index); + + render( + + ); + + const items = screen.queryAllByRole("listitem"); + expect(items).toHaveLength(7); + expect(rowKey).toHaveBeenCalledWith(0, EMPTY_OBJECT); + expect(rowKey).toHaveBeenCalledWith(1, EMPTY_OBJECT); + expect(rowKey).toHaveBeenCalledWith(2, EMPTY_OBJECT); + expect(rowKey).toHaveBeenCalledWith(3, EMPTY_OBJECT); + expect(rowKey).toHaveBeenCalledWith(4, EMPTY_OBJECT); + expect(rowKey).toHaveBeenCalledWith(5, EMPTY_OBJECT); + expect(rowKey).toHaveBeenCalledWith(6, EMPTY_OBJECT); + }); + + test("preserves state when list order changes", async () => { + let data = new Array(5).fill(true).map((_, index) => index); + + const rowKey = vi.fn((index) => data[index]); + const renderLog: string[] = []; + + function LocalRowComponent({ + data, + index, + style + }: RowComponentProps<{ data: number[] }>) { + const id = data[index]; + + const idDuringMountRef = useRef(id); + + useEffect(() => { + if (idDuringMountRef.current === id) { + renderLog.push(`index: ${index}, id: ${id}`); + return; + } + + throw Error( + `Expected id "${idDuringMountRef.current}" but was "${id}"` + ); + }); + + return ( +
+ Index {index}, id {id} +
+ ); + } + + const { rerender } = render( + + ); + + const items = screen.queryAllByRole("listitem"); + expect(items).toHaveLength(5); + expect(rowKey).toHaveBeenCalled(); + expect(renderLog).toMatchInlineSnapshot(` + [ + "index: 0, id: 0", + "index: 1, id: 1", + "index: 2, id: 2", + "index: 3, id: 3", + "index: 4, id: 4", + ] + `); + + renderLog.splice(0); + rowKey.mockReset(); + + await act(async () => { + data = [...data.reverse()]; + + rerender( + + ); + }); + + expect(rowKey).toHaveBeenCalled(); + expect(renderLog).toMatchInlineSnapshot(` + [ + "index: 0, id: 4", + "index: 1, id: 3", + "index: 2, id: 2", + "index: 3, id: 1", + "index: 4, id: 0", + ] + `); + }); + }); + describe("aria attributes", () => { test("should be set by default", () => { render( diff --git a/lib/components/list/types.ts b/lib/components/list/types.ts index 6f778faf..2530a9a8 100644 --- a/lib/components/list/types.ts +++ b/lib/components/list/types.ts @@ -134,19 +134,13 @@ export type ListProps< | ((index: number, cellProps: RowProps) => number) | DynamicRowHeight; - // TODO add documentation, examples, tests, whatever else, - // and implement this for grid. - // Also check whether the `PureComponent` part still applies. - /** - * By default, lists will use an item's index as its - * [key](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key). - * This is okay if: - * - Your collections of items is never sorted or modified - * - Your item renderer is not stateful and does not extend - * `PureComponent` + /** + * Lists use the row index as a `key` by default. + * This prop allows a custom `key` to be used instead. * - * If your list does not satisfy the above constraints, - * use this property to specify your own keys for items. + * ℹ️ Custom keys can ensure better UX for sortable or filterable lists, + * particularly if your row components are stateful. + * Refer to the [React documentation](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) for more info. */ rowKey?: (index: number, data: RowProps) => React.Key; diff --git a/public/generated/docs/List.json b/public/generated/docs/List.json index 5832751c..d0170794 100644 --- a/public/generated/docs/List.json +++ b/public/generated/docs/List.json @@ -138,10 +138,11 @@ "rowKey": { "description": [ { - "content": "

By default, lists will use an item's index as its\nkey.\nThis is okay if:

\n
    \n
  • Your collections of items is never sorted or modified
  • \n
  • Your item renderer is not stateful and does not extend\nPureComponent
  • \n
\n" + "content": "

Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.

\n" }, { - "content": "

If your list does not satisfy the above constraints,\nuse this property to specify your own keys for items.

\n" + "content": "

Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.

\n", + "intent": "primary" } ], "html": "
rowKey?: (index: number, data: RowProps) => Key
", diff --git a/public/generated/site-map.json b/public/generated/site-map.json index 7ef76570..79574d27 100644 --- a/public/generated/site-map.json +++ b/public/generated/site-map.json @@ -47,7 +47,7 @@ { "path": "/list/props", "section": "Lists", - "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", + "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n rowKey?: (index: number, data: RowProps) => Key Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", "title": "List component props" }, { From 05e6b273ce4dac5295f304f1e241afc3c723a2a7 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 20 Jul 2026 12:07:50 -0400 Subject: [PATCH 3/6] Updated doc comments --- README.md | 2 ++ lib/components/list/types.ts | 3 +++ lib/hooks/useStableCallback.ts | 19 +++++++++++++------ public/generated/docs/List.json | 4 ++++ public/generated/site-map.json | 2 +- 5 files changed, 23 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 3282b654..755ce87a 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,8 @@ This prop allows a custom key to be used instead.

ℹ️ Custom keys can ensure better UX for sortable or filterable lists, particularly if your row components are stateful. Refer to the React documentation for more info.

+

⚠️ This prop cannot be auto-memoized because it is called during render. +It is important to always useCallback() for this prop; do not use an inline function.

diff --git a/lib/components/list/types.ts b/lib/components/list/types.ts index 2530a9a8..3e0aa8e4 100644 --- a/lib/components/list/types.ts +++ b/lib/components/list/types.ts @@ -141,6 +141,9 @@ export type ListProps< * ℹ️ Custom keys can ensure better UX for sortable or filterable lists, * particularly if your row components are stateful. * Refer to the [React documentation](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) for more info. + * + * ⚠️ This prop cannot be auto-memoized because it is called during render. + * It is important to always useCallback() for this prop; do not use an inline function. */ rowKey?: (index: number, data: RowProps) => React.Key; diff --git a/lib/hooks/useStableCallback.ts b/lib/hooks/useStableCallback.ts index 954cbb1d..d009f388 100644 --- a/lib/hooks/useStableCallback.ts +++ b/lib/hooks/useStableCallback.ts @@ -2,18 +2,25 @@ import { useCallback, useRef } from "react"; import { useIsomorphicLayoutEffect } from "./useIsomorphicLayoutEffect"; // Forked from useEventCallback (usehooks-ts) -export function useStableCallback( - fn: (args: Args) => Return -): (args: Args) => Return { +export function useStableCallback( + fn: (...args: Args) => Return +): (...args: Args) => Return; +export function useStableCallback( + fn: ((...args: Args) => Return) | undefined +): ((...args: Args) => Return) | undefined; +export function useStableCallback( + fn: ((...args: Args) => Return) | undefined +): ((...args: Args) => Return) | undefined { const ref = useRef(() => { - throw new Error("Cannot call during render."); + // This error ensures components don't render with previous/stale function + throw new Error("Cannot call an event handler while rendering."); }); useIsomorphicLayoutEffect(() => { ref.current = fn; }, [fn]); - return useCallback((args: Args) => ref.current?.(args), [ref]) as ( - args: Args + return useCallback((...args: Args) => ref.current?.(...args), [ref]) as ( + ...args: Args ) => Return; } diff --git a/public/generated/docs/List.json b/public/generated/docs/List.json index d0170794..b20a9359 100644 --- a/public/generated/docs/List.json +++ b/public/generated/docs/List.json @@ -143,6 +143,10 @@ { "content": "

Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.

\n", "intent": "primary" + }, + { + "content": "

This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback() for this prop; do not use an inline function.

\n", + "intent": "warning" } ], "html": "
rowKey?: (index: number, data: RowProps) => Key
", diff --git a/public/generated/site-map.json b/public/generated/site-map.json index 79574d27..f0fcb192 100644 --- a/public/generated/site-map.json +++ b/public/generated/site-map.json @@ -47,7 +47,7 @@ { "path": "/list/props", "section": "Lists", - "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n rowKey?: (index: number, data: RowProps) => Key Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", + "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n rowKey?: (index: number, data: RowProps) => Key Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback() for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", "title": "List component props" }, { From 902a1178417d382c6e2c7feb94b0bcd1f580bf41 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 20 Jul 2026 12:14:45 -0400 Subject: [PATCH 4/6] Fix external dependency --- package.json | 2 +- pnpm-lock.yaml | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index f04cde7e..5fbc4f46 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "react-docgen-typescript": "^2.4.0", "react-dom": "^19.2.3", "react-error-boundary": "^6.0.0", - "react-lib-tools": "0.0.52", + "react-lib-tools": "0.0.53", "react-router-dom": "^7.6.3", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-visualizer": "^6.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61f6e414..b60163a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -119,8 +119,8 @@ importers: specifier: ^6.0.0 version: 6.0.0(react@19.2.3) react-lib-tools: - specifier: 0.0.52 - version: 0.0.52(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3) + specifier: 0.0.53 + version: 0.0.53(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3) react-router-dom: specifier: ^7.6.3 version: 7.6.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6664,10 +6664,10 @@ packages: integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== } - react-lib-tools@0.0.52: + react-lib-tools@0.0.53: resolution: { - integrity: sha512-UabOEVqBSNQOV7YJuA+V/Tg2GXDiAzk7ukPqUuPlmvnerX4ri1qZr3t34RdnnD9Y5Ovm29HvuKdw/tImb6qBHg== + integrity: sha512-0KSuuryin8JbehtPtW9D9KMScWKWdE+GwDZC2SZIN9g7/7YzmoXcUxT6v+3GQ1jV3Bh7z+TJcOYY00XaeV5b8w== } peerDependencies: react: ^18.0.0 || ^19.0.0 @@ -12067,7 +12067,7 @@ snapshots: react-is@17.0.2: {} - react-lib-tools@0.0.52(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3): + react-lib-tools@0.0.53(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.8.3): dependencies: "@codemirror/lang-css": 6.3.1 "@codemirror/lang-html": 6.4.11 From 24fa095b5289460e5798cfc5f23dbf25a94686c3 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 20 Jul 2026 12:36:43 -0400 Subject: [PATCH 5/6] Add rowKey and columnKey to Grid --- README.md | 24 ++++- lib/components/grid/Grid.test.tsx | 143 +++++++++++++++++++++++++++++- lib/components/grid/Grid.tsx | 27 +++++- lib/components/grid/types.ts | 30 +++++++ lib/components/list/types.ts | 2 +- public/generated/docs/Grid.json | 36 ++++++++ public/generated/docs/List.json | 2 +- public/generated/site-map.json | 4 +- 8 files changed, 260 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 755ce87a..df44431f 100644 --- a/README.md +++ b/README.md @@ -159,7 +159,7 @@ This prop allows a custom key to be used instead.

particularly if your row components are stateful. Refer to the React documentation for more info.

⚠️ This prop cannot be auto-memoized because it is called during render. -It is important to always useCallback() for this prop; do not use an inline function.

+It is important to always useCallback for this prop; do not use an inline function.

@@ -278,6 +278,17 @@ The grid of cells will fill the height and width defined by this style.

children

Additional content to be rendered within the grid (above cells). This property can be used to render things like overlays or tooltips.

+ + + + columnKey +

Grids use the column index as a key by default. +This prop allows a custom key to be used instead.

+

ℹ️ Custom keys can ensure better UX for sortable or filterable grids, +particularly if your cell components are stateful. +Refer to the React documentation for more info.

+

⚠️ This prop cannot be auto-memoized because it is called during render. +It is important to always useCallback for this prop; do not use an inline function.

@@ -313,6 +324,17 @@ This may be used to (re)scroll a cell into view.

overscanCount

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.

+ + + + rowKey +

Grids use the row index as a key by default. +This prop allows a custom key to be used instead.

+

ℹ️ Custom keys can ensure better UX for sortable or filterable grids, +particularly if your cell components are stateful. +Refer to the React documentation for more info.

+

⚠️ This prop cannot be auto-memoized because it is called during render. +It is important to always useCallback for this prop; do not use an inline function.

diff --git a/lib/components/grid/Grid.test.tsx b/lib/components/grid/Grid.test.tsx index c98732ae..9417c382 100644 --- a/lib/components/grid/Grid.test.tsx +++ b/lib/components/grid/Grid.test.tsx @@ -1,5 +1,5 @@ import { render, screen } from "@testing-library/react"; -import { createRef, useLayoutEffect } from "react"; +import { act, createRef, useEffect, useLayoutEffect, useRef } from "react"; import { beforeEach, describe, expect, test, vi } from "vitest"; import { EMPTY_OBJECT } from "../../../src/constants"; import { @@ -76,6 +76,147 @@ describe("Grid", () => { expect(items).toHaveLength(24); }); + describe("custom keys", () => { + test("are called for every rendered column and row", () => { + const columnKey = vi.fn(({ columnIndex }) => columnIndex); + const rowKey = vi.fn(({ rowIndex }) => rowIndex); + + render( + + ); + + for (let index = 0; index < 4; index++) { + expect(columnKey).toHaveBeenCalledWith({ + columnIndex: index, + data: EMPTY_OBJECT, + rowIndex: 0 + }); + expect(columnKey).toHaveBeenCalledWith({ + columnIndex: index, + data: EMPTY_OBJECT, + rowIndex: 1 + }); + } + for (let index = 0; index < 2; index++) { + expect(rowKey).toHaveBeenCalledWith({ + data: EMPTY_OBJECT, + rowIndex: index + }); + } + }); + + test("preserves state when list order changes", async () => { + let data = [ + [1, 2, 3], + [4, 5, 6] + ]; + + const columnKey = vi.fn( + ({ columnIndex, rowIndex }) => data[rowIndex][columnIndex] + ); + const rowKey = vi.fn(({ rowIndex }) => data[rowIndex][0]); + const renderLog: string[] = []; + + function LocalCellComponent({ + columnIndex, + data, + rowIndex, + style + }: CellComponentProps<{ data: number[][] }>) { + const id = data[rowIndex][columnIndex]; + + const idDuringMountRef = useRef(id); + + useEffect(() => { + if (idDuringMountRef.current === id) { + renderLog.push( + `row: ${rowIndex}, column: ${columnIndex}, id: ${id}` + ); + return; + } + + throw Error( + `Expected id "${idDuringMountRef.current}" but was "${id}"` + ); + }); + + return
; + } + + const { rerender } = render( + + ); + + expect(columnKey).toHaveBeenCalled(); + expect(rowKey).toHaveBeenCalled(); + expect(renderLog).toMatchInlineSnapshot(` + [ + "row: 0, column: 0, id: 1", + "row: 0, column: 1, id: 2", + "row: 0, column: 2, id: 3", + "row: 1, column: 0, id: 4", + "row: 1, column: 1, id: 5", + "row: 1, column: 2, id: 6", + ] + `); + + renderLog.splice(0); + columnKey.mockReset(); + rowKey.mockReset(); + + await act(async () => { + data = [...data.reverse()]; + + rerender( + + ); + }); + + expect(columnKey).toHaveBeenCalled(); + expect(rowKey).toHaveBeenCalled(); + expect(renderLog).toMatchInlineSnapshot(` + [ + "row: 0, column: 0, id: 4", + "row: 0, column: 1, id: 5", + "row: 0, column: 2, id: 6", + "row: 1, column: 0, id: 1", + "row: 1, column: 1, id: 2", + "row: 1, column: 2, id: 3", + ] + `); + }); + }); + describe("cell sizes", () => { test("type: number (px)", () => { const { container } = render( diff --git a/lib/components/grid/Grid.tsx b/lib/components/grid/Grid.tsx index 1e19e92a..d31c03d2 100644 --- a/lib/components/grid/Grid.tsx +++ b/lib/components/grid/Grid.tsx @@ -32,6 +32,7 @@ export function Grid< children, className, columnCount, + columnKey, columnWidth, defaultHeight = 0, defaultWidth = 0, @@ -42,6 +43,7 @@ export function Grid< overscanCount = 3, rowCount, rowHeight, + rowKey, style, tagName = "div" as TagName, ...rest @@ -248,7 +250,15 @@ export function Grid< role: "gridcell" }} columnIndex={columnIndex} - key={columnIndex} + key={ + columnKey + ? columnKey({ + columnIndex, + data: cellProps, + rowIndex + }) + : columnIndex + } rowIndex={rowIndex} style={{ position: "absolute", @@ -263,7 +273,18 @@ export function Grid< } children.push( -
+
{columns}
); @@ -274,12 +295,14 @@ export function Grid< CellComponent, cellProps, columnCount, + columnKey, columnStartIndexOverscan, columnStopIndexOverscan, getColumnBounds, getRowBounds, isRtl, rowCount, + rowKey, rowStartIndexOverscan, rowStopIndexOverscan ]); diff --git a/lib/components/grid/types.ts b/lib/components/grid/types.ts index 395053c7..e0d43e4a 100644 --- a/lib/components/grid/types.ts +++ b/lib/components/grid/types.ts @@ -61,6 +61,23 @@ export type GridProps< */ columnCount: number; + /** + * Grids use the column index as a `key` by default. + * This prop allows a custom `key` to be used instead. + * + * ℹ️ Custom keys can ensure better UX for sortable or filterable grids, + * particularly if your cell components are stateful. + * Refer to the [React documentation](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) for more info. + * + * ⚠️ This prop cannot be auto-memoized because it is called during render. + * It is important to always `useCallback` for this prop; do not use an inline function. + */ + columnKey?: (args: { + columnIndex: number; + data: CellProps; + rowIndex: number; + }) => React.Key; + /** * Column width; the following formats are supported: * - number of pixels (number) @@ -201,6 +218,19 @@ export type GridProps< | string | ((index: number, cellProps: CellProps) => number); + /** + * Grids use the row index as a `key` by default. + * This prop allows a custom `key` to be used instead. + * + * ℹ️ Custom keys can ensure better UX for sortable or filterable grids, + * particularly if your cell components are stateful. + * Refer to the [React documentation](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) for more info. + * + * ⚠️ This prop cannot be auto-memoized because it is called during render. + * It is important to always `useCallback` for this prop; do not use an inline function. + */ + rowKey?: (args: { data: CellProps; rowIndex: number }) => React.Key; + /** * Optional CSS properties. * The grid of cells will fill the height and width defined by this style. diff --git a/lib/components/list/types.ts b/lib/components/list/types.ts index 3e0aa8e4..794acd43 100644 --- a/lib/components/list/types.ts +++ b/lib/components/list/types.ts @@ -143,7 +143,7 @@ export type ListProps< * Refer to the [React documentation](https://react.dev/learn/rendering-lists#keeping-list-items-in-order-with-key) for more info. * * ⚠️ This prop cannot be auto-memoized because it is called during render. - * It is important to always useCallback() for this prop; do not use an inline function. + * It is important to always `useCallback` for this prop; do not use an inline function. */ rowKey?: (index: number, data: RowProps) => React.Key; diff --git a/public/generated/docs/Grid.json b/public/generated/docs/Grid.json index e4858156..e140e05a 100644 --- a/public/generated/docs/Grid.json +++ b/public/generated/docs/Grid.json @@ -96,6 +96,24 @@ "name": "columnCount", "required": true }, + "columnKey": { + "description": [ + { + "content": "

Grids use the column index as a key by default.\nThis prop allows a custom key to be used instead.

\n" + }, + { + "content": "

Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.

\n", + "intent": "primary" + }, + { + "content": "

This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.

\n", + "intent": "warning" + } + ], + "html": "
columnKey?: (args: { columnIndex: number; data: CellProps; rowIndex: number; }) => Key
", + "name": "columnKey", + "required": false + }, "columnWidth": { "description": [ { @@ -190,6 +208,24 @@ "name": "rowHeight", "required": true }, + "rowKey": { + "description": [ + { + "content": "

Grids use the row index as a key by default.\nThis prop allows a custom key to be used instead.

\n" + }, + { + "content": "

Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.

\n", + "intent": "primary" + }, + { + "content": "

This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.

\n", + "intent": "warning" + } + ], + "html": "
rowKey?: (args: { data: CellProps; rowIndex: number; }) => Key
", + "name": "rowKey", + "required": false + }, "tagName": { "description": [ { diff --git a/public/generated/docs/List.json b/public/generated/docs/List.json index b20a9359..5ed19988 100644 --- a/public/generated/docs/List.json +++ b/public/generated/docs/List.json @@ -145,7 +145,7 @@ "intent": "primary" }, { - "content": "

This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback() for this prop; do not use an inline function.

\n", + "content": "

This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.

\n", "intent": "warning" } ], diff --git a/public/generated/site-map.json b/public/generated/site-map.json index f0fcb192..45e65353 100644 --- a/public/generated/site-map.json +++ b/public/generated/site-map.json @@ -47,7 +47,7 @@ { "path": "/list/props", "section": "Lists", - "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n rowKey?: (index: number, data: RowProps) => Key Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback() for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", + "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n rowKey?: (index: number, data: RowProps) => Key Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", "title": "List component props" }, { @@ -89,7 +89,7 @@ { "path": "/grid/props", "section": "Grids", - "text": " Renders data with many rows and columns.\n Unlike List rows, Grid cell sizes must be known ahead of time.\nEither static sizes or something that can be derived (from the data in CellProps) without rendering.\n Required props cellComponent: (props: { ariaAttributes: { \"aria-colindex\": number; role: \"gridcell\"; }; columnIndex: number; rowIndex: number; style: CSSProperties; } & CellProps) => ReactNode | null React component responsible for rendering a cell.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to cellProps.\n The prop types for this component are exported as CellComponentProps \n cellProps: CellProps Additional props to be passed to the cell-rendering component.\nGrid will automatically re-render cells when values in this object change.\n This object must not contain ariaAttributes, columnIndex, rowIndex, or style props.\n columnCount: number Number of columns to be rendered in the grid.\n columnWidth: string | number | ((index: number, cellProps: CellProps) => number) Column width; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current width (string)\nfunction that returns the column width (in pixels) given an index and cellProps \n\n rowCount: number Number of rows to be rendered in the grid.\n rowHeight: string | number | ((index: number, cellProps: CellProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \n\n Optional props children?: ReactNode Additional content to be rendered within the grid (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of grid for initial render.\nThis value is important for server rendering.\n defaultWidth?: number = 0 Default width of grid for initial render.\nThis value is important for server rendering.\n dir?: string Indicates the directionality of grid cells.\n See HTML dir global attribute for more information.\n gridRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToCell(config: { behavior?: \"auto\" | \"instant\" | \"smooth\"; columnAlign?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; columnIndex: number; rowAlign?: \"auto\" | ... 3 more ... | \"start\"; rowIndex: number; }): void; scrollToColumn(config: { ...; }): void; scrollToR... Imperative Grid API.\n The useGridRef and useGridCallbackRef hooks are exported for convenience use in TypeScript projects.\n onCellsRendered?: (visibleCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }, allCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }) => void Callback notified when the range of rendered cells changes.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the Grid's outermost HTMLElement resizes.\nThis may be used to (re)scroll a cell into view.\n overscanCount?: number = 3 How many additional rows/columns to render outside of the visible area.\nThis can reduce visual flickering near the edges of a grid when scrolling.\n style?: CSSProperties Optional CSS properties.\nThe grid of cells will fill the height and width defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", + "text": " Renders data with many rows and columns.\n Unlike List rows, Grid cell sizes must be known ahead of time.\nEither static sizes or something that can be derived (from the data in CellProps) without rendering.\n Required props cellComponent: (props: { ariaAttributes: { \"aria-colindex\": number; role: \"gridcell\"; }; columnIndex: number; rowIndex: number; style: CSSProperties; } & CellProps) => ReactNode | null React component responsible for rendering a cell.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to cellProps.\n The prop types for this component are exported as CellComponentProps \n cellProps: CellProps Additional props to be passed to the cell-rendering component.\nGrid will automatically re-render cells when values in this object change.\n This object must not contain ariaAttributes, columnIndex, rowIndex, or style props.\n columnCount: number Number of columns to be rendered in the grid.\n columnWidth: string | number | ((index: number, cellProps: CellProps) => number) Column width; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current width (string)\nfunction that returns the column width (in pixels) given an index and cellProps \n\n rowCount: number Number of rows to be rendered in the grid.\n rowHeight: string | number | ((index: number, cellProps: CellProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \n\n Optional props children?: ReactNode Additional content to be rendered within the grid (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n columnKey?: (args: { columnIndex: number; data: CellProps; rowIndex: number; }) => Key Grids use the column index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n defaultHeight?: number = 0 Default height of grid for initial render.\nThis value is important for server rendering.\n defaultWidth?: number = 0 Default width of grid for initial render.\nThis value is important for server rendering.\n dir?: string Indicates the directionality of grid cells.\n See HTML dir global attribute for more information.\n gridRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToCell(config: { behavior?: \"auto\" | \"instant\" | \"smooth\"; columnAlign?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; columnIndex: number; rowAlign?: \"auto\" | ... 3 more ... | \"start\"; rowIndex: number; }): void; scrollToColumn(config: { ...; }): void; scrollToR... Imperative Grid API.\n The useGridRef and useGridCallbackRef hooks are exported for convenience use in TypeScript projects.\n onCellsRendered?: (visibleCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }, allCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }) => void Callback notified when the range of rendered cells changes.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the Grid's outermost HTMLElement resizes.\nThis may be used to (re)scroll a cell into view.\n overscanCount?: number = 3 How many additional rows/columns to render outside of the visible area.\nThis can reduce visual flickering near the edges of a grid when scrolling.\n rowKey?: (args: { data: CellProps; rowIndex: number; }) => Key Grids use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe grid of cells will fill the height and width defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", "title": "Grid component props" }, { From b668616d72f63f87334fd1b82f167585c6681598 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Mon, 20 Jul 2026 13:02:07 -0400 Subject: [PATCH 6/6] Tweak docs comments --- CHANGELOG.md | 4 ++++ README.md | 6 +++--- lib/components/grid/types.ts | 4 ++-- lib/components/list/types.ts | 2 +- public/generated/docs/Grid.json | 4 ++-- public/generated/docs/List.json | 2 +- public/generated/site-map.json | 4 ++-- 7 files changed, 15 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f93d010..c2f434e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 2.3.0 + +- Add optional `rowKey` prop to `List` and add optional `rowKey`/`columnKey` prop to `Grid`. + ## 2.2.7 - Fixed a problem with project logo not displaying correctly in the README for the Firefox browser. diff --git a/README.md b/README.md index df44431f..862c83c5 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ This can reduce visual flickering near the edges of a list when scrolling.

rowKey

Lists use the row index as a key by default. -This prop allows a custom key to be used instead.

+This prop can provide a custom key value.

ℹ️ Custom keys can ensure better UX for sortable or filterable lists, particularly if your row components are stateful. Refer to the React documentation for more info.

@@ -283,7 +283,7 @@ This property can be used to render things like overlays or tooltips.

columnKey

Grids use the column index as a key by default. -This prop allows a custom key to be used instead.

+This prop can be used along with the rowKey prop to provide a custom key value.

ℹ️ Custom keys can ensure better UX for sortable or filterable grids, particularly if your cell components are stateful. Refer to the React documentation for more info.

@@ -329,7 +329,7 @@ This can reduce visual flickering near the edges of a grid when scrolling.

rowKey

Grids use the row index as a key by default. -This prop allows a custom key to be used instead.

+This prop can be used along with the columnKey prop to provide a custom key value.

ℹ️ Custom keys can ensure better UX for sortable or filterable grids, particularly if your cell components are stateful. Refer to the React documentation for more info.

diff --git a/lib/components/grid/types.ts b/lib/components/grid/types.ts index e0d43e4a..2c9e09e6 100644 --- a/lib/components/grid/types.ts +++ b/lib/components/grid/types.ts @@ -63,7 +63,7 @@ export type GridProps< /** * Grids use the column index as a `key` by default. - * This prop allows a custom `key` to be used instead. + * This prop can be used along with the `rowKey` prop to provide a custom `key` value. * * ℹ️ Custom keys can ensure better UX for sortable or filterable grids, * particularly if your cell components are stateful. @@ -220,7 +220,7 @@ export type GridProps< /** * Grids use the row index as a `key` by default. - * This prop allows a custom `key` to be used instead. + * This prop can be used along with the `columnKey` prop to provide a custom `key` value. * * ℹ️ Custom keys can ensure better UX for sortable or filterable grids, * particularly if your cell components are stateful. diff --git a/lib/components/list/types.ts b/lib/components/list/types.ts index 794acd43..92fcc18d 100644 --- a/lib/components/list/types.ts +++ b/lib/components/list/types.ts @@ -136,7 +136,7 @@ export type ListProps< /** * Lists use the row index as a `key` by default. - * This prop allows a custom `key` to be used instead. + * This prop can provide a custom `key` value. * * ℹ️ Custom keys can ensure better UX for sortable or filterable lists, * particularly if your row components are stateful. diff --git a/public/generated/docs/Grid.json b/public/generated/docs/Grid.json index e140e05a..d2717ce2 100644 --- a/public/generated/docs/Grid.json +++ b/public/generated/docs/Grid.json @@ -99,7 +99,7 @@ "columnKey": { "description": [ { - "content": "

Grids use the column index as a key by default.\nThis prop allows a custom key to be used instead.

\n" + "content": "

Grids use the column index as a key by default.\nThis prop can be used along with the rowKey prop to provide a custom key value.

\n" }, { "content": "

Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.

\n", @@ -211,7 +211,7 @@ "rowKey": { "description": [ { - "content": "

Grids use the row index as a key by default.\nThis prop allows a custom key to be used instead.

\n" + "content": "

Grids use the row index as a key by default.\nThis prop can be used along with the columnKey prop to provide a custom key value.

\n" }, { "content": "

Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.

\n", diff --git a/public/generated/docs/List.json b/public/generated/docs/List.json index 5ed19988..6c157eac 100644 --- a/public/generated/docs/List.json +++ b/public/generated/docs/List.json @@ -138,7 +138,7 @@ "rowKey": { "description": [ { - "content": "

Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.

\n" + "content": "

Lists use the row index as a key by default.\nThis prop can provide a custom key value.

\n" }, { "content": "

Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.

\n", diff --git a/public/generated/site-map.json b/public/generated/site-map.json index 45e65353..df3e6fd8 100644 --- a/public/generated/site-map.json +++ b/public/generated/site-map.json @@ -47,7 +47,7 @@ { "path": "/list/props", "section": "Lists", - "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n rowKey?: (index: number, data: RowProps) => Key Lists use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", + "text": " Renders data with many rows.\n Required props rowComponent: (props: { ariaAttributes: { \"aria-posinset\": number; \"aria-setsize\": number; role: \"listitem\"; }; index: number; style: CSSProperties; } & RowProps) => ReactNode | null React component responsible for rendering a row.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to rowProps.\n The prop types for this component are exported as RowComponentProps \n rowCount: number Number of items to be rendered in the list.\n rowHeight: string | number | DynamicRowHeight | ((index: number, cellProps: RowProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \ndynamic row height cache returned by the useDynamicRowHeight hook\n\n Dynamic row heights are not as efficient as predetermined sizes.\nIt's recommended to provide your own height values if they can be determined ahead of time.\n rowProps: RowProps Additional props to be passed to the row-rendering component.\nList will automatically re-render rows when values in this object change.\n This object must not contain ariaAttributes, index, or style props.\n Optional props children?: ReactNode Additional content to be rendered within the list (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n defaultHeight?: number = 0 Default height of list for initial render.\nThis value is important for server rendering.\n listRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToRow(config: { align?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; behavior?: \"auto\" | \"instant\" | \"smooth\"; index: number; }): void; }> Ref used to interact with this component's imperative API.\n This API has imperative methods for scrolling and a getter for the outermost DOM element.\n The useListRef and useListCallbackRef hooks are exported for convenience use in TypeScript projects.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the List's outermost HTMLElement resizes.\nThis may be used to (re)scroll a row into view.\n onRowsRendered?: (visibleRows: { startIndex: number; stopIndex: number; }, allRows: { startIndex: number; stopIndex: number; }) => void Callback notified when the range of visible rows changes.\n overscanCount?: number = 3 How many additional rows to render outside of the visible area.\nThis can reduce visual flickering near the edges of a list when scrolling.\n rowKey?: (index: number, data: RowProps) => Key Lists use the row index as a key by default.\nThis prop can provide a custom key value.\n Custom keys can ensure better UX for sortable or filterable lists,\nparticularly if your row components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe list of rows will fill the height defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", "title": "List component props" }, { @@ -89,7 +89,7 @@ { "path": "/grid/props", "section": "Grids", - "text": " Renders data with many rows and columns.\n Unlike List rows, Grid cell sizes must be known ahead of time.\nEither static sizes or something that can be derived (from the data in CellProps) without rendering.\n Required props cellComponent: (props: { ariaAttributes: { \"aria-colindex\": number; role: \"gridcell\"; }; columnIndex: number; rowIndex: number; style: CSSProperties; } & CellProps) => ReactNode | null React component responsible for rendering a cell.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to cellProps.\n The prop types for this component are exported as CellComponentProps \n cellProps: CellProps Additional props to be passed to the cell-rendering component.\nGrid will automatically re-render cells when values in this object change.\n This object must not contain ariaAttributes, columnIndex, rowIndex, or style props.\n columnCount: number Number of columns to be rendered in the grid.\n columnWidth: string | number | ((index: number, cellProps: CellProps) => number) Column width; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current width (string)\nfunction that returns the column width (in pixels) given an index and cellProps \n\n rowCount: number Number of rows to be rendered in the grid.\n rowHeight: string | number | ((index: number, cellProps: CellProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \n\n Optional props children?: ReactNode Additional content to be rendered within the grid (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n columnKey?: (args: { columnIndex: number; data: CellProps; rowIndex: number; }) => Key Grids use the column index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n defaultHeight?: number = 0 Default height of grid for initial render.\nThis value is important for server rendering.\n defaultWidth?: number = 0 Default width of grid for initial render.\nThis value is important for server rendering.\n dir?: string Indicates the directionality of grid cells.\n See HTML dir global attribute for more information.\n gridRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToCell(config: { behavior?: \"auto\" | \"instant\" | \"smooth\"; columnAlign?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; columnIndex: number; rowAlign?: \"auto\" | ... 3 more ... | \"start\"; rowIndex: number; }): void; scrollToColumn(config: { ...; }): void; scrollToR... Imperative Grid API.\n The useGridRef and useGridCallbackRef hooks are exported for convenience use in TypeScript projects.\n onCellsRendered?: (visibleCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }, allCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }) => void Callback notified when the range of rendered cells changes.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the Grid's outermost HTMLElement resizes.\nThis may be used to (re)scroll a cell into view.\n overscanCount?: number = 3 How many additional rows/columns to render outside of the visible area.\nThis can reduce visual flickering near the edges of a grid when scrolling.\n rowKey?: (args: { data: CellProps; rowIndex: number; }) => Key Grids use the row index as a key by default.\nThis prop allows a custom key to be used instead.\n Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe grid of cells will fill the height and width defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", + "text": " Renders data with many rows and columns.\n Unlike List rows, Grid cell sizes must be known ahead of time.\nEither static sizes or something that can be derived (from the data in CellProps) without rendering.\n Required props cellComponent: (props: { ariaAttributes: { \"aria-colindex\": number; role: \"gridcell\"; }; columnIndex: number; rowIndex: number; style: CSSProperties; } & CellProps) => ReactNode | null React component responsible for rendering a cell.\n This component will receive an index and style prop by default.\nAdditionally it will receive prop values passed to cellProps.\n The prop types for this component are exported as CellComponentProps \n cellProps: CellProps Additional props to be passed to the cell-rendering component.\nGrid will automatically re-render cells when values in this object change.\n This object must not contain ariaAttributes, columnIndex, rowIndex, or style props.\n columnCount: number Number of columns to be rendered in the grid.\n columnWidth: string | number | ((index: number, cellProps: CellProps) => number) Column width; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current width (string)\nfunction that returns the column width (in pixels) given an index and cellProps \n\n rowCount: number Number of rows to be rendered in the grid.\n rowHeight: string | number | ((index: number, cellProps: CellProps) => number) Row height; the following formats are supported:\n\nnumber of pixels (number)\npercentage of the grid's current height (string)\nfunction that returns the row height (in pixels) given an index and cellProps \n\n Optional props children?: ReactNode Additional content to be rendered within the grid (above cells).\nThis property can be used to render things like overlays or tooltips.\n className?: string CSS class name.\n columnKey?: (args: { columnIndex: number; data: CellProps; rowIndex: number; }) => Key Grids use the column index as a key by default.\nThis prop can be used along with the rowKey prop to provide a custom key value.\n Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n defaultHeight?: number = 0 Default height of grid for initial render.\nThis value is important for server rendering.\n defaultWidth?: number = 0 Default width of grid for initial render.\nThis value is important for server rendering.\n dir?: string Indicates the directionality of grid cells.\n See HTML dir global attribute for more information.\n gridRef?: Ref<{ readonly element: HTMLDivElement | null; scrollToCell(config: { behavior?: \"auto\" | \"instant\" | \"smooth\"; columnAlign?: \"auto\" | \"center\" | \"end\" | \"smart\" | \"start\"; columnIndex: number; rowAlign?: \"auto\" | ... 3 more ... | \"start\"; rowIndex: number; }): void; scrollToColumn(config: { ...; }): void; scrollToR... Imperative Grid API.\n The useGridRef and useGridCallbackRef hooks are exported for convenience use in TypeScript projects.\n onCellsRendered?: (visibleCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }, allCells: { columnStartIndex: number; columnStopIndex: number; rowStartIndex: number; rowStopIndex: number; }) => void Callback notified when the range of rendered cells changes.\n onResize?: (size: { height: number; width: number; }, prevSize: { height: number; width: number; }) => void Callback notified when the Grid's outermost HTMLElement resizes.\nThis may be used to (re)scroll a cell into view.\n overscanCount?: number = 3 How many additional rows/columns to render outside of the visible area.\nThis can reduce visual flickering near the edges of a grid when scrolling.\n rowKey?: (args: { data: CellProps; rowIndex: number; }) => Key Grids use the row index as a key by default.\nThis prop can be used along with the columnKey prop to provide a custom key value.\n Custom keys can ensure better UX for sortable or filterable grids,\nparticularly if your cell components are stateful.\nRefer to the React documentation for more info.\n This prop cannot be auto-memoized because it is called during render.\nIt is important to always useCallback for this prop; do not use an inline function.\n style?: CSSProperties Optional CSS properties.\nThe grid of cells will fill the height and width defined by this style.\n tagName?: keyof IntrinsicElements = \"div\" as TagName Can be used to override the root HTML element rendered by the List component.\nThe default value is \"div\", meaning that List renders an HTMLDivElement as its root.\n In most use cases the default ARIA roles are sufficient and this prop is not needed.\n ", "title": "Grid component props" }, {