You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
iOS - Expense - Two scrolling mechanisms in landscape mode #103140
Version Number: 9.5.3-0 Reproducible in staging?: Yes Reproducible in production?: N/A - new feature, doesn't exist in prod If this was caught during regression testing, add the test name, ID and link from BrowserStack:#102665 Email or phone of affected tester (no customers):jsoidjndoiniodnsjojd@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: iPhone 17 Pro Max / iOS 27.0.1 App Component: Money Requests
Action Performed:
Precondition:
Enable anchoredFieldDropdowns
Set device navigation to navigation bar instead of gestures.
Launch Expensify app.
Open FAB > Create expense > Manual.
Tap Category.
Rotate device to landscape mode.
Scroll down the list.
Scroll down the search field.
Expected Result:
Scrolling behavior should be the same when scrolling down the list and scrolling down the search field.
Actual Result:
Scrolling behavior is different when scrolling down the list and scrolling down the search field.
This results in two scrollers when scrolling down the list and scrolling down the search field.
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
Identify the pull request that introduced this issue and revert it.
Recommendation: Fix forward rather than revert. The feature is behind the anchoredFieldDropdowns beta, the bug only affects iOS in landscape, and there is no data risk. The fix is a few lines in CategoryPickerModal.tsx.
Please re-state the problem that we are trying to solve in this issue.
On iOS in landscape, the Category dropdown has two vertical scrollers: dragging the list scrolls the list, but dragging the search field scrolls an outer container.
CategoryPickerModal doesn't opt out of that wrapper (CategoryPickerModal.tsx:97-112). It also gives its content a fixed 416pt height on small screens (CategoryPickerModal.tsx:83, :113). That is taller than the landscape cap (about 330pt on an iPhone), so the outer ScrollView can scroll. The search input sits outside the inner FlashList, so a drag on it scrolls the outer ScrollView.
The PR made this path reachable from the expense form by opening CategoryPickerModal from the anchored Category field.
What changes do you think we should make in order to solve the problem?
In CategoryPickerModal.tsx:
Pass shouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode={false} to PopoverWithMeasuredContent. Other list popovers already do this, for example FilterPopupButton.tsx:156.
In landscape, cap the content height at windowHeight * CONST.MODAL_MAX_HEIGHT_TO_WINDOW_HEIGHT_RATIO_LANDSCAPE_MODE (minus the container padding) instead of the fixed 416pt. Without this cap, step 1 alone would clip the bottom of the list.
I checked the other App PRs on the checklist that touch Modal, Popover, SelectionList, CategoryPicker or ScrollView code and ruled them out. One removed dead list-item props and only changed row minHeight. The other changed how pickers fetch policy categories and tags. Neither changes scroll behavior.
CategoryPickerModal already had the fixed-height wrapper without the opt-out before this PR. It is also used by the Search table's inline category edit, which may show the same issue on native in landscape. I didn't verify that path.
I haven't tested this on a device. The web tester can't reproduce iOS landscape.
💡 Suggested AI code review rule
This bug looks like a recurring, mechanically detectable pattern. It could be worth a coding-standards rule so the AI reviewer catches the next one. Proposed for Expensify/App:
Rule:UI-4 Opt list popovers out of the landscape ScrollView wrapper
Condition: Flag a PopoverWithMeasuredContent, Popover or bottom-docked Modal whose children render a vertical scroller (SelectionList, FlashList, FlatList, ScrollView, or a *Picker/*Selector that wraps one) without shouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode={false}. Also cap fixed content heights to the landscape maximum.
Why: In landscape, BaseModal wraps the children in its own ScrollView. That creates nested scrollers, as in this issue.
Search pattern:<PopoverWithMeasuredContent / <Popover blocks containing SelectionList|FlashList|FlatList|ScrollView|Picker and no shouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode={false}.
The full rule file, with the ❌/✅ code, would go in App/.claude/skills/app-coding-standards/rules/. If the rule is worth adding, a maintainer can open it there as a draft PR.
Next Steps for Contributor+ team: To accept:@MelvinBot implement [this](https://github.com/Expensify/App/issues/103140) to create a draft PR. To refine:@MelvinBot <your feedback> To reject: Explain why you are rejecting Melvin's proposal.
@puneetlath@ikevin127@DylanDylann this issue was created 2 weeks ago. Are we close to a solution? Let's make sure we're treating this as a top priority. Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!
Activity
applause-bot commentedon Oct 6, 2026
While Applause doesn't embed attachments for this bug, here are the links for quick view:
https://platform.applause.com/services/links/v1/external/5027a9fbb9fe8d81c8e6f8e1b1e932bce2a7965a37608cdb28b1928cc0f26b96
melvin-bot commentedon Oct 6, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #102665
melvin-bot commentedon Oct 6, 2026
@puneetlath @ikevin127 you have been assigned to this deploy blocker because you reviewed the offending PR: #102665
melvin-bot commentedon Oct 6, 2026
@DylanDylann you have been assigned to this deploy blocker because you authored the offending PR: #102665
github-actions commentedon Oct 6, 2026
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
melvin-bot commentedon Oct 6, 2026
💬 A slack conversation has been started in #expensify-open-source
MelvinBot commentedon Oct 6, 2026
Deploy Blocker Investigation
Causing PR: [CFI] Open the Category list in a container anchored to its row (high confidence).
Recommendation: Fix forward rather than revert. The feature is behind the
anchoredFieldDropdownsbeta, the bug only affects iOS in landscape, and there is no data risk. The fix is a few lines inCategoryPickerModal.tsx.Please re-state the problem that we are trying to solve in this issue.
On iOS in landscape, the Category dropdown has two vertical scrollers: dragging the list scrolls the list, but dragging the search field scrolls an outer container.
What is the root cause of that problem?
In landscape,
isSmallScreenWidthis alwaystrue(useResponsiveLayout/index.ts:41), so the Category popover opens as a bottom-docked modal. For bottom-docked modals in landscape,BaseModalcaps the height at 75% of the window (BaseModal.tsx:411) and wraps the children in aScrollViewby default (BaseModal.tsx:314-316, BaseModal.tsx:429).CategoryPickerModaldoesn't opt out of that wrapper (CategoryPickerModal.tsx:97-112). It also gives its content a fixed 416pt height on small screens (CategoryPickerModal.tsx:83, :113). That is taller than the landscape cap (about 330pt on an iPhone), so the outerScrollViewcan scroll. The search input sits outside the innerFlashList, so a drag on it scrolls the outerScrollView.The PR made this path reachable from the expense form by opening
CategoryPickerModalfrom the anchored Category field.What changes do you think we should make in order to solve the problem?
In
CategoryPickerModal.tsx:shouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode={false}toPopoverWithMeasuredContent. Other list popovers already do this, for example FilterPopupButton.tsx:156.windowHeight * CONST.MODAL_MAX_HEIGHT_TO_WINDOW_HEIGHT_RATIO_LANDSCAPE_MODE(minus the container padding) instead of the fixed 416pt. Without this cap, step 1 alone would clip the bottom of the list.Investigation details
minHeight. The other changed how pickers fetch policy categories and tags. Neither changes scroll behavior.CategoryPickerModalalready had the fixed-height wrapper without the opt-out before this PR. It is also used by the Search table's inline category edit, which may show the same issue on native in landscape. I didn't verify that path.💡 Suggested AI code review rule
This bug looks like a recurring, mechanically detectable pattern. It could be worth a coding-standards rule so the AI reviewer catches the next one. Proposed for
Expensify/App:UI-4Opt list popovers out of the landscape ScrollView wrapperPopoverWithMeasuredContent,Popoveror bottom-dockedModalwhose children render a vertical scroller (SelectionList,FlashList,FlatList,ScrollView, or a*Picker/*Selectorthat wraps one) withoutshouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode={false}. Also cap fixed content heights to the landscape maximum.BaseModalwraps the children in its ownScrollView. That creates nested scrollers, as in this issue.<PopoverWithMeasuredContent/<Popoverblocks containingSelectionList|FlashList|FlatList|ScrollView|Pickerand noshouldWrapModalChildrenInScrollViewIfBottomDockedInLandscapeMode={false}.The full rule file, with the ❌/✅ code, would go in
App/.claude/skills/app-coding-standards/rules/. If the rule is worth adding, a maintainer can open it there as a draft PR.Next Steps for Contributor+ team:
To accept:
@MelvinBot implement [this](https://github.com/Expensify/App/issues/103140)to create a draft PR.To refine:
@MelvinBot <your feedback>To reject: Explain why you are rejecting Melvin's proposal.
5 remaining items
melvin-bot commentedon Oct 13, 2026
@DylanDylann 6 days overdue. This is scarier than being forced to listen to Vogon poetry!
DylanDylann commentedon Oct 14, 2026
will test again after #103552 is merged
melvin-bot commentedon Oct 19, 2026
@DylanDylann Huh... This is 4 days overdue. Who can take care of this?
DylanDylann commentedon Oct 20, 2026
melvin-bot commentedon Oct 20, 2026
@puneetlath @ikevin127 @DylanDylann this issue was created 2 weeks ago. Are we close to a solution? Let's make sure we're treating this as a top priority. Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!
DylanDylann commentedon Oct 22, 2026
@ikevin127 @trjExpensify Fixed on main
Screen.Recording.2026-10-22.at.11.50.35.mov
melvin-bot commentedon Oct 27, 2026
@DylanDylann Huh... This is 4 days overdue. Who can take care of this?