Migration to v3
Version 3 introduces first‑class Web support and a new SectionList component, plus several API improvements.
Migrating from 3.6 to 3.7
New in 3.7 (3.7.0 is unreleased).
The only breaking type changes are new required members on the public ref and state types: code that implements or mocks these types must add them. Apps that only consume refs and state do not need to implement these members themselves. There are no deprecations in 3.7.
| Type | New required members |
|---|---|
LegendListRef (React Native and Web) | cancelScroll, scrollToKey, anchorVisibleContent |
SectionListRef | cancelScroll, scrollToKey, anchorVisibleContent, inherited from LegendListRef |
LegendListState | distanceFromEnd, isFollowingEnd |
LegendListState.dataKey is a new optional member. listen accepts isFollowingEnd; distanceFromEnd is computed when getState() is called and is not a listen key. Existing 3.6-shaped listen implementations remain assignable. LegendListMetrics is unchanged: onMetricsChange still receives only headerSize and footerSize.
For example, update a test double that only needs to model cancellation and unreachable key navigation with these members. A mock that simulates actual scrolling should model the new completion behavior too.
import type { LegendListRef, LegendListState } from "@legendapp/list/react-native";
const newRefMembers: Pick<LegendListRef,
"cancelScroll" | "scrollToKey" | "anchorVisibleContent"
> = {
cancelScroll: () => {},
scrollToKey: async () => {},
anchorVisibleContent: () => undefined,
};
const newStateMembers: Pick<LegendListState,
"distanceFromEnd" | "isFollowingEnd"
> = {
distanceFromEnd: 0,
isFollowingEnd: false,
};Add those members to your existing mock's ref and state objects. See the ref methods and state fields for their contracts.
For SectionList key-based methods, pass flattened item keys of the form ${sectionKey}:item:${itemKey}, rather than the bare item key. sectionKey is the section's key or section-${sectionIndex} when omitted; itemKey comes from the section or list keyExtractor; without one, it uses item.key, then item.id, then the item index within the section, converted to a string. anchorVisibleContent accepts and returns those same flattened keys. See SectionList for header, footer, and separator keys.
Behavior also changes in 3.7:
- Scroll promises now resolve on landing or settlement, including interruption, cancellation, replacement, or an unreachable target, instead of resolving early or never. Resolution does not guarantee arrival.
- Use
maintainScrollAtEnd.on.dataAppendwith a stablekeyExtractorfor append-only following, leavingdataChangedisabled. WithoutkeyExtractor, any increase in data length, including a prepend, triggers following. - With a trailing inset,
isAtEnd,onEndReached, andmaintainScrollAtEndnow activate closer to the physical end because the inset is counted once. - Allow
onStartReached/onEndReachedto run after layout changes without a scroll event. - Pass external fixed-size dependencies through
extraDatasogetFixedItemSizesizes are invalidated when they change.
See Chat interfaces and Scrolling a search match into view for examples.
✨ 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-listwith a React Native‑compatible APIscrollToLocationsupport- Sticky section headers powered by
stickyHeaderIndices
Always Render
alwaysRenderkeeps selected items mounted outside the virtualization window
Better Scroll & Metrics APIs
initialScrollAtEndfor chat and feedsanchoredEndSpacefor reserving readable space after a chat or feed anchor rowcontentInsetEndAdjustmentfor floating composers and overlay UI at the end of a listuseKeyboardChatComposerInsetfor React Native keyboard chat composersonMetricsChangefor header/footer size changesgetState()now exposes listeners, element access, and scroll velocity
🔄 Breaking changes from v2
-
Typed import paths
- The root
@legendapp/listcomponent export has been removed in v3. - Use:
- React Native:
@legendapp/list/react-native - React (Web):
@legendapp/list/react
- React Native:
- The root
-
maintainVisibleContentPositiondefaults- 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 toomaintainVisibleContentPosition={{ size: false }}to disable size/layout stabilizationmaintainVisibleContentPosition={true}to enable bothsizeanddatamaintainVisibleContentPosition={false}to disable both
-
Size hints and fixed-size callbacks
getFixedItemSizeis now(item, index, type)getEstimatedItemSizehas been removed. Prefer no estimate for most dynamic-size lists,estimatedItemSizeonly as a small initial allocation hint when rows are far from100px, orgetFixedItemSizewhen sizes are known exactly.suggestEstimatedItemSizehas been removed. Useref.current?.getState().getAverageItemSizes()to inspect measured average sizes directly.
-
Sticky headers prop rename
stickyIndiceshas been removed. UsestickyHeaderIndices.
-
Keyboard integration entrypoint update
- v2 keyboard docs used
@legendapp/list/keyboard-controllerandLegendList. - In v3 use
@legendapp/list/keyboardand importKeyboardAwareLegendList. LegendListis no longer exported from the@legendapp/list/keyboardentrypoint.- Chat screens can use
KeyboardAwareLegendList,useKeyboardScrollToEnd, anduseKeyboardChatComposerInsetfrom@legendapp/list/keyboard. KeyboardAvoidingLegendListis available from@legendapp/list/keyboard-legacyfor apps that still need the previous keyboard-avoiding integration.
- v2 keyboard docs used
-
renderItemis a render callbackrenderItemis 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} />}.
-
Imperative scroll methods are async
- These ref methods now return
Promise<void>:scrollIndexIntoViewscrollItemIntoViewscrollToEndscrollToIndexscrollToItemscrollToOffset
- If you run logic after a programmatic scroll,
awaitthe call. The promise also resolves if the scroll is cancelled or superseded, so resolution does not guarantee arrival at the target.
- These ref methods now return
-
getState()shape changed for advanced integrationsstate.positionsis no longer part of the publicgetState()return value.- Replace direct map access with:
positionAtIndex(index)positionByKey(key)
getState()now also exposes listener helpers (listen,listenToPosition),scrollVelocity, andgetAverageItemSizes().
-
Removed compatibility props and types
initialContainerPoolRatiohas been removed. LegendList manages spare container capacity automatically.InitialScrollAnchorhas been removed. UseScrollIndexWithOffsetPositionfor public initial-scroll position typing.
Migration checklist
- Move imports to typed platform entrypoints (
/react-nativeor/react) - Update fixed-size callback signatures to
(item, index, type) - Replace
getEstimatedItemSizewith no estimate,estimatedItemSizeonly for unusual initial sizes, orgetFixedItemSize - Replace
suggestEstimatedItemSizewithgetState().getAverageItemSizes() - Replace
stickyIndiceswithstickyHeaderIndices - Remove
initialContainerPoolRatio; spare container capacity is automatic - Replace
InitialScrollAnchortype references withScrollIndexWithOffsetPosition - Update keyboard imports from
@legendapp/list/keyboard-controllerto@legendapp/list/keyboardand useKeyboardAwareLegendList - If you still need the previous keyboard-avoiding integration, import
KeyboardAvoidingLegendListfrom@legendapp/list/keyboard-legacy - Wrap hook-using item components in a
renderItemcallback instead of passing them directly - For floating composers, replace content padding workarounds with
contentInsetEndAdjustmenton web oruseKeyboardChatComposerInsetwithKeyboardAwareLegendListon React Native awaitimperative scroll calls to wait for completion or cancellation- Update advanced
getState()consumers to usepositionAtIndex/positionByKeyinstead ofpositions
Install
npm install @legendapp/list