Fix: force FlashList to use natural DOM order on web#85825
Fix: force FlashList to use natural DOM order on web#85825sharabai wants to merge 1 commit intoExpensify:mainfrom
Conversation
|
|
|
This patch starts with 003 because another one of my PRs takes 002. |
FlashList isn't used in Mobile-Expensify, we're good here. |
|
@eVoloshchak Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2ca24ea86e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| + if (Platform.OS === "web") { | ||
| + renderEntries.sort(([, a], [, b]) => a.index - b.index); |
There was a problem hiding this comment.
Handle inverted lists when forcing natural DOM order
This sort always uses ascending index, but FlashList still supports inverted on web (RecyclerView/ViewHolder reverse the visual order via the inverted transform helpers). In that mode the DOM will now be deterministically ordered opposite to what users see, so keyboard and screen-reader traversal stays backwards for any inverted FlashList even though this patch is meant to fix accessibility ordering. The web sort needs to account for inverted (and horizontal inverted) instead of always using a.index - b.index.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
We don't have yet any components that are using inverted prop with FlashList. I did test it on FlashList 2.3.0 without the patch and let's just say inverted does a lot of things at once and navigation there looks weird in general. For example, list starts from the bottom and tabbing goes up, not down (without the patch). The patch does not change that behavior. Maybe it's warranted to come back to it when we have some components that do use that prop and reevaluate, but the behavior looks good to me at this point.
There was a problem hiding this comment.
@VickyStash Can you please look into this when you use this prop?
There was a problem hiding this comment.
Here is the PR #85114 where I'm working on migration main chat to FlashList with the inverted flag (P.S. I have three patches there as well). So what should I test specifically?
There was a problem hiding this comment.
FYI I've also tested this PR over the scenario when main chat (so expense details too) are migrated to FlashList, and I see some wrong ordering when I use voice over:
Monosnap.screencast.2026-03-20.09-32-05.mp4
But since FlashList is not used for the main chat in the current prod, I guess it can be solved later.
Just one question from me, does this PR then fixes the original issue for production? Since at this moment FlatList is used for main chat/expense details on prod?
There was a problem hiding this comment.
@VickyStash
This PR aimed to fix the issue of elements in the list being often in 'random' order when scrolling through it.
It was created with the assumption that the main chat would use FlashList instead, which is not true anymore as understand it.
Let's focus on what's actually needed for my PR and why @VickyStash was tagged in the first place.
It all comes down to if you apply my PR to your PR, would it break anything in FlashList's behavior with inverted prop used? I think that was what @shubham1206agra was asking. Basically, could you look at how navigating with screen reader works without my patch on a FlashList with inverted prop, then apply my patch and see if it broke anything.
There was a problem hiding this comment.
I've tested the patch over the main chat that uses FlashList with inverted flag and here are the results:
- I've followed the test steps from the original issue and i see the same issue:
Monosnap.screencast.2026-03-23.17-22-15.mp4
- But other than that, I've noticed nothing. Everything works the same way as before
There was a problem hiding this comment.
Great, it means it doesn't come in conflict with inverted prop. Since the original issue is going to be fixed with the original approach I'm changing the issue to a broader one I created.
Screen.Recording.2026-03-19.at.11.35.42.PM.movBUG: Multiple items in LHN gets highlighted when scrolling fast (Not repro on staging) |
|
🚧 @luacmartins has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
2ca24ea to
c41dca9
Compare
7dc3360 to
8640360
Compare
|
No product review needed |
8640360 to
1f0f379
Compare
@VickyStash |
@VickyStash |
|
@VickyStash |
Increasing the |
The first part about |
|
Thank you for the explanations! |
|
Let's just make sure there are no other side effects we're unaware of. |
|
@shubham1206agra can you prioritize this PR please? |
30e5ba1 to
5e07bb1
Compare
|
@shubham1206agra bump |
|
@mountiny Can you pass this PR off to someone else for review? |
|
@sharabai please resovle the conflict |
|
@codex review |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Screen.Recording.2026-04-16.at.12.12.29.movBUG: UI issue in chat search |
After clearing and rebuilding, the issue is gone. |
Screen.Recording.2026-04-16.at.15.01.23.mov@sharabai When moving down the list using the arrow keys, I see flickering and items jumping positions. The order doesn't remain stable. |
Screen.Recording.2026-04-16.at.15.09.40.mov@sharabai When I use arrow up to reach the first item and press arrow up again, the focus moves to the last item. After that, the list becomes unstable and items jump around. |
Screen.Recording.2026-04-16.at.15.15.39.mov@sharabai The list behaves incorrectly when using Arrow Down/Up to navigate from the first item to the last item. This issue does not occur on staging. |
|
@sharabai If you want to test with a high-traffic account like I did, you can refer to this guide: https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#high-traffic-accounts |
|
@sharabai Do you have any updates on this? |
5e07bb1 to
65df099
Compare
|
@huult I'll get back to you shortly 😃. |
65df099 to
aeaf3ca
Compare
@sharabai Please avoid using force push anymore |

Explanation of Change
FlashList uses absolute positioning, so the DOM order of elements doesn’t affect layout from its perspective. However, this creates an accessibility issue: mobile screen readers navigate based on visual position, while web screen readers follow the DOM order.
This patch ensures that list items are rendered in a natural DOM order, aligning behavior across platforms.
Performance
The performance impact is minimal. Sorting only occurs for the pool of reusable DOM elements changes. Even in a heavy scenario, say, 30 visible items plus a buffer above and below (around 50 elements total) the cost of sorting is negligible.
From my testing on a heavy AppleSauce account at

https://dev.new.expensify.com:8082/new/chatwrappingSectionListWithSectionsintoProfiler, there's not much of a measurable impact in such a heavy list, which is expected.First
#1 - #5are tests with the patch. Last#1, #3 #4are from main without the patch.As you can see, there's greater variability between measurements than between main and this patch.
Fixed Issues
$ #86126
It also should potentinally prevent a similar issue to #37447 with FlashList
Tests
Prerequisites: run those commands from project root before testing
You can test in on any list in the app that uses FlashList and has lots of elements.
Example test for
src/pages/iou/request/MoneyRequestParticipantsSelector.tsxOffline tests
QA Steps
Same as tests
I'm open to suggestions what type of QA testing is best here. In my opinion a general regression testing to check for bugs on pages that use FlashList.
A good place to check different places in the app that use FlashList can be found here
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
correct.FlashList.DOM.order.mp4