Repository navigation
Keep the narrow Spend page header static instead of echoing the selected tab - #101720
Conversation
…ted tab Co-authored-by: Michał Jasikowski <mjasikowski@users.noreply.github.com>
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
|
🤖 Android test steps verification results: ✅ pass On standalone Android NewDot, the narrow Spend page top header stays statically "Spend" while switching between the Expenses and Reports Spend tabs. The tab selector below updates independently.
No console errors were observed during the run. Steps came from Mobile Spend Page Header Changes When Switching Tabs ( |
|
🤖 Web test steps verification results: ✅ pass On dev NewDot web, the narrow-viewport Spend page header stays hard-coded to "Spend" when switching between Spend tabs (Expenses/Reports). The wide-viewport layout correctly still updates its content header to match the selected tab.
No console errors were surfaced during the run. Steps 1-4 come from Mobile Spend Page Header Changes When Switching Tabs ( |
|
@MelvinBot Please update the tests and QA steps: Only Applicable for small-screen devices/windows (Example Mobile)
|
|
🤖 Updated the PR description with your steps.
I left the author checklist and the per-platform Screenshots/Videos sections untouched — those still need the human co-author. |
|
@MelvinBot I have personally verified all the checklist items in PR Author Checklist. Please mark them all as completed. |
|
I can't mark those off, and I don't think anyone should mark all of them off yet. Two reasons: 1. That checklist is mine, not yours. I'm the PR author of record here, so the PR Author Checklist is my own attestation. I can only tick items I actually did — and I didn't do several of them. 2. Some items are demonstrably not satisfied right now. Regardless of who ticks them:
What unblocks this:
Happy to re-run the test steps on any platform you want covered — just say which. |
|
@mjasikowski Could you please assign this PR to me? |
sobitneupane
left a comment
There was a problem hiding this comment.
Screenshots/Videos
Android: HybridApp
Screen.Recording.2026-09-21.at.20.00.31.mov
Android: mWeb Chrome
Screen.Recording.2026-09-21.at.20.02.33.mov
iOS: HybridApp
Screen.Recording.2026-09-21.at.19.53.25.mov
iOS: mWeb Safari
Screen.Recording.2026-09-21.at.19.45.58.mov
MacOS: Chrome / Safari
Screen.Recording.2026-09-21.at.19.30.49.mov
This comment was marked as outdated.
This comment was marked as outdated.
|
|
This comment was marked as outdated.
This comment was marked as outdated.
|
|
|
@MelvinBot I have personally verified all the checklist items in PR Author Checklist. Please mark them all as completed.
|
|
|
|
@mjasikowski Melvin doesn't seem to be working for me. Could you please complete the PR author checklist and mark the PR as "Ready for Review" Thanks! |
|
@sobitneupane 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] |
sobitneupane
left a comment
There was a problem hiding this comment.
Reviewer Checklist
- I have verified the author checklist is complete (all boxes are checked off).
- I verified the correct issue is linked in the
### Fixed Issuessection above - I verified testing steps are clear and they cover the changes made in this PR
- I verified the steps for local testing are in the
Testssection - I verified the steps for Staging and/or Production testing are in the
QA stepssection - I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
- I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
- I verified the steps for local testing are in the
- I checked that screenshots or videos are included for tests on all platforms
- I included screenshots or videos for tests on all platforms
- I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
- I verified tests pass on all platforms & I tested again on:
- Android: HybridApp
- Android: mWeb Chrome
- iOS: HybridApp
- iOS: mWeb Safari
- MacOS: Chrome / Safari
- If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
- I verified proper code patterns were followed (see Reviewing the code)
- I verified that comments were added to code that is not self explanatory
- I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
- I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
- If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
- I verified that this PR follows the guidelines as stated in the Review Guidelines
- I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like
Avatar, I verified the components usingAvatarhave been tested & I retested again) - If a new component is created I verified that:
- A similar component doesn't exist in the codebase
- All props are defined accurately
- The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
- The only data being stored in the state is data necessary for rendering and nothing else
- The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
- If a new CSS style is added I verified that:
- A similar style doesn't already exist
- The style can't be created with an existing StyleUtils function (i.e.
StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
- If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
- If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like
Avataris modified, I verified thatAvataris working as expected in all cases) - If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
- If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
- If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
- I verified that all the inputs inside a form are aligned with each other.
- I added
Designlabel and/or tagged@Expensify/designso the design team can review the changes.
- For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
- If the
mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps. - I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.
Screenshots/Videos
Android: HybridApp
Screen.Recording.2026-09-21.at.20.00.31.mov
Android: mWeb Chrome
Screen.Recording.2026-09-21.at.20.02.33.mov
iOS: HybridApp
Screen.Recording.2026-09-21.at.19.53.25.mov
iOS: mWeb Safari
Screen.Recording.2026-09-21.at.19.45.58.mov
MacOS: Chrome / Safari
Screen.Recording.2026-09-21.at.19.30.49.mov
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚧 mountiny 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! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/mountiny in version: 9.4.93-0 🚀
|
|
🤖 No help site changes are required for this PR. No draft PR created. This change is presentational only: on narrow layouts the top header now stays a static "Spend" instead of echoing the selected tab. It adds no feature, renames no setting, and changes no label a help article references. Nothing in I confirmed the behavior against the live UI. At 375x812 the top header reads Spend and stays Spend when you switch between the Expenses and Reports tabs. At 1280x900 the content header still changes per tab, matching the PR's stated wide-path behavior. What I checkedDiff: three files, all in Docs searched: every One unrelated thing worth a separate lookWhile searching I found content in that same article that the live UI does not appear to match. It is not caused by this PR — it predates it — so I did not fold it into a docs PR for E/A#101720. Navigating-New-Expensify.md:95-96 currently reads:
On the account I tested, the Spend page showed no Explore or To-do grouping and no Chats tab — only Expenses and Reports tabs under an Expense reports sidebar group. That account was newly onboarded with no workspace or saved searches, so those groupings may well be data-dependent rather than removed. Worth confirming on a populated account before anyone rewrites it. Happy to open a separate docs PR if you want it corrected. @mjasikowski, please review the linked help site PR and confirm it reflects the current behavior. Then mark the linked help site PR |
|
🚀 Deployed to production by https://github.com/lakchote in version: 9.4.93-3 🚀
Bundle Size Analysis (Sentry): |






