Fix keyboard focus not returning to FAB and composer + after Back - #97678
Fix keyboard focus not returning to FAB and composer + after Back#97678Krishna2323 wants to merge 8 commits into
Conversation
Signed-off-by: krishna2323 <belivethatkg@gmail.com>
|
@MelvinBot review |
Review — LGTM with one minor nitThe approach is correct and the diff is clean. Root cause is accurately identified: the create-menu triggers Verified the wiring holds together:
Nit (low severity, non-blocking)In In practice this is benign: Testing noteThe three new unit tests are well-targeted (registration-before-open ordering, native no-op path, deactivate-on-hide). They mock I couldn't validate the end-to-end keyboard focus-return behavior automatically — the web test tooling here can't dispatch raw Tab/Enter/Arrow keys or read |
Signed-off-by: krishna2323 <belivethatkg@gmail.com>
|
@MelvinBot review |
Re-review — nit resolved, LGTM
Nice side benefit: registration and deactivation now both key off Test coverage followed the move correctly: the old No new concerns. Same caveat as before: I can't auto-verify the end-to-end keyboard focus-return in CI (the web tooling can't dispatch raw Tab/Enter/Arrow keys or read |
|
@mkhutornyi 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] |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 24e43a7105
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // launcher later. | ||
| const launcher = resolvePopoverLauncherElement(actionButtonRef); | ||
| if (launcher) { | ||
| markActivePopoverLauncherDeactivated(launcher); |
There was a problem hiding this comment.
Keep the composer launcher alive through file picking
When the user chooses Add attachment, triggerAttachmentPicker only calls onAttachmentPicked after the OS file picker returns, and that handler navigates to REPORT_ADD_ATTACHMENT; marking the composer + launcher deactivated as soon as the menu hides means LauncherStack prunes it after the 1s clear delay. If the user takes more than a second to pick a file, the forward navigation has no launcher to capture, so Back from the attachment preview will not restore focus to the composer + despite this flow being covered by the fix. Re-register or otherwise preserve the launcher when the picker returns before navigating.
Useful? React with 👍 / 👎.
joekaufmanexpensify
left a comment
There was a problem hiding this comment.
Good for product.
|
Flow 2 — Chat Composer Create Menu
This happens but briefly. Then automatically focuses on composer. I think it's expected. |
|
Is this out of scope? Esc on popover menu doesn't return to FAB Screen.Recording.2026-08-05.at.3.41.01.PM.mov |
|
This is web-only fix. |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / SafariScreen.Recording.2026-08-05.at.3.49.53.PM.mov |
|
Similar to Esc on popover menu, "Create report" case not working. Screen.Recording.2026-08-05.at.3.50.43.PM.mov |
@rushatgabhane, should we cover these in this PR or handle them in a follow-up? The original issue was specifically about fixing the Track Distance and Chat flows. |
… trap Signed-off-by: krishna2323 <belivethatkg@gmail.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.
|
|
@MelvinBot review |
ReviewTwo CI checks are red — both come entirely from the new test file and block merge. Fix those first; the implementation itself looks correct (details below). 🔴 Blocking — failing checks (
|
Signed-off-by: krishna2323 <belivethatkg@gmail.com>
Signed-off-by: krishna2323 <belivethatkg@gmail.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 53399ebbaa
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // out to the FAB behind that modal, and leave the user nothing to return to when it closes. | ||
| const isCoveredByNewerTrap = sharedTrapStack.length > trapDepthAtActivateRef.current; | ||
| // Mark first so a throw in restoreFocusWithModality can't leak the LauncherStack entry; the deferred clear keeps the post-hide capture window. | ||
| markActivePopoverLauncherDeactivated(launcher); |
There was a problem hiding this comment.
Preserve launcher entries while a newer trap owns them
When an anchorless confirm opens from a popover (for example FAB/composer Create report when the empty-report confirmation is shown), its activation falls back to the popover launcher and setActivePopoverLauncher dedupes the stack entry by element. The closing popover then still runs this deactivation even though isCoveredByNewerTrap is true, so the newer confirm's only launcher entry becomes deactivated and expires after LAUNCHER_CLEAR_DELAY_MS; if the user spends more than a second in the confirm before pressing Create report or the Reports link, the forward navigation can't capture the FAB/composer fallback and Back won't restore focus to the launcher.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Tested this case and works fine
Screen.Recording.2026-08-13.at.5.37.33.PM.mov
|
🤖 Regression testing: runtime keyboard checks could not be run; one code-level regression surface worth a second look. Heads up on verification: I couldn't execute this PR's actual regression checks at runtime. Every assertion here is keyboard-driven (Tab / Arrow / Enter / Esc → focus returns to the FAB / composer What did pass (mouse-driven smoke only — proves routes don't break, not focus return):
Code-level regression surface worth confirming ( The new focus "shield" is an app-wide singleton, not scoped to the trap that set it.
Testing environment details
Evidence Reply with |
|
Please pull main |
Review — LGTM, all checks greenRe-reviewed at The implementation is unchanged from what I traced before and still holds up — the anchor→ Two standing non-blocking notes (unchanged — for the manual checklist)
Verification note: I still can't auto-verify the end-to-end keyboard focus-return — the web test harness here can't dispatch raw Tab/Enter/Esc/Arrow keys or read Merge status: |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
|
We did not find an internal engineer to review this PR, trying to assign a random engineer to #96972 as well as to this PR... Please reach out for help on Slack if no one gets assigned! |
Signed-off-by: krishna2323 <belivethatkg@gmail.com>
…'s focus return Signed-off-by: krishna2323 <belivethatkg@gmail.com>
|
lmk when this is ready again |
|
It's ready 🙂 |
|
Latest changes seems require quick retest |
|
Works well on my end |
|
@mkhutornyi would you mind retesting & reapproving please? |


Explanation of Change
Fixed Issues
$ #96972
PROPOSAL:
Tests
Flow 1 — FAB Create Menu (Track Distance)
Flow 2 — Chat Composer Create Menu
Regression Checks
Offline tests
QA Steps
Same as tests
Verify that no errors appear in the JS console
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.md) were followedAvatar, 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.ScrollViewcomponent to make it scrollable when more elements are added to the page.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
web_chrome_mac.mp4
web_chrome.mp4