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
[Due for payment 2026-10-23] Report - "Find Expense" input is not visible with keyboard opened on landscape mode. #102021
Version Number: 9.4.92-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:#100886 Email or phone of affected tester (no customers):ibellicotest+2766@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: Motorola MotoG60 / Android 12 (Hybrid app) App Component: Money Requests
Action Performed:
Prerequisite: Account has a workspace.
Prerequisite: Account has at least one expense created.
Open the Expensify app.
Navigate to workspace chat.
Create an empty report.
Tap on "Add Expense" > "Add existing expense"
Turn to landscape mode.
Tap on "Find expene" input to trigger keyboard.
Note that input is now displayed behind "Add to report" button.
Expected Result:
"Find expense" input should remain visible while keyboard is opened on landscape mode.
Actual Result:
"Find expense" input is displayed behind "Add to report" button and is not visible while in landscape mode.
👋 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.
Confirmed: PR #100886 moved the "Find expense" input from a pinned position above the list into the list's scrollable content, so it gets clipped out of view when the keyboard collapses the list viewport in landscape. A revert is unattractive because the PR is a 15-file refactor of the shared Table component and a fix-forward for another blocker from the same PR (#102003) is already in review, so reverting would invalidate that work; a small targeted fix on this screen is lower risk.
Assigned: @Krishna2323 (PR author), @JS00001 and @situchan (approving reviewers) — already assigned by Melvin, no change made. Labels: No changes. DeployBlockerCash is kept (an App PR caused it); DeployBlocker was not present, so nothing was removed.
📋 Detailed Analysis
Evidence
Before #100886 this screen used SelectionList, which renders the search input outside the FlashList, directly under the screen header (BaseSelectionList.tsx#L513-L515, with the footer rendered after the list at #L570). The input was therefore part of the non-shrinkable page chrome and could never be covered by the footer — the list itself absorbed all the vertical shrink when the keyboard opened.
Expensify/App#100886 is on the current checklist (Deploy Checklist: New Expensify 2026-09-23), the bug is staging-only and the report itself is "N/A in production - new feature".
src/pages/AddExistingExpense.tsx is the only screen in the repo that renders both a @components/Tables/* table and a FixedFooter, so this layout combination is new as of this PR and not exercised anywhere else.
Side effect of the same change worth noting: the old code only showed the search input when there were at least CONST.STANDARD_LIST_ITEM_LIMIT (12) expenses; the Table.FilterBar renders whenever there is any data, so the broken input is now reachable with a couple of expenses too.
Supporting (pre-existing, unchanged) code that makes the new layout fail:
FixedFooter.tsx#L43 — the footer is flexShrink0, so it never gives up height.
ScreenWrapperContainer.tsx#L220-L228 with the default behavior="padding" (#L95) — with the keyboard open the whole screen is compressed into windowHeight - keyboardHeight.
Static analysis only — no device/browser verification was available in this run, so the geometry below is computed from the styles rather than measured.
Root Cause
With the keyboard open, ScreenWrapper's KeyboardAvoidingView (behavior="padding") squeezes header + content + footer into windowHeight - keyboardHeight. In that squeezed box:
HeaderWithBackButton keeps its variables.contentHeaderHeight of 72dp.
The table wrapper is styles.flex1 (flex: 1 → flexGrow: 1, flexShrink: 1, flexBasis: 0) and the FlashList container adds mnh0 (minHeight: 0), so it is the only child that can shrink — and it shrinks all the way to ~0.
On a MotoG60 in landscape the usable height is roughly 393dp, and the Android landscape IME takes ~180–220dp, leaving ~170–210dp. Header + footer already consume ~145–170dp of that, so the list viewport ends up at roughly 0–50dp while the filter bar alone needs 56dp (h11 44dp + pb3 12dp). The search input, being the first thing inside the list's scroll content, is therefore clipped underneath the footer — which is what the tester sees as "displayed behind the Add to report button".
useScrollToFocusedInput cannot rescue it: it anchors the focused input to the top of the list container and bails out when delta <= 0, and the search input is already at the top of the content, so no scroll happens — and with a ~0dp viewport there is nowhere to scroll it to anyway.
Suggested fix directions (for the assignees to pick)
Free the vertical space while typing (smallest, page-level): in AddExistingExpense.tsx, skip/collapse the FixedFooter while the keyboard is shown (useKeyboardState), at least on narrow layouts. The confirm button is unreachable while the keyboard covers it anyway, and Button.KeyboardShortcut still handles Enter. Needs a quick design sanity check.
Pin the filter bar (restores pre-PR behaviour): render <Table.FilterBar> as a direct child of <Table> instead of inside <Table.ListHeader>, so it sits above the header/body run and stops scrolling (TableSemanticContainer.tsx#L121-L130). Caveat: that flips hasPageHeader to false, which changes the empty/no-results path (Table.NoResultsState is only used when a page header exists — TableBody.tsx#L259-L260), so "No results found" would need re-testing.
Table-level (follow-up, not for the blocker): teach Table to keep the FilterBar pinned on narrow layouts when the keyboard is shown, which would protect every future Table + fixed-footer screen.
If a fix can't land quickly, demoting this to a non-blocker is defensible (portrait is unaffected and the flow is fully usable there), but that call belongs to the DeployBlockerCash owner rather than this investigation.
💡 Suggested AI code review rule
This bug looks like a recurring, mechanically detectable pattern, so it may be worth a coding-standards rule so the AI reviewer catches the next one. Proposed for Expensify/App:
Rule:UI-4 Keep a list's search input out of the region the keyboard collapses
Condition: Flag a narrow-layout screen that renders a Table/list whose search or filter input lives in the scrollable content (Table.ListHeader, ListHeaderComponent) and a non-shrinkable FixedFooter inside a keyboard-avoiding ScreenWrapper; either pin the input outside the list or release the footer's height while the keyboard is shown.
Why:ScreenWrapper's KeyboardAvoidingView uses behavior="padding", and FixedFooter is flexShrink: 0, so the flex: 1 list is the only child that shrinks. In landscape the header plus footer consume the entire keyboard-free height, the list viewport collapses to ~0dp, and an input inside its scroll content is clipped behind the footer — exactly this issue.
Search pattern:grep -rl "FixedFooter" src/pages src/components --include=*.tsx | xargs grep -ln "@components/Tables/\|Table.ListHeader\|ListHeaderComponent" (this is how the offending screen was isolated — it is currently the only match).
Fix (✅): not landed yet — the pre-regression shape is BaseSelectionList.tsx#L513-L515, where the input is rendered above the list rather than inside it.
The full rule file, with the ❌/✅ code inline in Expensify/App's app-coding-standards format, would go in Expensify/App itself. If it's worth adding, a maintainer can open it there as a draft PR.
changed the title [-]Report - "Find Expense" input is not visible with keyboard opened on landscape mode.[/-][+][Due for payment 2026-10-23] Report - "Find Expense" input is not visible with keyboard opened on landscape mode.[/+]on Oct 16, 2026
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.12-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-23. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]
Activity
applause-bot commentedon Sep 23, 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/30eaa20999fb7acf51f2f0645ea0c3d4d7fc3938a199fea797d64b077dc85f3f
melvin-bot commentedon Sep 23, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #100886
melvin-bot commentedon Sep 23, 2026
@JS00001 @situchan you have been assigned to this deploy blocker because you reviewed the offending PR: #100886
github-actions commentedon Sep 23, 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 23, 2026
@Krishna2323 you have been assigned to this deploy blocker because you authored the offending PR: #100886
melvin-bot commentedon Sep 23, 2026
💬 A slack conversation has been started in #expensify-open-source
MelvinBot commentedon Sep 23, 2026
🔍 Investigation Summary
Classification: Frontend bug
Causing PR: feat: use Table component for Add existing expense flow (
Expensify/App#100886) by @Krishna2323 (High confidence)Related Issues: Reports - Add existing expense to report doesn't work — same causing PR, fix already in review; Expense - Status modal is scrollable — same flow, different causing PR
Recommendation: ROLL FORWARD
Confirmed: PR #100886 moved the "Find expense" input from a pinned position above the list into the list's scrollable content, so it gets clipped out of view when the keyboard collapses the list viewport in landscape. A revert is unattractive because the PR is a 15-file refactor of the shared
Tablecomponent and a fix-forward for another blocker from the same PR (#102003) is already in review, so reverting would invalidate that work; a small targeted fix on this screen is lower risk.Assigned: @Krishna2323 (PR author), @JS00001 and @situchan (approving reviewers) — already assigned by Melvin, no change made.
Labels: No changes.
DeployBlockerCashis kept (an App PR caused it);DeployBlockerwas not present, so nothing was removed.📋 Detailed Analysis
Evidence
Before #100886 this screen used
SelectionList, which renders the search input outside theFlashList, directly under the screen header (BaseSelectionList.tsx#L513-L515, with the footer rendered after the list at#L570). The input was therefore part of the non-shrinkable page chrome and could never be covered by the footer — the list itself absorbed all the vertical shrink when the keyboard opened.After #100886 the input is a
Table.FilterBarnested inTable.ListHeader(AddExistingExpenseTable/index.tsx#L141-L143). That slot is explicitly "content that should scroll away with the table rows" (TableListHeader.tsx#L3-L11) and is rendered as theFlashListListHeaderComponent(TableBody.tsx#L241-L246,TableBody.tsx#L384-L390) — i.e. it now lives inside the region that collapses under the keyboard.Two more signals that point at this PR:
Expensify/App#100886is on the current checklist (Deploy Checklist: New Expensify 2026-09-23), the bug is staging-only and the report itself is "N/A in production - new feature".src/pages/AddExistingExpense.tsxis the only screen in the repo that renders both a@components/Tables/*table and aFixedFooter, so this layout combination is new as of this PR and not exercised anywhere else.Side effect of the same change worth noting: the old code only showed the search input when there were at least
CONST.STANDARD_LIST_ITEM_LIMIT(12) expenses; theTable.FilterBarrenders whenever there is any data, so the broken input is now reachable with a couple of expenses too.Verification
Affected files (all touched by #100886):
src/pages/AddExistingExpense.tsx#L200-L232— newScreenWrapper→ header +<View style={styles.flex1}>(table) +{footerContent}layout.src/pages/AddExistingExpense.tsx#L106-L120— footer moved out ofSelectionList'sfooterContentinto a standaloneFixedFooter.src/components/Tables/AddExistingExpenseTable/index.tsx#L141-L143— new file added by the PR; puts the search input inside the scrolling list header.Supporting (pre-existing, unchanged) code that makes the new layout fail:
FixedFooter.tsx#L43— the footer isflexShrink0, so it never gives up height.ScreenWrapperContainer.tsx#L220-L228with the defaultbehavior="padding"(#L95) — with the keyboard open the whole screen is compressed intowindowHeight - keyboardHeight.useScrollToFocusedInput/index.native.ts#L76-L85— the mechanism meant to keep the input above the keyboard.Static analysis only — no device/browser verification was available in this run, so the geometry below is computed from the styles rather than measured.
Root Cause
With the keyboard open,
ScreenWrapper'sKeyboardAvoidingView(behavior="padding") squeezes header + content + footer intowindowHeight - keyboardHeight. In that squeezed box:HeaderWithBackButtonkeeps itsvariables.contentHeaderHeightof 72dp.FixedFooterisflexShrink: 0— 52dp (componentSizeLargebutton) + 20dp (pb5) + bottom inset ≈ 72–95dp.styles.flex1(flex: 1→flexGrow: 1, flexShrink: 1, flexBasis: 0) and theFlashListcontainer addsmnh0(minHeight: 0), so it is the only child that can shrink — and it shrinks all the way to ~0.On a MotoG60 in landscape the usable height is roughly 393dp, and the Android landscape IME takes ~180–220dp, leaving ~170–210dp. Header + footer already consume ~145–170dp of that, so the list viewport ends up at roughly 0–50dp while the filter bar alone needs 56dp (
h1144dp +pb312dp). The search input, being the first thing inside the list's scroll content, is therefore clipped underneath the footer — which is what the tester sees as "displayed behind the Add to report button".useScrollToFocusedInputcannot rescue it: it anchors the focused input to the top of the list container and bails out whendelta <= 0, and the search input is already at the top of the content, so no scroll happens — and with a ~0dp viewport there is nowhere to scroll it to anyway.Suggested fix directions (for the assignees to pick)
AddExistingExpense.tsx, skip/collapse theFixedFooterwhile the keyboard is shown (useKeyboardState), at least on narrow layouts. The confirm button is unreachable while the keyboard covers it anyway, andButton.KeyboardShortcutstill handles Enter. Needs a quick design sanity check.<Table.FilterBar>as a direct child of<Table>instead of inside<Table.ListHeader>, so it sits above the header/body run and stops scrolling (TableSemanticContainer.tsx#L121-L130). Caveat: that flipshasPageHeadertofalse, which changes the empty/no-results path (Table.NoResultsStateis only used when a page header exists —TableBody.tsx#L259-L260), so "No results found" would need re-testing.Tableto keep theFilterBarpinned on narrow layouts when the keyboard is shown, which would protect every futureTable+ fixed-footer screen.If a fix can't land quickly, demoting this to a non-blocker is defensible (portrait is unaffected and the flow is fully usable there), but that call belongs to the DeployBlockerCash owner rather than this investigation.
💡 Suggested AI code review rule
This bug looks like a recurring, mechanically detectable pattern, so it may be worth a coding-standards rule so the AI reviewer catches the next one. Proposed for
Expensify/App:UI-4Keep a list's search input out of the region the keyboard collapsesTable/list whose search or filter input lives in the scrollable content (Table.ListHeader,ListHeaderComponent) and a non-shrinkableFixedFooterinside a keyboard-avoidingScreenWrapper; either pin the input outside the list or release the footer's height while the keyboard is shown.ScreenWrapper'sKeyboardAvoidingViewusesbehavior="padding", andFixedFooterisflexShrink: 0, so theflex: 1list is the only child that shrinks. In landscape the header plus footer consume the entire keyboard-free height, the list viewport collapses to ~0dp, and an input inside its scroll content is clipped behind the footer — exactly this issue.grep -rl "FixedFooter" src/pages src/components --include=*.tsx | xargs grep -ln "@components/Tables/\|Table.ListHeader\|ListHeaderComponent"(this is how the offending screen was isolated — it is currently the only match).src/pages/AddExistingExpense.tsx#L200-L232together withAddExistingExpenseTable/index.tsx#L141-L143BaseSelectionList.tsx#L513-L515, where the input is rendered above the list rather than inside it.The full rule file, with the ❌/✅ code inline in
Expensify/App'sapp-coding-standardsformat, would go inExpensify/Appitself. If it's worth adding, a maintainer can open it there as a draft PR.21 remaining items
JS00001 commentedon Oct 12, 2026
Waiting on a PR here
melvin-bot commentedon Oct 13, 2026
@Krishna2323 Huh... This is 4 days overdue. Who can take care of this?
Krishna2323 commentedon Oct 14, 2026
Started working on the fix.
Krishna2323 commentedon Oct 14, 2026
@situchan PR is ready for review: #104003
melvin-bot commentedon Oct 15, 2026
If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.
If a regression has occurred and you are the assigned CM follow the instructions here.
If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.
[-]Report - "Find Expense" input is not visible with keyboard opened on landscape mode.[/-][+][Due for payment 2026-10-23] Report - "Find Expense" input is not visible with keyboard opened on landscape mode.[/+]melvin-bot commentedon Oct 16, 2026
@Krishna2323 / @situchan
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.5.12-1 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-23. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]