Migration to v3

Version 3 introduces first‑class Web support and a new SectionList component, plus several API improvements.

✨ New in v3

Web Support

  • DOM‑native rendering (no React Native dependency required)
  • Same virtualization core as React Native
  • Web examples and docs

SectionList Component

  • @legendapp/list/section-list with a React Native‑compatible API
  • scrollToLocation support
  • Sticky section headers powered by stickyHeaderIndices

Always Render

  • alwaysRender keeps selected items mounted outside the virtualization window

Better Scroll & Metrics APIs

  • initialScrollAtEnd for chat and feeds
  • anchoredEndSpace for reserving readable space after a chat or feed anchor row
  • contentInsetEndAdjustment for floating composers and overlay UI at the end of a list
  • useKeyboardChatComposerInset for React Native keyboard chat composers
  • onMetricsChange for header/footer size changes
  • getState() now exposes listeners, element access, and scroll velocity

🔄 Breaking changes from v2

  1. Typed import paths

    • The root @legendapp/list component export has been removed in v3.
    • Use:
      • React Native: @legendapp/list/react-native
      • React (Web): @legendapp/list/react
  2. maintainVisibleContentPosition defaults

    • v3 now enables scroll-position stabilization on size changes by default
    • Default behavior is equivalent to maintainVisibleContentPosition={{ size: true, data: false }}
    • Toggle specific behavior as needed:
      • maintainVisibleContentPosition={{ data: true }} to anchor on data changes too
      • maintainVisibleContentPosition={{ size: false }} to disable size/layout stabilization
      • maintainVisibleContentPosition={true} to enable both size and data
      • maintainVisibleContentPosition={false} to disable both
  3. Size hints and fixed-size callbacks

    • getFixedItemSize is now (item, index, type)
    • getEstimatedItemSize has been removed. Prefer no estimate for most dynamic-size lists, estimatedItemSize only as a small initial allocation hint when rows are far from 100px, or getFixedItemSize when sizes are known exactly.
    • suggestEstimatedItemSize has been removed. Use ref.current?.getState().getAverageItemSizes() to inspect measured average sizes directly.
  4. Sticky headers prop rename

    • stickyIndices has been removed. Use stickyHeaderIndices.
  5. Keyboard integration entrypoint update

    • v2 keyboard docs used @legendapp/list/keyboard-controller and LegendList.
    • In v3 use @legendapp/list/keyboard and import KeyboardAwareLegendList.
    • LegendList is no longer exported from the @legendapp/list/keyboard entrypoint.
    • Chat screens can use KeyboardAwareLegendList, useKeyboardScrollToEnd, and useKeyboardChatComposerInset from @legendapp/list/keyboard.
    • KeyboardAvoidingLegendList is available from @legendapp/list/keyboard-legacy for apps that still need the previous keyboard-avoiding integration.
  6. renderItem is a render callback

    • renderItem is called directly as (props) => ReactNode.
    • Do not pass a hook-using item component directly as renderItem={Row}.
    • Return hook-using item components from the callback instead: renderItem={({ item }) => <Row item={item} />}.
  7. Imperative scroll methods are async

    • These ref methods now return Promise<void>:
      • scrollIndexIntoView
      • scrollItemIntoView
      • scrollToEnd
      • scrollToIndex
      • scrollToItem
      • scrollToOffset
    • If you run logic after a programmatic scroll, await the call.
  8. getState() shape changed for advanced integrations

    • state.positions is no longer part of the public getState() return value.
    • Replace direct map access with:
      • positionAtIndex(index)
      • positionByKey(key)
    • getState() now also exposes listener helpers (listen, listenToPosition), scrollVelocity, and getAverageItemSizes().
  9. Removed compatibility props and types

    • initialContainerPoolRatio has been removed. LegendList manages spare container capacity automatically.
    • InitialScrollAnchor has been removed. Use ScrollIndexWithOffsetPosition for public initial-scroll position typing.

Migration checklist

  • Move imports to typed platform entrypoints (/react-native or /react)
  • Update fixed-size callback signatures to (item, index, type)
  • Replace getEstimatedItemSize with no estimate, estimatedItemSize only for unusual initial sizes, or getFixedItemSize
  • Replace suggestEstimatedItemSize with getState().getAverageItemSizes()
  • Replace stickyIndices with stickyHeaderIndices
  • Remove initialContainerPoolRatio; spare container capacity is automatic
  • Replace InitialScrollAnchor type references with ScrollIndexWithOffsetPosition
  • Update keyboard imports from @legendapp/list/keyboard-controller to @legendapp/list/keyboard and use KeyboardAwareLegendList
  • If you still need the previous keyboard-avoiding integration, import KeyboardAvoidingLegendList from @legendapp/list/keyboard-legacy
  • Wrap hook-using item components in a renderItem callback instead of passing them directly
  • For floating composers, replace content padding workarounds with contentInsetEndAdjustment on web or useKeyboardChatComposerInset with KeyboardAwareLegendList on React Native
  • await imperative scroll calls if your code depends on post-scroll timing
  • Update advanced getState() consumers to use positionAtIndex / positionByKey instead of positions

Install

npm install @legendapp/list

On this page