Variable width items in wrong position when FlashList is recycled with existing scroll offset
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 7.2k
- Forks
- 393
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 1
Description
Description
We're using a nested vertical FlashList of of horizontal FlashList rows in our app. Each row contains a variable number of items which have differing sizes, but we know those sizes upfront. In FlashList v2 we've found a regression where recycling the FlashList rows can cause the items in the row to be incorrectly positioned if the row has a non-zero scroll offset already applied.
We believe this is related to the removal of the size value in the overrideItemLayout prop, which previously allowed us to specify the known item sizes upfront. Other list libraries or FlatList provide a getItemLayout prop that lets us fix this issue but we have no similar functionality in FlashList v2.
Current behavior
When a FlashList that has a scroll offset is recycled with new variable width items the layout positions of the items can be incorrect. Manually scrolling eventually 'fixes' the layout with the items jumping to their correct offsets.
Expected behavior
The list items should always be in the correct position even if a scroll offset is present.
Reproduction
Expo Snack or minimal reproduction link:
https://snack.expo.dev/@jarafe9811/upbeat-blue-scones
Scroll horizontally ahead a couple of times and then begin scrolling vertically down. You will find eventually that some items are in the wrong scroll position by comparing their start/end offsets to adjacent rows
Platform
- iOS
- Android
- Web (if applicable)
Environment
React Native info output:
System:
OS: macOS 26.3
CPU: (10) arm64 Apple M1 Max
Memory: 133.64 MB / 32.00 GB
Shell:
version: "5.9"
path: /bin/zsh
Binaries:
Node:
version: 24.13.0
path: /Users/moussa/.local/share/mise/installs/node/24.13.0/bin/node
Yarn:
version: 1.22.17
path: /Users/moussa/.volta/bin/yarn
npm:
version: 11.6.2
path: /Users/moussa/.local/share/mise/installs/node/24.13.0/bin/npm
Watchman:
version: 2025.04.28.00
path: /opt/homebrew/bin/watchman
Managers:
CocoaPods:
version: 1.15.2
path: /Users/moussa/.local/share/mise/installs/ruby/2.7.6/bin/pod
SDKs:
iOS SDK:
Platforms:
- DriverKit 25.0
- iOS 26.0
- macOS 26.0
- tvOS 26.0
- visionOS 26.0
- watchOS 26.0
Android SDK: Not Found
IDEs:
Android Studio: 2024.2 AI-242.23339.11.2421.12483815
Xcode:
version: 26.0.1/17A400
path: /usr/bin/xcodebuild
Languages:
Java:
version: 17.0.2
path: /Users/moussa/.local/share/mise/installs/java/openjdk-17.0.2/bin/javac
Ruby:
version: 2.7.6
path: /Users/moussa/.local/share/mise/installs/ruby/2.7.6/bin/ruby
npmPackages:
"@react-native-community/cli": Not Found
react:
installed: 19.1.1
wanted: 19.1.1
react-native: Not Found
react-native-macos: Not Found
npmGlobalPackages:
"react-native": Not Found
Android:
hermesEnabled: Not found
newArchEnabled: Not found
iOS:
hermesEnabled: Not found
newArchEnabled: Not found
FlashList version: 2.2.0
Additional context
We've tried various workarounds like calling clearLayoutCacheOnUpdate() on the list ref or using the useLayoutState hook to attempt to force the list to recalculate layout without success. The only workaround is to make the list to scroll to 0 and back to the current offset but this isn't an acceptable solution.
Checklist
- I've searched existing issues and couldn't find a duplicate
- I've provided a minimal reproduction (Expo Snack preferred)
- I'm using the latest version of @shopify/flash-list
- I've included all required information above
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the linked Expo Snack reproduction with FlashList 2.2.0, then scroll the horizontal rows ahead before scrolling vertically and compare item offsets with adjacent rows. Investigate the interaction between variable item sizes, recycled rows, and existing scroll offsets, including the removed overrideItemLayout size value and the attempted clearLayoutCacheOnUpdate and useLayoutState workarounds. Done means recycled items remain at their correct positions without scrolling to zero and back.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react-native, typescript
- Domain
- mobile
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100