Right-anchor the Display popover to match the Filters popover#95065
Conversation
Co-authored-by: Shawn Borton <shawnborton@users.noreply.github.com>
|
🚧 shawnborton has triggered a test Expensify/App build. You can view the workflow run here. |
|
🤖 I looked into the failing checks. There's no code fix to push — the only failing check is the PR Author Checklist, which only a human can complete.
Every real CI check that has finished is green — ESLint, Prettier, React Compiler, Bun tests, Next step: fill in the |
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
This comment has been minimized.
This comment has been minimized.
|
@MelvinBot please fill out the pr author checklist. |
|
Done — I filled out the PR Author Checklist in the description. I checked the items I can honestly verify as the author (issue linked, testing steps written, code patterns / review guidelines followed, and the conditional items that don't apply to this change — new files, CSS, assets, message-editing code, Storybook, deeplinks). I left the following unchecked because they require manual execution I can't attest to — they're for the human co-author before marking this "ready for review":
Note: this is a UI positioning change, and design ( |
|
@FitseTLT since this is a Melvin PR, can you please help with screenshots for all platforms? Thanks! |
|
🤖 Update: all the previously-pending CI checks have now finished and passed — That confirms my earlier comment: there's no code fix to push. The only remaining non-passing check is the PR Author Checklist ( |
| sentryLabel={CONST.SENTRY_LABEL.SEARCH.FILTER_DISPLAY} | ||
| value={null} | ||
| PopoverComponent={displayPopup} | ||
| popoverAnchorAlignment={{ |
There was a problem hiding this comment.
❌ CONSISTENCY-3 (docs)
The exact same popoverAnchorAlignment object literal is defined twice in this component — once in the narrow/medium FilterPopupButton branch (lines 50-53) and again here in the wide-layout DropdownButton branch (lines 82-85). The identical alignment object also already exists in the sibling SearchAdvancedFiltersButton.tsx (lines 90-93). Duplicating this constant in three places means any future change to the anchor alignment must be made in multiple spots, raising maintenance overhead and drift risk.
Hoist the alignment into a single named constant and reuse it in both branches (and ideally share it with the Filters button):
const DISPLAY_POPOVER_ANCHOR_ALIGNMENT = {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
} as const;
// narrow/medium branch
<FilterPopupButton PopoverComponent={displayPopup} popoverAnchorAlignment={DISPLAY_POPOVER_ANCHOR_ALIGNMENT} ... />
// wide-layout branch
<DropdownButton ... PopoverComponent={displayPopup} popoverAnchorAlignment={DISPLAY_POPOVER_ANCHOR_ALIGNMENT} />Reviewed at: ff08acf | Please rate this suggestion with 👍 or 👎 to help us improve! Reactions are used to monitor reviewer efficiency.
There was a problem hiding this comment.
@MelvinBot can u use a common const for both cases pls?
There was a problem hiding this comment.
Agreed — the popoverAnchorAlignment object is duplicated across the two branches, so hoisting it into one named const is the right call. Here's the change I'd make (scoped to both cases in this file):
// near the top of the component, after the hooks
const DISPLAY_POPOVER_ANCHOR_ALIGNMENT = {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP,
} as const;
// narrow/medium branch
<FilterPopupButton
PopoverComponent={displayPopup}
popoverAnchorAlignment={DISPLAY_POPOVER_ANCHOR_ALIGNMENT}
renderButton={/* ... */}
/>
// wide-layout branch
<DropdownButton
label={translate('search.display.label')}
sentryLabel={CONST.SENTRY_LABEL.SEARCH.FILTER_DISPLAY}
value={null}
PopoverComponent={displayPopup}
popoverAnchorAlignment={DISPLAY_POPOVER_ANCHOR_ALIGNMENT}
/>I'd keep it local to SearchDisplayDropdownButton rather than also sharing with SearchAdvancedFiltersButton — the two live in separate components and a shared module for one small alignment literal would be more indirection than it's worth. Happy to go further if you'd prefer a shared const across both buttons.
I can only make code changes when directed by the PR author, an assignee, or an existing co-author. To have me implement this, the PR assignee or author should reply with a request tagging me (or add me as an assignee), and I'll push it.
There was a problem hiding this comment.
Done — I've added you (FitseTLT) as an assignee on this PR. Since you're now an assignee, you're authorized to direct code changes, so reply here tagging me and I'll implement the shared-const refactor.
There was a problem hiding this comment.
@MelvinBot wdyt of the comment #95065 (comment)
There was a problem hiding this comment.
I agree with it — it's a legit DRY cleanup. The popoverAnchorAlignment literal is byte-for-byte identical in the two branches of this component (the narrow/medium FilterPopupButton and the wide-layout DropdownButton), so hoisting it into one named const removes the drift risk the bot flagged.
Two caveats on scope:
- I'd keep the const local to
SearchDisplayDropdownButton. The bot also suggests sharing it withSearchAdvancedFiltersButton, but those are separate components and a shared module for one tiny alignment literal is more indirection than it buys us. If we ever want them to move in lockstep that's a different, deliberate decision. - The values here (
RIGHT/TOP) are the right-anchor this PR is specifically adding, so the const is just deduping — no behavior change.
I posted the concrete diff in my earlier reply on this thread. I can't push it myself, though — I only make code changes when directed by the PR author, an assignee, or an existing co-author, and none of those apply here. If an assignee/author tags me (or adds me as an assignee), I'll apply it.
There was a problem hiding this comment.
@MelvinBot I am an assignee of the pr pls make the changes
There was a problem hiding this comment.
Done ✅ Hoisted the duplicated popoverAnchorAlignment object into a single DISPLAY_POPOVER_ANCHOR_ALIGNMENT const and reused it in both the FilterPopupButton and DropdownButton branches — pushed in 17e3223.
I kept it local to this component rather than also sharing it with SearchAdvancedFiltersButton, since that lives in a separate component and a shared module for one small alignment literal would add more indirection than it saves.
Lint and Prettier pass on the changed file. Typecheck flagged only pre-existing expensify-common/dist/* errors unrelated to this change.
|
🤖 Update: all real CI checks are now green — the only remaining failure is the PR Author Checklist ( The 5 unchecked items are all under "I ran the tests on all platforms & verified they passed on:" — these are platform-testing boxes only you can tick after verifying,
Check those 5 boxes (and drop the screenshots/videos in the platform sections) and the |
|
@shawnborton the first time after page refresh when u open the popup, it moves to the left but this also happens for filters button and also on main for display, so should we handle it in another issue? 2026-07-02.00-37-19.mp4 |
|
Agreed — that first-open jump is pre-existing and out of scope for this PR. Handle it separately (or leave it, since it's a subtle one-frame flicker). Why it's not this PR's problem: you already confirmed it reproduces on Root cause of the jump (for the follow-up)It's the two-pass measure-then-position in A fix would live in the shared measurement component (e.g. keep it hidden until measured, or seed a real width), not in If you want it tracked, I'm happy to open a separate issue for the shared-popover flicker. |
|
🤖 I looked into the failing checks. The only two that are red are PR Author Checklist and PR Reviewer Checklist — and neither can be fixed by pushing code.
Every actual code/CI check is green — Bun tests, Jest Next step: the human co-author should complete the author checklist (fill in the |
|
Hmm I'm not seeing the bug in your video? Seems like we're all good to proceed here. |
Ha ha, You 're right. may be the vid recorder doesn't have enough frame rate 😄 |
Reviewer Checklist
Screenshots/Videos |
|
We did not find an internal engineer to review this PR, trying to assign a random engineer to #95059 as well as to this PR... Please reach out for help on Slack if no one gets assigned! |
|
Update: the Jest Unit Tests run has now finished. 8 of 9 shards passed — only I tried to trigger the re-run myself but this environment blocks |
trjExpensify
left a comment
There was a problem hiding this comment.
Good from product 👍
No, I am not the author, @shawnborton is |
|
@FitseTLT for future reference, given that you are the C+ reviewer here, please do not assign yourself as a PR author and ask Melvin to make changes - that should be something that the PR author does (in this case, it's me). |
|
Checklist is filled out now, let's get this into final review. |
So you want me to ask you to assign me to the pr? B/c I asked melv to assign me as I can not command it unless I am an assignee of the PR. |
|
@MelvinBot merge main |
|
No, you are the reviewer of the PR, not the assignee. |
|
We don't want a situation where we have someone making commits that's also going to be approving the PR. |
|
But a reviewer requires changes to be made. Should I tag you on every change requests? |
|
Yes, you should. The same way you would tag any other PR author to make changes. Thanks! |
|
Ok can u merge latest main to see if jest passes? @shawnborton 😄 |
|
Haha yes but at this point you are already a PR author. I am saying, for future reference, please let's keep the roles of reviewer and author more clearly divided. Looks like you already asked @MelvinBot above to merge main, so let's see if that works. |
|
Unfortunately in most cases where the pr is raised my melvin the C+ is both reviewer and author/assigne. That's why I was following it. |
…RightAnchor Co-authored-by: Fitsum Abebe <FitseTLT@users.noreply.github.com>
|
🤖 Merged |
|
@iwiznia tests passed. Ready |
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚧 iwiznia 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/iwiznia in version: 9.4.29-0 🚀
|
Help site review — no changes requiredI reviewed the changes in this PR against the help site articles under Conclusion: No help site updates are needed. This PR is a purely cosmetic UI positioning fix — it right-anchors the Display popover on the Search/Spend page so it aligns with the Filters popover. The only change is adding a Since the help site describes what features do and how to use them (not pixel-level popover alignment), there is nothing to document here. No draft PR was created. cc @shawnborton — let me know if you'd like me to reconsider. |
|
🚀 Deployed to staging by https://github.com/iwiznia in version: 9.4.31-0 🚀
|
No help site changes required 📚I reviewed the changes in this PR against Expensify's help site files under Conclusion: No documentation updates are needed, so I did not open a docs PR. Why: This is a purely cosmetic UI positioning fix. It adds
Help site articles document features and how-to flows, not the exact alignment of a popover, so none of the existing articles reference or depend on this behavior. If you'd like a docs update anyway (e.g., screenshots in a help article need refreshing to reflect the corrected alignment), let me know which article and I'll draft it. No help site PR was created since no documentation changes are required. @shawnborton, if you disagree and there's an article that should be updated, point me to it and I'll draft the changes. |
|
🚀 Deployed to production by https://github.com/grgia in version: 9.4.31-0 🚀
Bundle Size Analysis (Sentry): |






Explanation of Change
The Display popover on the Search/Spend page was not right-anchored to its button, so it rendered horizontally offset compared to the Filters popover.
Both buttons share the same
FilterPopupButton→usePopoverPosition→PopoverWithMeasuredContentmachinery. The Filters button explicitly passespopoverAnchorAlignment={{ horizontal: RIGHT, ... }}, but the Display button passed nothing, soFilterPopupButtonfell back to itsANCHOR_ORIGINdefault (horizontal: LEFT). LEFT alignment resolves the anchor x to the button's left edge (x) instead of its right edge (x + width), which is what made the Display menu appear misaligned.This PR adds
popoverAnchorAlignmentwithhorizontal: RIGHTto both render paths ofSearchDisplayDropdownButton(the narrow/mediumFilterPopupButtonand the wide-layoutDropdownButton), matching the Filters button so the Display popover right-anchors to its button.Fixed Issues
$ #95059
PROPOSAL: #95059 (comment)
Tests
// TODO: The human co-author must fill out the tests you ran before marking this PR as "ready for review".
// Please describe what tests you performed that validate your changes work.
Offline tests
Same as tests.
QA Steps
// TODO: The human co-author must fill out the QA tests you ran before marking this PR as "ready for review".
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)Avatar, 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