Virtualization in React Listview component

13 Jan 202524 minutes to read

UI virtualization loads only the viewable list items in a viewport, which significantly improves ListView performance when loading a large number of data items.

Module injection

To use UI Virtualization, we need to inject its virtualization service in the App. This modules should be injected into the ListView using the Inject directive as like the below code snippet.

import { ListViewComponent, Inject, Virtualization } from '@syncfusion/ej2-react-lists';

....
....

return (
    // specifies the tag to render the ListView component
    <ListViewComponent id='ui-list' dataSource={listData} enableVirtualization={true} >
        <Inject services={[Virtualization]} />
    </ListViewComponent>
);
return (
// specifies the tag to render the ListView component
<ListViewComponent id='ui-list' dataSource={listData} enableVirtualization={true}>
              <Inject services={[Virtualization]}/>
          </ListViewComponent>);
export {};

Getting started

UI virtualization can be enabled in ListView by setting the enableVirtualization property to true. There are two types of scrollers available:

Window scroll - This scroller is used in ListView by default.

Container scroll - This will be used, if the height property of ListView was set.

import * as React from 'react';
import * as ReactDOM from "react-dom";
import { ListViewComponent, Inject, Virtualization } from '@syncfusion/ej2-react-lists';
function App() {
    // define the array of Json
    let listData;
    listData = [
        { text: "Nancy", id: "0" },
        { text: "Andrew", id: "1" },
        { text: "Janet", id: "2" },
        { text: "Margaret", id: "3" },
        { text: "Steven", id: "4" },
        { text: "Laura", id: "5" },
        { text: "Robert", id: "6" },
        { text: "Michael", id: "7" },
        { text: "Albert", id: "8" },
        { text: "Nolan", id: "9" }
    ];
    for (let i = 10; i <= 1010; i++) {
        let index = parseInt((Math.random() * 10).toString());
        listData.push({ text: listData[index].text, id: i.toString() });
    }
    return (
        // specifies the tag to render the ListView component
        <ListViewComponent id="ui-list" dataSource={listData} enableVirtualization={true}>
            <Inject services={[Virtualization]} />
        </ListViewComponent>);
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
import * as React from 'react';
import * as ReactDOM from "react-dom";
import { ListViewComponent, Inject, Virtualization } from '@syncfusion/ej2-react-lists';

function App() {
  // define the array of Json
  let listData: { [key: string]: string | object }[];
  listData = [
    { text: "Nancy", id: "0" },
    { text: "Andrew", id: "1" },
    { text: "Janet", id: "2" },
    { text: "Margaret", id: "3" },
    { text: "Steven", id: "4" },
    { text: "Laura", id: "5" },
    { text: "Robert", id: "6" },
    { text: "Michael", id: "7" },
    { text: "Albert", id: "8" },
    { text: "Nolan", id: "9" }
  ];
  for (let i: number = 10; i <= 1010; i++) {
    let index: number = parseInt((Math.random() * 10).toString());
    listData.push({ text: listData[index].text, id: i.toString() });
  }

  return (
    // specifies the tag to render the ListView component
    <ListViewComponent id="ui-list" dataSource={listData} enableVirtualization={true}>
      <Inject services={[Virtualization]} />
    </ListViewComponent>
  );
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
#ui-list {
  display: block;
  max-width: 400px;
  margin: auto;
  border-radius: 3px;
  cursor: pointer;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ListView</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-react-lists/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='element' style="margin:0 auto; max-width:400px;">
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>

We can use template property to customize list items in UI virtualization.

import * as React from 'react';
import * as ReactDOM from "react-dom";
import { ListViewComponent, Inject, Virtualization } from '@syncfusion/ej2-react-lists';
import './index.css';
function App() {
  // define the array of Json
  let listData;
  listData = [
    { name: 'Nancy', icon: 'N', id: '0', },
    { name: 'Andrew', icon: 'A', id: '1' },
    { name: 'Janet', icon: 'J', id: '2' },
    { name: 'Margaret', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/margaret.png', id: '3' },
    { name: 'Steven', icon: 'S', id: '4' },
    { name: 'Laura', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/laura.png', id: '5' },
    { name: 'Robert', icon: 'R', id: '6' },
    { name: 'Michael', icon: 'M', id: '7' },
    { name: 'Albert', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/albert.png', id: '8' },
    { name: 'Nolan', icon: 'N', id: '9' }
  ];
  for (let i = 10; i <= 1010; i++) {
    let index = parseInt((Math.random() * 10).toString());
    listData.push({ name: listData[index].name, icon: listData[index].icon, imgUrl: listData[index].imgUrl, id: i.toString() });
  }
  function template(data) {
    return (
      <div className="e-list-wrapper e-list-avatar">
        <span className={`e-avatar e-avatar-small e-avatar-circle ${data.icon} ${data.imgUrl ? 'hideUI' : 'showUI'}`}>{data.icon}</span>
        <img className={`e-avatar e-avatar-circle ${data.imgUrl ? 'showUI' : 'hideUI'}`} src={data.imgUrl ? data.imgUrl : ' '} alt="" />
        <span className="e-list-content">{data.name}</span>
      </div>
    );
  } return (
    // specifies the tag to render the ListView component
    <ListViewComponent id='ui-list' dataSource={listData} enableVirtualization={true} template={template} cssClass='e-list-template' height={500} headerTitle="Contacts" showHeader={true}>
      <Inject services={[Virtualization]} />
    </ListViewComponent>);
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
import * as React from 'react';
import * as ReactDOM from "react-dom";
import { ListViewComponent, Inject, Virtualization } from '@syncfusion/ej2-react-lists';

function App() {
    // define the array of Json
    let listData: { [key: string]: string | object }[];
    listData = [
        { name: 'Nancy', icon: 'N', id: '0', },
        { name: 'Andrew', icon: 'A', id: '1' },
        { name: 'Janet', icon: 'J', id: '2' },
        { name: 'Margaret', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/margaret.png', id: '3' },
        { name: 'Steven', icon: 'S', id: '4' },
        { name: 'Laura', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/laura.png', id: '5' },
        { name: 'Robert', icon: 'R', id: '6' },
        { name: 'Michael', icon: 'M', id: '7' },
        { name: 'Albert', imgUrl: 'https://ej2.syncfusion.com/react/demos/src/listview/images/albert.png', id: '8' },
        { name: 'Nolan', icon: 'N', id: '9' }
    ];
    for (let i: number = 10; i <= 1010; i++) {
        let index: number = parseInt((Math.random() * 10).toString());
        listData.push({ name: listData[index].name, icon: listData[index].icon, imgUrl: listData[index].imgUrl, id: i.toString() });
    }
    // Set customized list template
    function template(data: any) {
        return (
            <div className="e-list-wrapper e-list-avatar">
                <span className={`e-avatar e-avatar-circle ${data.icon} ${data.imgUrl ? 'hideUI' : 'showUI'}`}>{data.icon}</span>
                <img className={`e-avatar e-avatar-circle ${data.imgUrl ? 'showUI' : 'hideUI'}`} src={data.imgUrl ? data.imgUrl : ' '} />
                <span className="e-list-content">{data.name}</span>
            </div>
        );
    }
    return (
        // specifies the tag to render the ListView component
        <ListViewComponent id='ui-list' dataSource={listData} enableVirtualization={true} template={template} height={500} cssClass='e-list-template' headerTitle="Contacts" showHeader={true}>
            <Inject services={[Virtualization]} />
        </ListViewComponent>
    );
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
#ui-list.e-listview {
    margin: auto;
    max-width: 325px;
    line-height: initial;
    border: 1px solid lightgray;
}

/* ListView header alignment */

#ui-list.e-listview .e-list-header {
    height: 50px
}

#ui-list.e-listview .e-list-header .e-text {
    line-height: 18px
}

/* ListView template customization */

#ui-list.e-listview .showUI {
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
}

#ui-list.e-listview .hideUI {
    display: none;
}

#ui-list.e-listview .e-list-item {
    padding: 3px 0;
}

#ui-list.e-listview .R {
    background: lightgrey;
}

#ui-list.e-listview .M {
    background: pink;
}

#ui-list.e-listview .A {
    background: lightgreen;
}

