Customize Rendering
The React Virtuoso component renders as several nested DIV elements. The default values in the component prop entries are div.
components.Scroller (div)
|-viewport (div)
|-header(div* headerFooterTag)
|-components.Header
|-components.List (div)
|-components.Group (div+)
|-groupItemContent
|-components.Item (div+)
|-itemContent
|-components.EmptyPlaceholder
|-footer(div*, headerFooterTag)
|-components.Footer
|-components.List (Top Items) (div)
|-components.Item (div+)
|-itemContent
|-components.Group (div+)
|-groupItemContent
Pass a custom component to the specified key in components to change rendering.
Notice that the List component must accept and pass its ref to the actual DOM element.
The example below adds borders to each customizable element.
If you pass the components inline and combine that with useState, each re-render will pass a fresh instance component, causing unnecessary unmounting and remounting.
Don't do
<Virtuoso components={{ Header:() => <div></div> }} />
Move the components outside. If you need to capture a certain state in them, use the context prop.
Example with @emotion/styled
import styled from '@emotion/styled'
import React from 'react'
import { Virtuoso } from 'react-virtuoso'
const Item = styled.div`
border: 2px solid red;
`
const ListEl = styled.div`
border: 1px solid blue;
`
const Header = () => 'Header'
const Footer = () => 'Footer'
const List = React.forwardRef((props, ref) => {
return <ListEl {...props} ref={ref} />
})
export default function App() {
return (
<Virtuoso style={{ height: '100%' }} components={{ Item, List, Header, Footer }} totalCount={30} itemContent={(idx) => `Item ${idx}`} />
)
}
TypeScript Interfaces
The types for each component are available in the Components interface. The example below annotates the Scroller custom component:
import { Components } from 'react-virtuoso'
const Scroller: Components['Scroller'] = React.forwardRef(({ style, children }, ref) => {
return (
<div style={style} ref={ref}>
{children}
</div>
)
})