- Fixed a problem with project logo not displaying correctly in the README for the Firefox browser.
useDynamicRowHeightshould not instantiateResizeObserverwhen server-rendering
- Use
defaultHeight/defaultWidthprop to server render initial set of rows/cells - Adjust TypeScript return type for
rowComponent/cellComponentto work around aReactNodevsReactElementmismatch caused by #875
- Update README docs
- Update TS Doc comments for
ListandGridimperative methods to specify when a method throws. - Throw a
RangeError(instead of a regularError) if an invalid index is passed to one of the imperative scroll-to methods.
The return type of List and Grid components is explicitly annotated as ReactElement. The return type of rowComponent and cellComponent changed from ReactNode to ReactElement. This was done to fix TypeScript warnings for React versions 18.0 - 18.2. (See issue #875)
- Fix possible scroll-jump scenario with
useDynamicRowHeight
- Support for dynamic row heights via new
useDynamicRowHeighthook.
const rowHeight = useDynamicRowHeight({
defaultRowHeight: 50
});
return <List rowHeight={rowHeight} {...rest} />;- Smaller NPM bundle; (docs are no longer included as part of the bundle due to the added size)
Prevent ResizeObserver API from being called at all if an explicit List height (or Grid width and height) is provided.
Grids with only one row no longer incorrectly set cell height to 100%.
Improved ARIA support:
- Add better default ARIA attributes for outer
HTMLDivElement - Add optional
ariaAttributesprop to row and cell renderers to simplify better ARIA attributes for user-rendered cells - Remove intermediate
HTMLDivElementfromListandGrid- This may enable more/better custom CSS styling
- This may also enable adding an optional
childrenprop toListandGridfor e.g. overlays/tooltips
- Add optional
tagNameprop; defaults to"div"but can be changed to e.g."ul"
// Example of how to use new `ariaAttributes` prop
function RowComponent({
ariaAttributes,
index,
style,
...rest
}: RowComponentProps<object>) {
return (
<div style={style} {...ariaAttributes}>
...
</div>
);
}Added optional children prop to better support edge cases like sticky rows.
Minor changes to onRowsRendered and onCellsRendered callbacks to make it easier to differentiate between visible items and items rendered due to overscan settings. These methods will now receive two params– the first for visible rows and the second for all rows (including overscan), e.g.:
function onRowsRendered(
visibleRows: {
startIndex: number;
stopIndex: number;
},
allRows: {
startIndex: number;
stopIndex: number;
}
): void {
// ...
}
function onCellsRendered(
visibleCells: {
columnStartIndex: number;
columnStopIndex: number;
rowStartIndex: number;
rowStopIndex: number;
},
allCells: {
columnStartIndex: number;
columnStopIndex: number;
rowStartIndex: number;
rowStopIndex: number;
}
): void {
// ...
}Fixed edge-case bug with Grid imperative API scrollToCell method and "smooth" scrolling behavior.
- Remove ARIA
roleattribute fromListandGrid. This resulted in potentially invalid configurations (e.g. a ARIA list should contain at least one listitem but that was not enforced by this library). Users of this library should specify theroleattribute that makes the most sense to them based on mdn guidelines. For example:
<List
role="list"
rowComponent={RowComponent}
rowCount={names.length}
rowHeight={25}
rowProps={{ names }}
/>;
function RowComponent({ index, style, ...rest }: RowComponentProps<object>) {
return (
<div role="listitem" style={style}>
...
</div>
);
}Version 2 is a major rewrite that offers the following benefits:
- More ergonomic props API
- Automatic memoization of row/cell renderers and props/context
- Automatically sizing for
ListandGrid(no more need forAutoSizer) - Native TypeScript support (no more need for
@types/react-window) - Smaller bundle size
This section contains a couple of examples for common upgrade paths. Please refer to the documentation for more information.
import AutoSizer from "react-virtualized-auto-sizer";
import { FixedSizeList, type ListChildComponentProps } from "react-window";
function Example({ names }: { names: string[] }) {
const itemData = useMemo<ItemData>(() => ({ names }), [names]);
return (
<AutoSizer>
{({ height, width }) => (
<FixedSizeList
children={Row}
height={height}
itemCount={names.length}
itemData={itemData}
itemSize={25}
width={width}
/>
)}
</AutoSizer>
);
}
function Row({
data,
index,
style
}: ListChildComponentProps<{
names: string[];
}>) {
const { names } = data;
const name = names[index];
return <div style={style}>{name}</div>;
}import { List, type RowComponentProps } from "react-window";
function Example({ names }: { names: string[] }) {
// You don't need to useMemo for rowProps;
// List will automatically memoize them
return (
<List
rowComponent={RowComponent}
rowCount={names.length}
rowHeight={25}
rowProps={{ names }}
/>
);
}
function RowComponent({
index,
names,
style
}: RowComponentProps<{
names: string[];
}>) {
const name = names[index];
return <div style={style}>{name}</div>;
}import AutoSizer from "react-virtualized-auto-sizer";
import { VariableSizeList, type ListChildComponentProps } from "react-window";
function Example({ items }: { items: Item[] }) {
const itemData = useMemo<ItemData>(() => ({ items }), [items]);
const itemSize = useCallback(
(index: number) => {
const item = itemData.items[index];
return item.type === "header" ? 40 : 20;
},
[itemData]
);
return (
<AutoSizer>
{({ height, width }) => (
<VariableSizeList
children={Row}
height={height}
itemCount={items.length}
itemData={itemData}
itemSize={itemSize}
width={width}
/>
)}
</AutoSizer>
);
}
function itemSize();
function Row({
data,
index,
style
}: ListChildComponentProps<{
items: Item[];
}>) {
const { items } = data;
const item = items[index];
return <div style={style}>{item.label}</div>;
}import { List, type RowComponentProps } from "react-window";
type RowProps = {
items: Item[];
};
function Example({ items }: { items: Item[] }) {
// You don't need to useMemo for rowProps;
// List will automatically memoize them
return (
<List
rowComponent={RowComponent}
rowCount={items.length}
rowHeight={rowHeight}
rowProps={{ items }}
/>
);
}
// The rowHeight method also receives the extra props,
// so it can be defined at the module level
function rowHeight(index: number, { item }: RowProps) {
return item.type === "header" ? 40 : 20;
}
function RowComponent({ index, items, style }: RowComponentProps<RowProps>) {
const item = items[index];
return <div style={style}>{item.label}</div>;
}import AutoSizer from "react-virtualized-auto-sizer";
import { FixedSizeGrid, type GridChildComponentProps } from "react-window";
function Example({ data }: { data: Data[] }) {
const itemData = useMemo<ItemData>(() => ({ data }), [data]);
return (
<AutoSizer>
{({ height, width }) => (
<FixedSizeGrid
children={Cell}
columnCount={data[0]?.length ?? 0}
columnWidth={100}
height={height}
itemData={itemData}
rowCount={data.length}
rowHeight={35}
width={width}
/>
)}
</AutoSizer>
);
}
function Cell({
columnIndex,
data,
rowIndex,
style
}: GridChildComponentProps<{
names: string[];
}>) {
const { data } = data;
const datum = data[index];
return <div style={style}>...</div>;
}import { FixedSizeGrid, type GridChildComponentProps } from "react-window";
function Example({ data }: { data: Data[] }) {
// You don't need to useMemo for cellProps;
// Grid will automatically memoize them
return (
<Grid
cellComponent={Cell}
cellProps={{ data }}
columnCount={data[0]?.length ?? 0}
columnWidth={75}
rowCount={data.length}
rowHeight={25}
/>
);
}
function Cell({
columnIndex,
data,
rowIndex,
style
}: CellComponentProps<{
data: Data[];
}>) {
const datum = data[rowIndex][columnIndex];
return <div style={style}>...</div>;
}import AutoSizer from "react-virtualized-auto-sizer";
import { VariableSizeGrid, type GridChildComponentProps } from "react-window";
function Example({ data }: { data: Data[] }) {
const itemData = useMemo<ItemData>(() => ({ data }), [data]);
const columnWidth = useCallback(
(columnIndex: number) => {
// ...
},
[itemData]
);
const rowHeight = useCallback(
(rowIndex: number) => {
// ...
},
[itemData]
);
return (
<AutoSizer>
{({ height, width }) => (
<VariableSizeGrid
children={Cell}
columnCount={data[0]?.length ?? 0}
columnWidth={columnWidth}
height={height}
itemData={itemData}
rowCount={data.length}
rowHeight={rowHeight}
width={width}
/>
)}
</AutoSizer>
);
}
function Cell({
columnIndex,
data,
rowIndex,
style
}: GridChildComponentProps<{
names: string[];
}>) {
const { data } = data;
const datum = data[index];
return <div style={style}>...</div>;
}import { FixedSizeGrid, type GridChildComponentProps } from "react-window";
type CellProps = {
data: Data[];
};
function Example({ data }: { data: Data[] }) {
// You don't need to useMemo for cellProps;
// Grid will automatically memoize them
return (
<Grid
cellComponent={Cell}
cellProps={{ data }}
columnCount={data[0]?.length ?? 0}
columnWidth={columnWidth}
rowCount={data.length}
rowHeight={rowHeight}
/>
);
}
// The columnWidth method also receives the extra props,
// so it can be defined at the module level
function columnWidth(columnIndex: number, { data }: CellProps) {
// ...
}
// The rowHeight method also receives the extra props,
// so it can be defined at the module level
function rowHeight(rowIndex: number, { data }: CellProps) {
// ...
}
function Cell({
columnIndex,
data,
rowIndex,
style
}: CellComponentProps<CellProps>) {
const datum = data[rowIndex][columnIndex];
return <div style={style}>...</div>;
}The following requirements are new in version 2 and may be reasons to consider not upgrading:
- Peer dependencies now require React version 18 or newer
ResizeObserverprimitive (or polyfill) is required unless explicit pixel dimensions are provided viastyleprop; (see documentation for more)
- Dependencies updated to include React 19
- Fix scrollDirection when direction is RTL (#690)
- Readme changes
- 🐛
scrollToItemaccounts for scrollbar size in the uncommon case where a List component has scrolling in the non-dominant direction (e.g. a "vertical" layout list also scrolls horizontally).
- ✨ Updated peer dependencies to include React v18.
- ✨ Updated peer dependencies to include React v17.
- ✨ Added UMD (dev and prod) build - (emmanueltouzery - #281)
- 🐛 Fixed size list and grid components now accurately report
visibleStopIndexinonItemsRendered. (Previously this value was incorrectly reported as one index higher.) - (justingrant - #274) - 🐛 Fixed size list and grid components
scrollToItem"center" mode when the item being scrolled to is near the viewport edge. - (justingrant - #274)
- 🐛 Edge case bug-fix for
scrollToItemwhen scrollbars are present (MarkFalconbridge - #267) - 🐛 Fixed RTL scroll offsets for non-Chromium Edge (MarkFalconbridge - #268)
- 🐛 Flow types improved (TrySound - #260)
- ✨ Deprecated grid props
overscanColumnsCountandoverscanRowsCountprops in favor of more consistently namedoverscanColumnCountandoverscanRowCount. (nihgwu - #229) - 🐛 Fixed shaky elastic scroll problems present in iOS Safari. #244
- 🐛 Fixed RTL edge case bugs and broken scroll-to-item behavior. #159
- 🐛 Fixed broken synchronized scrolling for RTL lists/grids. #198
- 🐛 Replaced an incorrect empty-string value for
pointer-eventswithundefined(oliviertassinari - #210)
- 🐛 Add guards to avoid invalid scroll offsets when
scrollTo()is called with a negative offset or whenscrollToItemis called with invalid indices (negative or too large).
- 🎉 Grid
scrollToItemsupports optionalrowIndexandcolumnIndexparams (jgoz - #174) - DEV mode checks for
WeakSetsupport before using it to avoid requiring a polyfill for IE11 - (jgoz - #167)
- 🐛 Bugfix for RTL when scrolling back towards the beginning (right) of the list.
- 🐛 Bugfix to account for differences between Chrome and non-Chrome browsers with regard to RTL and "scroll" events.
- 🎉 RTL support added for lists and grids. Special thanks to davidgarsan for his support. - #156
- 🐛 Grid
scrollToItemmethods take scrollbar size into account when aligning items - #153
- 🐛 Edge case bug fix for
VariableSizeListandVariableSizeGridwhen the number of items decreases while a scroll is in progress. - (iamsolankiamit - #138)
- 🐛 Updated
getDerivedStateFlow annotations to address a warning in a newer version of Flow.
- 🎉 Added advanced memoization helpers methods
areEqualandshouldComponentUpdatefor item renderers. - #114
- 🎉 List and Grid components now "overscan" (pre-render) in both directions when scrolling is not active. When scrolling is in progress, cells are only pre-rendered in the direction being scrolled. This change has been made in an effort to reduce visible flicker when scrolling starts without adding additional overhead during scroll (which is the most performance sensitive time).
- 🎉 Grid components now support separate
overscanColumnsCountandoverscanRowsCountprops. LegacyoverscanCountprop will continue to work, but with a deprecation warning in DEV mode. - 🐛 Replaced
setTimeoutwithrequestAnimationFramebased timer, to avoid starvation issue forisScrollingreset. - #106 - 🎉 Renamed List and Grid
innerTagNameandouterTagNameprops toinnerElementTypeandouterElementTypeto formalize support for attaching arbitrary props (e.g. test ids) to List and Grid inner and outer DOM elements. LegacyinnerTagNameandouterTagNameprops will continue to work, but with a deprecation warning in DEV mode. - 🐛 List re-renders items if
directionprop changes. - #104
- 🎉 Pass
itemDatavalue to customitemKeycallbacks when present - #90)
- (Skipped)
- 🐛 Added Flow annotations to memoized methods to avoid a Flow warning for newer versions of Flow
- 🐛 Relaxed
childrenvalidation checks. They were too strict and didn't support new React APIs likememo.
- 🐛 Improved Flow types for class component item renderers - (nicholas-l - #77)
- 🎉 Improved Flow types to include optional
itemDataparameter. (TrySound - #66) - 🐛
VariableSizeListandVariableSizeGridno longer call size getter functions with invalid index when item count is zero.
- 🎉 Flow types added to NPM package. (TrySound - #40)
- 🎉 Relaxed grid
scrollTomethod to makescrollLeftandscrollTopparams optional (so you can only update one axis if desired). - #63) - 🐛 Fixed invalid
thispointer inVariableSizeGridthat broke theresetAfter*methods - #58) - Upgraded to babel 7 and used shared runtime helpers to reduce package size slightly. (TrySound - #48)
- Remove
overflow:hiddenfrom inner container (souporserious - #56)
- 🐛 Fixed edge case
scrollToItembug that caused lists/grids with very few items to have negative scroll offsets.
- 🐛
FixedSizeGridandFixedSizeListautomatically clear style cache when item size props change.
- 🎉 Use explicit
constructorandsuperto generate cleaner component code. (Andarist - #26) - 🎉 Add optional
shouldForceUpdateparam reset-index methods to specifyforceUpdatebehavior. (nihgwu - #32)
- 🐛 Avoid unnecessary scrollbars for lists (e.g. no horizontal scrollbar for a vertical list) unless content requires them.
- 🎉 Enable Babel
annotate-pure-callsoption so that classes compiled by "transform-es2015-classes" are annotated with#__PURE__. This enables UglifyJS to remove them if they are not referenced, improving dead code elimination in application code. (Andarist - #20) - 🎉 Update "rollup-plugin-peer-deps-external" and use new
includeDependenciesflag so that the "memoize-one" dependency does not get inlined into the Rollup bundle. (Andarist - #19) - 🎉 Enable Babel "loose" mode to reduce package size (-8%). (Andarist - #18)
Updated README.md file to remove @alpha tag from NPM installation instructions.
Initial release of library. Includes the following components:
FixedSizeGridFixedSizeListVariableSizeGridVariableSizeList