#ui-list.e-listview .S {
    background: lightskyblue;
}

#ui-list.e-listview .J {
    background: orange;
}

#ui-list.e-listview .N {
    background: lightblue;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ListView</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-react-lists/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='element' style="margin:0 auto; max-width:400px;">
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>

Conditional rendering

We have also provided following conditional rendering support for template and groupTemplate.

Name Syntax
Conditional class <div class="${ $id % 2 === 0 ? 'even-list' : 'odd-list'}"></div>
Conditional attribute <div id="${ $id % 2 === 0 ? 'even-list' : 'odd-list'}"></div>
Conditional text content <div>${ $id % 2 === 0 ? 'even-list' : 'odd-list'}</div>

In the below sample, we have applied light blue for even list and light coral for odd list based on the conditional class.

import * as React from 'react';
import * as ReactDOM from "react-dom";
import { ListViewComponent, Inject, Virtualization } from '@syncfusion/ej2-react-lists';
function App() {
    // define the array of Json
    let listData;
    listData = [
        { text: "Nancy", id: "0" },
        { text: "Andrew", id: "1" },
        { text: "Janet", id: "2" },
        { text: "Margaret", id: "3" },
        { text: "Steven", id: "4" },
        { text: "Laura", id: "5" },
        { text: "Robert", id: "6" },
        { text: "Michael", id: "7" },
        { text: "Albert", id: "8" },
        { text: "Nolan", id: "9" }
    ];
    for (let i = 10; i <= 1010; i++) {
        let index = parseInt((Math.random() * 10).toString());
        listData.push({ text: listData[index].text, id: i.toString() });
    }
    let template = "<div id=\"list-container\" class=\"${ $id % 2 === 0 ? 'even-list' : 'odd-list' }\" > ${text} </div>";
    return (
        // specifies the tag to render the ListView component
        <ListViewComponent id="ui-list" dataSource={listData} enableVirtualization={true} template={template} height={500}>
            <Inject services={[Virtualization]} />
        </ListViewComponent>);
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
import * as React from 'react';
import * as ReactDOM from "react-dom";
import { ListViewComponent, Inject, Virtualization } from '@syncfusion/ej2-react-lists';

function App() {
  // define the array of Json
  let listData: { [key: string]: string | object }[];
  listData = [
    { text: "Nancy", id: "0" },
    { text: "Andrew", id: "1" },
    { text: "Janet", id: "2" },
    { text: "Margaret", id: "3" },
    { text: "Steven", id: "4" },
    { text: "Laura", id: "5" },
    { text: "Robert", id: "6" },
    { text: "Michael", id: "7" },
    { text: "Albert", id: "8" },
    { text: "Nolan", id: "9" }
  ];
  for (let i: number = 10; i <= 1010; i++) {
    let index: number = parseInt((Math.random() * 10).toString());
    listData.push({ text: listData[index].text, id: i.toString() });
  }

  let template: string =
    "<div id=\"list-container\" class=\"${ $id % 2 === 0 ? 'even-list' : 'odd-list' }\" > ${text} </div>";

  return (
    // specifies the tag to render the ListView component
    <ListViewComponent
      id="ui-list"
      dataSource={listData}
      enableVirtualization={true}
      template={template}
      height={500}
    >
      <Inject services={[Virtualization]} />
    </ListViewComponent>
  );
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
#ui-list {
  display: block;
  max-width: 400px;
  margin: auto;
  border: 1px solid #dddddd;
  border-radius: 3px;
  cursor: pointer;
}

#list-container {
  height: inherit;
  width: inherit;
  padding-left: 30px;
}

#ui-list .e-list-item {
  padding: 0;
}

#ui-list .even-list {
  background-color: #cfd8dc;
}

#ui-list .odd-list {
  background-color: #eceff1;
}
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Syncfusion React ListView</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Essential JS 2 for React Components" />
    <meta name="author" content="Syncfusion" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-base/styles/material.css" rel="stylesheet" />
    <link href="https://cdn.syncfusion.com/ej2/28.1.33/ej2-react-lists/styles/material.css" rel="stylesheet" />
    <link href="index.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.19.38/system.js"></script>
    <script src="systemjs.config.js"></script>
    <style>
        #loader {
            color: #008cff;
            height: 40px;
            left: 45%;
            position: absolute;
            top: 45%;
            width: 30%;
        }
    </style>
<script src="https://cdn.syncfusion.com/ej2/syncfusion-helper.js" type ="text/javascript"></script>
</head>

<body>
    <div id='element' style="margin:0 auto; max-width:400px;">
        <div id='loader'>Loading....</div>
    </div>
</body>

</html>