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
Android - Expense - List report field auto closes when there are at least 8 list values #101823
Version Number: 9.4.91-0 Reproducible in staging?: Yes Reproducible in production?: No If this was caught during regression testing, add the test name, ID and link from BrowserStack: github.com//pull/100735 Email or phone of affected tester (no customers):jsdoijnodsdisojo@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: Samsung Galaxy S25 FE / Android 16 App Component: Money Requests
Action Performed:
Precondition:
Create list type report field with at least 8 list values.
Launch Expensify app.
Go to workspace chat.
Create two expenses.
Open the expense.
Tap on the list report field.
Expected Result:
List report field will not close after opening it.
Actual Result:
List report field closes after opening it.
It requires a few attempts for it to not close after opening it.
👋 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.
PR #100735 is the only reason a list report field opens a dropdown at all (it previously navigated to a full page), and it has produced five Android/inline-report-field deploy blockers in this one release; the remaining fix would have to change FilterPopupButton, which is shared by the Search and Table filter bars, which is not a safe mid-deploy change. Reverting clears this blocker and its siblings at once, and the feature can re-land with an idempotent, intent-guarded open.
Assigned: @Gonals and @daledah (approving reviewers of the causing PR) — already assigned by melvin-bot, no change made. The PR author is a bot, so no author assignment. Labels: No changes. DeployBlockerCash is kept (an App PR caused this and the fix lands in Expensify/App); DeployBlocker is not present, so there is nothing to remove.
At exactly 8 enabled values the dropdown starts rendering a search input, and the search input is what raises the Android soft keyboard inside the open dropdown. Below 8 no keyboard is ever raised by the dropdown, which is why 7 values behave correctly.
gh pr view 100735 --json files confirms all three are in the diff, along with MoneyReportView.tsx and MoneyRequestViewReportFields.tsx, which render the fields on both call sites.
Merge timing lines up: merged 2026-09-21 09:40 UTC into the 9.4.91-0 staging build; reported against 9.4.91-0 the same day, and it is not on production.
No other PR in the checklist touches report fields, FilterPopupButton, Popover, or keyboard handling.
Root Cause
The dropdown open is a toggle, and at ≥ 8 options the open becomes asynchronous and re-entrant, so a second toggle closes what the first just opened.
FilterPopupButton uses one toggleOverlay for everything — the trigger's onPress, the popover's onClose, and the closeOverlay handed to the content — and routes the open through KeyboardUtils.dismissKeyboardAndExecute: FilterPopupButton.tsx#L81-L112. A toggle is only correct if every trigger fires exactly once.
On Android, dismissKeyboardAndExecute runs the callback synchronously only when no keyboard is up; otherwise it defers it behind a keyboardDidHide listener, and on the e.height !== 0 branch it returns without removing that listener, so a stale callback can fire on a later keyboard hide: src/utils/keyboard/index.android.ts#L50-L69.
With ≥ 8 values the dropdown renders the SelectionList search input, which auto-focuses 300ms after mount unless disableAutoFocus is passed — and EditReportFieldDropdown does not pass it: SelectionList/components/TextInput.tsx#L121-L136. So the soft keyboard comes up while the dropdown is open, flipping the module-level isVisible flag to true and putting every subsequent open into the deferred, listener-based path.
The trigger can fire onPress more than once per tap: on native BaseTextInput wires the caller's onPress to both the wrapper pressable and the inner input's onPressOut (BaseTextInput/implementation/index.native.tsx#L441-L442), and ReportFieldInlineInput additionally binds the same handler to onSubmitEditing (#L216-L218). Once one of those toggles is deferred behind a keyboard event, it lands after the dropdown is already open and toggles it straight back shut — the reported "closes immediately after opening", and the "takes a few attempts" flakiness, since the outcome depends on the keyboard-event race.
For contrast, DatePicker — the closest analogue, also a TextInput with disableKeyboard opening a popover — does not misbehave because its open is idempotent and intent-guarded (setPickerVisibility(true) plus an openIntentRef), not a toggle: DatePicker/index.tsx.
If a roll-forward is preferred over a revert, the minimal fix is:
Split toggleOverlay in FilterPopupButton into idempotent openOverlay/closeOverlay, pass openOverlay as the trigger's onPress and the real closeOverlay as onClose and to PopoverComponent, and guard the deferred open with an intent ref the way DatePicker does.
Stop binding the same handler to both onPress and onSubmitEditing on the list trigger in ReportFieldInlineInput.
Optionally pass disableAutoFocus in EditReportFieldDropdown's textInputOptions when it is rendered inside the inline dropdown, so the dropdown never raises the keyboard on open.
Unverified: I could not run this on an Android device, so which of the extra triggers wins the race (the inner onPressOut versus onSubmitEditing versus a stale deferred callback) is inferred from the code rather than observed. The exact 8-value threshold matching REPORT_FIELD_LIST_SEARCH_THRESHOLD, and the defect itself — a toggle used as an open action, reachable from several triggers and deferred asynchronously whenever a keyboard is up — hold regardless.
Activity
applause-bot commentedon Sep 22, 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/2374974272ce60e1781919563d5aa7216042fe03d1f71b2e055e589e05f1108b
melvin-bot commentedon Sep 22, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #100735
github-actions commentedon Sep 22, 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 Sep 22, 2026
@Gonals @daledah you have been assigned to this deploy blocker because you reviewed the offending PR: #100735
melvin-bot commentedon Sep 22, 2026
💬 A slack conversation has been started in #expensify-open-source
MelvinBot commentedon Sep 22, 2026
🔍 Investigation Summary
Classification: Frontend bug
Causing PR: Show up to three report fields per row and edit them inline (
Expensify/App#100735) — authored by @MelvinBot, merged by @Gonals, approved by @Gonals and @daledah (High confidence)Related Issues: Android - Expense - List dopdown auto closes after focusing on text field and opening list (
Expensify/App#101802), Android - Expense - Report auto scrolls to bottom after opening report field (Expensify/App#101799), Expense - Cursor appears briefly on list report field after clicking on it (Expensify/App#101804), Expense - No background blur when Month/Year RHP is opened while editing report field inline (Expensify/App#101810) — all from the same PRRecommendation: REVERT
PR #100735 is the only reason a list report field opens a dropdown at all (it previously navigated to a full page), and it has produced five Android/inline-report-field deploy blockers in this one release; the remaining fix would have to change
FilterPopupButton, which is shared by the Search and Table filter bars, which is not a safe mid-deploy change. Reverting clears this blocker and its siblings at once, and the feature can re-land with an idempotent, intent-guarded open.Assigned: @Gonals and @daledah (approving reviewers of the causing PR) — already assigned by melvin-bot, no change made. The PR author is a bot, so no author assignment.
Labels: No changes.
DeployBlockerCashis kept (an App PR caused this and the fix lands inExpensify/App);DeployBlockeris not present, so there is nothing to remove.📋 Detailed Analysis
Evidence
Reproducible on staging
9.4.91-0, not on production, so the cause is in the current Deploy Checklist: New Expensify 2026-09-21 (Expensify/App#101773).Before PR Show up to three report fields per row and edit them inline #100735, tapping a list report field navigated to
DynamicEditReportFieldPage— a full screen, with no popover that could dismiss itself. That PR replaced the report-field rows with inline inputs and made alistfield open the option list in a popover instead (ReportFieldInlineInput.tsx#L150-L154,#L199-L222). The symptom described here cannot exist without that change.The reported threshold is exact, and it maps to a constant the same PR introduced:
src/CONST/index.ts#L7099-L7100ReportFieldInlineInput.tsx#L154At exactly 8 enabled values the dropdown starts rendering a search input, and the search input is what raises the Android soft keyboard inside the open dropdown. Below 8 no keyboard is ever raised by the dropdown, which is why 7 values behave correctly.
Verification
src/components/MoneyRequestReportView/ReportFieldInlineInput.tsx(new in the PR) — the list-field trigger and the popover content.src/pages/EditReportFieldDropdown.tsx#L102-L110— the PR added theshouldShowTextInputpass-through that turns the search input on at ≥ 8 options.src/CONST/index.ts#L7099-L7100— the threshold itself.gh pr view 100735 --json filesconfirms all three are in the diff, along withMoneyReportView.tsxandMoneyRequestViewReportFields.tsx, which render the fields on both call sites.9.4.91-0staging build; reported against9.4.91-0the same day, and it is not on production.FilterPopupButton,Popover, or keyboard handling.Root Cause
The dropdown open is a toggle, and at ≥ 8 options the open becomes asynchronous and re-entrant, so a second toggle closes what the first just opened.
FilterPopupButtonuses onetoggleOverlayfor everything — the trigger'sonPress, the popover'sonClose, and thecloseOverlayhanded to the content — and routes the open throughKeyboardUtils.dismissKeyboardAndExecute:FilterPopupButton.tsx#L81-L112. A toggle is only correct if every trigger fires exactly once.dismissKeyboardAndExecuteruns the callback synchronously only when no keyboard is up; otherwise it defers it behind akeyboardDidHidelistener, and on thee.height !== 0branch it returns without removing that listener, so a stale callback can fire on a later keyboard hide:src/utils/keyboard/index.android.ts#L50-L69.disableAutoFocusis passed — andEditReportFieldDropdowndoes not pass it:SelectionList/components/TextInput.tsx#L121-L136. So the soft keyboard comes up while the dropdown is open, flipping the module-levelisVisibleflag totrueand putting every subsequent open into the deferred, listener-based path.onPressmore than once per tap: on nativeBaseTextInputwires the caller'sonPressto both the wrapper pressable and the inner input'sonPressOut(BaseTextInput/implementation/index.native.tsx#L441-L442), andReportFieldInlineInputadditionally binds the same handler toonSubmitEditing(#L216-L218). Once one of those toggles is deferred behind a keyboard event, it lands after the dropdown is already open and toggles it straight back shut — the reported "closes immediately after opening", and the "takes a few attempts" flakiness, since the outcome depends on the keyboard-event race.For contrast,
DatePicker— the closest analogue, also aTextInputwithdisableKeyboardopening a popover — does not misbehave because its open is idempotent and intent-guarded (setPickerVisibility(true)plus anopenIntentRef), not a toggle:DatePicker/index.tsx.If a roll-forward is preferred over a revert, the minimal fix is:
toggleOverlayinFilterPopupButtoninto idempotentopenOverlay/closeOverlay, passopenOverlayas the trigger'sonPressand the realcloseOverlayasonCloseand toPopoverComponent, and guard the deferred open with an intent ref the wayDatePickerdoes.onPressandonSubmitEditingon the list trigger inReportFieldInlineInput.disableAutoFocusinEditReportFieldDropdown'stextInputOptionswhen it is rendered inside the inline dropdown, so the dropdown never raises the keyboard on open.Unverified: I could not run this on an Android device, so which of the extra triggers wins the race (the inner
onPressOutversusonSubmitEditingversus a stale deferred callback) is inferred from the code rather than observed. The exact 8-value threshold matchingREPORT_FIELD_LIST_SEARCH_THRESHOLD, and the defect itself — a toggle used as an open action, reachable from several triggers and deferred asynchronously whenever a keyboard is up — hold regardless.Gonals commentedon Sep 22, 2026
PR reverted
IuliiaHerets commentedon Sep 22, 2026
Xiaomi Redmi Note 10 / Android 12
9.4.91-1
Not repro
Screenrecorder-2026-09-22-14-12-22-272.mp4