Efficiently displays large lists by only rendering the visible items within the viewport, plus a configurable buffer.
It does so by dynamically measuring the height of the displayed elements.
In case you know the heights in advance you might get a better performance by using FabienHenon/elm-infinite-list-view.
Include VirtualList.Model in your app's model:
import VirtualList
type alias Model =
{ virtualList : VirtualList.Model
-- other fields
}
defaultModel : Model
defaultModel =
{ virtualList = VirtualList.init
-- other fields
}Include VirtualList.Msg in your app’s update function:
type Msg
= VirtualListMsg VirtualList.Msg
-- other messages
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
VirtualListMsg virtualListMsg ->
let
( virtualListModel, virtualListCmd ) =
VirtualList.update virtualListMsg model.virtualList
in
( { model | virtualList = virtualListModel }, Cmd.map VirtualListMsg virtualListCmd )
-- other casesRender the virtual list in your view:
view : Model -> Html Msg
view model =
VirtualList.view (renderRow model) model.virtualList VirtualListMsg
renderRow : Model -> String -> Html Msg
renderRow model id =
div [] [text id]Provides a default configuration with sensible initial values.
listId: The ID of the list container in the DOM.
initialHeight: Estimated height of the list before it is measured.
defaultItemHeight: Default height assigned to items before they are measured.
showListDuringInitialMeasure: If True, the list is visible while measuring (potentially causing spacing issues).
buffer: Number of items rendered outside the visible range to ensure smooth scrolling.
dynamicBuffer: If True, increases buffer size when scrolling quickly.
defaultConfig : Config defaultConfig = { listId = "virtual-list" , initialHeight = 500 , defaultItemHeight = 26 , showListDuringInitialMeasure = False , buffer = 5 , dynamicBuffer = True }
Initializes a virtual list model using the default configuration.
Initializes a virtual list model using a custom configuration.
initWithConfig defaultConfigYou can modify the default configuration:
config =
{ defaultConfig | buffer = 10 }Messages handled by the virtual list.
You need to include VirtualList.Msg in your app’s Msg type and handle it in update.
type Msg
= VirtualListMsg VirtualList.Msg
-- other messagesUpdates the virtual list model in response to messages.
You must integrate this into your update function and map the result back to your own Msg.
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
VirtualListMsg virtualListMsg ->
let
( virtualListModel, virtualListCmd ) =
VirtualList.update virtualListMsg model.virtualList
in
( { model | virtualList = virtualListModel }, Cmd.map VirtualListMsg virtualListCmd )
-- other casesRenders the virtual list.
You provide it with
Model andIn your code this would look like this:
view : Model -> Html Msg
view model =
VirtualList.view (renderRow model) model.virtualList VirtualListMsg
renderRow : Model -> String -> Html Msg
renderRow model id =
div [] [text id]renderRow is executed lazily.
Updates the list of items displayed in the virtual list.
Only new items are considered for measurement; existing items retain their cached heights.
VirtualList.setItems model.virtualList idsSame as setItems, but allows remeasuring the entire list.
Use this when item heights may have changed.
VirtualList.setItemsAndRemeasureAll model.virtualList newIdsSame as setItems, but allows specifying which items should be remeasured.
This is useful when only a subset of items might have changed in height.
VirtualList.setItemsAndRemeasure model.virtualList { newIds = newIds, idsToRemeasure = changedIds }Scrolls to the specified item in the virtual list.
Does nothing if the item is already visible.
Cmd.map VirtualListMsg (VirtualList.scrollToItem model.virtualList "item-42" VirtualList.Center)Defines where an item should appear in the viewport when scrolled to.
Top: Scrolls the item to the top.Center: Scrolls the item to the center.Bottom: Scrolls the item to the bottom.
Modelfor maintaining the virtual list state. You need to include it in your model:You create one with the
initfunction.