Skip to main content

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.List (div)
|-components.Group (div+)
|-components.Item (div+)
|-footer(div*, headerFooterTag)
|-components.List (Top Items) (div)
|-components.Item (div+)
|-components.Group (div+)

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: 400 }} 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}>