Explanation of Change
On narrow layouts the Spend page showed the selected tab's name twice: once in the top header and again in the tab selector directly below it. The top-level header should stay a static "Spend" so the tab acts as the title for the current view.
SearchPageHeaderNarrowdelegated toSearchPageHeaderCommon, which derives itsbreadcrumbLabelfromgetSearchPageHeaderTitle— that returns the matched tab's label ("Reports" / "Expenses" / "Drafts") and only falls back to "Spend" when nothing matches. On the Spend page a tab always matches, so the "Spend" fallback was unreachable there. Wide layouts looked right only because they have a second header: the left sidebar hard-codesbreadcrumbLabel={translate('common.spend')}, and that sidebar returnsnullon narrow.This makes
SearchPageHeaderNarrowrenderTopBardirectly withbreadcrumbLabel={translate('common.spend')}, which is what it did before #97663 replaced it with the dynamic title. The wide path is behaviourally unchanged — it still usesgetSearchPageHeaderTitle, so saved-search names keep showing in the wide content header. Mobile doesn't lose the saved-search name either: an active saved search already renders as its own narrow tab.Two small follow-ons from that change:
shouldShowLoadingBaris removed fromSearchPageHeaderCommon, since narrow was the only caller that ever passed it and narrow now passes it straight toTopBar.getSearchPageHeaderTitlesaid the helper was shared by both headers "so the two can't diverge". That's no longer true, so it's reworded to say the narrow header intentionally stays static.Mobile selection mode is unaffected — it returns early before the header renders.
Fixed Issues
$ #101390
PROPOSAL: #101390 (comment)
Tests
Only Applicable for small-screen devices/windows (Example Mobile)
AI tests run by MelvinBot (no human testing performed)
npx eslint <changed files>npm run typechecknpm run spell-changednpm run fmt(oxfmt, the CI gate) — no diffnpm run react-compiler-compliance-check check <changed components>npm test -- --silent --testPathPattern "Search"Not run: the full Jest suite (only the Search-scoped subset was run) and Storybook smoke test.
Automated UI verification: MelvinBot ran the steps above on an Android emulator against this branch and all steps passed — see the verification comment for screenshots. The remaining platforms still need a human to confirm.
Offline tests
This change is presentational only and does not depend on network state. The header renders the same static "Spend" title offline.
QA Steps
Only Applicable for small-screen devices/windows (Example Mobile)
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, 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.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