A React component that can virtualise lists and any set of children

Sep 04, 2021
A React component that can virtualise lists and any set of children


A list virtualiser that can create virtual rows out of arrays or a total count, or virtualise an arbitrary set of React components.

View Demo View Github


npm i virtual-window


You can place a Virtual Window over a set of arbitrary React components by simply wrapping them

function MyComponent({ list }) { return ( <VirtualWindow> <MyComponent1 /> { => ( <SomeComponent key={} data={l} /> ))} <MyLastComponent /> </VirtualWindow> ) }

You can also use the mode where it is a virtual list, in this mode you specify a number of parameters

classNameA class to apply to the outer wrapper component
item<Simple/> a fragment like componentThe item that will be used to display this element. This component is passed properties for the item being displayed and the index of it.

e.g. <VirtualWindow list={items} item={<MyComponent withAny={prop}/>} />
itemSize36The default size to expect for items
keyFnWeakMap of items to unique integersA function to create a key for an item in the list.

e.g. <VirtualWindow list={items} keyFn={v=>}/>
listThe array of items to display
passitema string containing the name of the property to pass to the item being rendered.
onConfigureA callback function that receives properties of the Virtual Window in attributes called expectedSize and scrollingElement. The callback is triggered whenever measurement detects a change in the expected size of items.
onVisibleChangedA callback function that receives the first and last visible items as they change onVisibleChanged={(first, last)=>console.log(first, last)}.

You can use this property to update the list and provide endless scrolling.
overscan2The number of additional pages to render below and above the visible list for sizing
totalCountThe number of records to render, this is used instead of a list to have the component totally virtual. In this case the item passed to the rendered component is the index to use for the data.


By default the virtual item container has a height of 100% and a flex of 1. This allows it to resize into
various useful containers. If you need to specify a height then either size the wrapping component or pass a className
to the <VirtualWindow/>


import { VirtualWindow } from "lib/VirtualWindow" import { Box, IconButton } from "@material-ui/core" import { useState, useMemo } from "react" import { MdExpandLess, MdExpandMore } from "react-icons/md" import randomColor from "randomcolor" import { routes } from "./routes" import { makeStyles } from "@material-ui/core" const useStyles = makeStyles({ virtualBox: { height: 370, background: "#0002", overflow: "auto" } }) export const items = Array.from({ length: 2000 }, (_, i) => ({ content: i, color: randomColor() })) export default function App() { const classes = useStyles() return ( <div className="App"> <div className={classes.virtualBox}> <VirtualWindow list={items} item={<DummyItem />} /> </div> </div> ) } export function DummyItem({ item, index }) { const [extra, setExtra] = useState(item.upsized || 0) item.upsized = extra const style = useMemo( () => ({ minHeight: 34 + (index & 7) * 9 + extra, width: "100%", background: item.color }), [item.color, extra, index] ) return ( <Box display="flex" flexDirection="row" p={2} style={style}> <Box flex={1} /> <Box borderRadius={4} bgcolor="#ffffffdc" color="#444" boxShadow="inset 0 0 6px 0px #000c" p={1} display="flex" alignItems="center" > <Box mr={2}>{item.content}</Box> <Box>{JSON.stringify(style, null, 2)}</Box> <Box ml={1} onClick={() => { if (extra) { setExtra(0) } else { setExtra(Math.floor(Math.random() * 90) + 20) } }} > <IconButton color="primary"> {extra ? <MdExpandLess /> : <MdExpandMore />} </IconButton> </Box> </Box> <Box flex={1} /> </Box> ) }


On CodeSandBox