Represents a list that renders using virtualization, presenting only a portion of the list at a time. This component requires API version 67.0 or later. To use this component, select the Dev channel in Salesforce Release Manager.
For Use In
Lightning Experience, Experience Builder Sites, Salesforce Mobile App, Lightning Out (Beta), Standalone Lightning App, Mobile Offline
Working with dynamic lists is available as a developer preview. This feature isn’t generally available unless or until Salesforce announces its general availability in documentation or in press releases or public statements. All commands, parameters, and other features are subject to change or deprecation at any time, with or without notice. Don’t implement functionality in production with these commands or tools.
Note
The lightning-dynamic-list-container component renders a portion of a list at a time by using intelligent virtualization. This component is useful for large datasets where you don’t want to render the entire list all at once in the DOM. It can improve browser performance, reduce memory usage, and speed up user interactions in large lists.
To implement your list using lightning-dynamic-list-container, consider the roles of these key wrapper components:
lightning-dynamic-list-container: the parent wrapper responsible for managing overall list rendering and slicing data based on the user’s scroll position.
lightning-dynamic-list-item: the child wrapper representing each individual row, dynamically positioned by the container based on the current scroll position.
Both wrappers use <slot>, allowing them to wrap various list implementations and row types.
To create a dynamic list:
Enclose all rows with lightning-dynamic-list-container.
Enclose each row with lightning-dynamic-list-item, passing a unique identifier using the item-id attribute.
Place both lightning-dynamic-list-container and lightning-dynamic-list-item in the same LWC template.
Pass the full list data to lightning-dynamic-list-container using the list-items attribute.
1<template>2<!--3 Scrollable behavior is managed by dynamicListContainer.4 Don't add scrollable classes, such as slds-scrollable_y.5 -->6 <div class="list-container">7 <lightning-dynamic-list-container8 lwc:ref="dynamicListContainer"9 list-items={listItems}10 onrenderlistitems={handleRenderListItems}11 >12 <template for:each={listItemsToRender} for:item="item">13 <lightning-dynamic-list-item key={item.id} item-id={item.id}>14 <div>Your Custom Row Content</div>15 </lightning-dynamic-list-item>16 </template>17 <footer slot="footer">18 <div>Your Custom List Footer</div>19 </footer>20 </lightning-dynamic-list-container>21 </div>22</template>
Make sure that there are no components or elements between adjacent lightning-dynamic-list-item components, or between the container and the first lightning-dynamic-list-item. You don’t need to configure custom scrolling such as overflow: scroll or similar styles from your list container. Scrolling is handled by lightning-dynamic-list-container.
To manage rendering of lists as you scroll, handle the renderlistitems event from lightning-dynamic-list-container. Extract listItemsToRender from the event detail to get the subset of list data to render in the DOM. The component automatically positions each row.
1import{LightningElement, api}from "lwc";23export default class MyDynamicList extends LightningElement{4 _listItemsToRender = [];56 // The full list data7 @api listItems;89 get listItemsToRender(){10 return this._listItemsToRender;11}1213 handleRenderListItems(event){14 // The component tells you which items to render15 this._listItemsToRender = event.detail.listItemsToRender;16}17}
lightning-dynamic-list-container requires a bounded height for the list. Make sure that at least one ancestor of lightning-dynamic-list-container has an explicit height in pixels, percentage, or viewport units. The scrollable viewport expands to fill the height of its nearest ancestor with a defined height.
1.list-container{2 height: 400px; /* fixed and bounded */3}45.list-container{6 max-height: 80vh; /* bounded by the viewport height */7}
When building your lists, avoid padding on elements between lightning-dynamic-list-container and lightning-dynamic-list-item. Use margin on rows wrapped by lightning-dynamic-list-item for spacing between rows and between rows and container.
Virtualization
The lightning-dynamic-list-container component implements intelligent virtualization with these behaviors.
Renders only visible items: Only the rows currently visible in the viewport with a small buffer are rendered in the DOM. The component adds rows and removes them from the DOM as you scroll.
Supports variable row heights: Rows can have different heights, and the component automatically recalculates positions as needed.
Maintains smooth scrolling: Uses scroll anchoring to ensure a smooth scrolling experience during virtualization.
Handles dynamic list changes efficiently:
Rows can be resized individually or collectively.
Rows can be added or removed at any position in the list.
The list container itself can be resized.
Load More Rows
To load more rows when the user scrolls to the end of the list, you can either add a load more button using the footer slot or listen for the loadmore event dispatched by the lightning-dynamic-list-container. If you append new list items to the existing list, reassign the list to trigger reactivity.
1<template>2 <div class="list-container">3<!--4 Display the spinner above the DynamicList.5 Don't remove or re-create DynamicListContainer when loading more rows.6 -->7 <template if:true={isLoading}>8 <lightning-spinner></lightning-spinner>9 </template>10 <lightning-dynamic-list-container11 lwc:ref="dynamicListContainer"12 list-items={listItems}13 onrenderlistitems={handleRenderListItems}14 onloadmore={handleLoadMore}15 >16 <template for:each={listItemsToRender} for:item="item">17 <lightning-dynamic-list-item key={item.id} item-id={item.id}>18 <div>Your Custom Row Content</div>19 </lightning-dynamic-list-item>20 </template>21 </lightning-dynamic-list-container>22 </div>23</template>
To add a loading screen while loading more rows, such as with lightning-spinner, display the spinner above the lightning-dynamic-list-container rather than replacing it. Don’t remove or re-create the lightning-dynamic-list-container when loading more rows.
1import{LightningElement, api}from "lwc";23export default class MyDynamicList extends LightningElement{4 _listItems = [];5 _listItemsToRender = [];6 _isLoading = false;78 get listItemsToRender(){9 return this._listItemsToRender;10}1112 get isLoading(){13 return this._isLoading;14}1516 handleRenderListItems(event){17 this._listItemsToRender = event.detail.listItemsToRender;18}1920 handleLoadMore(event){21 const startOffset = event.detail.startOffset;22 this._generateListItems();23 // Make sure to reassign to listItems for reactivity24 this._listItems = [...this._listItems];25}2627 connectedCallback(){28 this._generateListItems();29}3031 _generateListItems(){32 this._isLoading = true;33 for(let i = 0; i<500; i++){34 this._listItems.push({35 id: this._listItems.length,36});37}38 this._isLoading = false;39}40}
Make sure that the component defines an explicit height.
1.list-container{2 height: 400px; /* or any bounded value */3 position: relative; /* ensure spinner is positioned correctly */4}
List Filtering and Search
If the list is filtered, such as after a search, call the reset() method on lightning-dynamic-list-container before updating the list data. This ensures the internal cache is cleared and new rows are rendered from the beginning.
1import{LightningElement, api}from "lwc";23export default class MyDynamicList extends LightningElement{4 _listData;5 _filteredListData = [];6 _listItemsToRender = [];78 @api9 get listData(){10 return this._filteredListData;11}1213 set listData(value){14 if(Array.isArray(value)){15 this._listData = value;16 this._filteredListData = value;17}18}1920 get listItemsToRender(){21 return this._listItemsToRender;22}2324 handleRenderListItems(event){25 this._listItemsToRender = event.detail.listItemsToRender;26}2728 handleSearch(event){29 // Call the reset method before setting the new list data30 this.refs.dynamicListContainer.reset();31 this._filteredListData = this._listData.filter((data)=>{32 // Custom filter logic33});34}35}
Scroll a Row Into View
To scroll a specific row into view, use the scrollRowIntoView() method on lightning-dynamic-list-container. Pass the target row index as the first argument and an optional config object as the second. By default, scrolling is instant and focus remains unchanged. To enable smooth scrolling and move focus to the row, set behavior: 'smooth' and focus: true in the config.
1import{LightningElement, api}from "lwc";23export default class MyDynamicList extends LightningElement{4 _listItemsToRender = [];56 // The full list data7 @api listItems;89 get listItemsToRender(){10 return this._listItemsToRender;11}1213 handleRenderListItems(event){14 this._listItemsToRender = event.detail.listItemsToRender;15}1617 handleScrollRowIntoView(targetRowIndex){18 this.refs.dynamicListContainer.scrollRowIntoView(targetRowIndex, {19 behavior: "smooth",20 focus: true,21});22}23}
Configure ARIA Role Assignment
By default, lightning-dynamic-list-container follows standard list semantics to ensure accessibility for screen readers. When disableAutoListSemantics is false (default), the component automatically assigns these roles:
Container Level: The viewport or main container is assigned role="list".
Item Level: Each list item is assigned role="listitem".
To change the role to presentation, set disableAutoListSemantics to true. This configuration is useful when the lightning-dynamic-list-container component is nested inside other components that already provide their own ARIA context, preventing redundant or conflicting screen reader announcements.
Configure Keyboard Navigation Support
By default, lightning-dynamic-list-container handles keydown events. To disable keyboard support, set disableKeyboardSupport = true. When disableKeyboardSupport = true, these features are deactivated:
Arrow Key Navigation: Users can’t move focus between list items using the Up Arrow and Down Arrow keys.
Home and End Keys: Shortcuts to jump to the first or last item in the list are disabled.
Page Up and Down Keys: The ability to scroll through the list in “pages” via the keyboard is removed.
Focus Tracking: The internal keyboard state doesn’t update the index for focused item based on user key presses.
When disableKeyboardSupport is true, screen reader users can still navigate the list using their standard virtual cursor when disableAutoListSemantics remains false. This property only affects the active keyboard event listeners managed by the component. This configuration is useful in these use cases:
Custom Key Handlers: If your application requires specific, non-standard keyboard interactions that conflict with the default list navigation, you can disable the internal support and implement your own listener on a wrapper element.
Read-Only Lists: In scenarios where the list is decorative or informational and doesn’t contain interactive elements, disabling keyboard support can prevent accidental focus traps.
Nested Interactivity: If the list items themselves contain complex widgets that manage their own internal focus and key events, you can disable the container-level support to avoid “bubbling” conflicts.
Focus Tracking and Preservation
Unlike other virtualization frameworks, lightning-dynamic-list-container ensures that system focus is always preserved, even if the row with system focus is no longer visible in the viewport. This critical feature provides:
Focus Tracking: Keeps track of which row has focus even when it’s not rendered.
Focus Restoration: Ensures the row with focus is rendered in the DOM after a repaint, and programmatically restores focus to the row.
Usage Considerations
If a user focuses on any element within a row—other than the first focusable element—then scrolls the row out of view and later scrolls back, the component restores focus to the first focusable element in that row, not the originally focused element. The same behavior occurs if the user presses the Tab or Shift+Tab keys while the focused row is out of view.
When a user scrolls quickly, multiple scroll events are fired in rapid succession. To improve performance, lightning-dynamic-list processes only the last event captured. This can result in a temporary blank screen during fast scrolling, with content appearing only after scrolling stops.
Accessibility
lightning-dynamic-list-container provides comprehensive accessibility and keyboard navigation support out of the box.
Arrow Key Navigation: Use the Up Arrow and Down Arrow keys to navigate between rows, even if the focused row isn’t currently visible.
Home/End Key Navigation: Jump to the first or last row in the list, even if those rows are not currently visible.
Semantic List Support: Automatically adds appropriate ARIA roles (list, listitem, presentation) to maintain semantic structure and provides aria-setsize and aria-posinset attributes for proper list item positioning information.
Browse Mode Detection: Detects when users navigate using screen reader browse mode (where system focus and cursor aren’t synchronized) and provides live announcements to suggest switching to focus mode.
Screen Reader Support: Supports JAWS, NVDA, and VoiceOver screen readers.
Custom Events
loadmore
The event that’s fired when the user scrolls to the end of the list.
The loadmore event returns this parameter.
Parameter
Type
Description
startOffset
number
The index in the list where the next batch of data should begin loading.
The event properties are as follows.
Property
Value
Description
bubbles
false
This event doesn’t bubble.
cancelable
false
This event has no default behavior that can be canceled. You can’t call preventDefault() on this event.
composed
false
This event doesn’t propagate outside the template in which it was dispatched.
renderlistitems
The event that’s fired when the component determines which items should be rendered.
The renderlistitems event returns this parameter.
Parameter
Type
Description
listItemsToRender
array
The list items to be rendered, which are the only items rendered in the DOM.
The event properties are as follows.
Property
Value
Description
bubbles
false
This event doesn’t bubble.
cancelable
false
This event has no default behavior that can be canceled. You can’t call preventDefault() on this event.
composed
false
This event doesn’t propagate outside the template in which it was dispatched.
Attributes
Name
Description
Type
Default
Required
disable-auto-list-semantics
Disables automatic ARIA role assignment
boolean
disable-keyboard-support
Disables keyboard navigation support
boolean
list-items
The complete array of items to virtualize
Methods
Name
Description
Argument Name
Argument Type
Argument Description
reset
Reset the list container to its initial state and scrolls to the top.
scrollRowIntoView
Scrolls the specified row into view, optionally with smooth behavior and focus.