Repository navigation
fix(web): clicked workspace areas no longer show the focus ring after a stray key - #28191
juliusmarminge wants to merge 5 commits into
Conversation
…e key press A workspace area focused by a mouse click starts matching :focus-visible once a lone key (a modifier delivered by a window switch) reaches the page, so it draws the area focus ring and counts as keyboard-reached on window return. Areas reached with F6 keep both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chromium's :focus-visible turns on for an area the user clicked as soon as any bare key reaches the page, such as a modifier delivered on window activation. That drew the F6 ring around the clicked home or conversation area and blocked the composer refocus on window return. The workspace focus controller now marks an area when it focuses the area itself and :focus-visible matches at that moment. Focus moving to another element or a pointer press clears the mark; a window switch does not. The ring and shouldRefocusComposerOnWindowFocus read that mark instead of bare :focus-visible, and the area rule also suppresses the UA focus ring. Fixes #28166 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mark an area on focusin when focus arrives there from elsewhere and is keyboard-visible, instead of only when the controller focuses it, so focus a dialog returns to the area keeps its ring. Window activation refocuses the same element and is not an arrival, so a clicked area still never rings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Workspace focus rings and window-return focus handling now distinguish keyboard navigation from clicked regions. The change is limited to transient browser focus behavior, with existing protected-control exceptions preserved. You can add or adjust custom eligibility rules. Learn more. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Track keyboard-focused workspace areas apps/web/src/lib/workspaceFocus.ts |
The controller marks qualifying keyboard focus and clears the marker when focus moves elsewhere, pointer input occurs, or the controller is disposed. |
Apply the focus marker to UI behavior apps/web/src/index.css, apps/web/src/components/ChatView.logic.ts, apps/web/src/lib/workspaceFocus.browser.test.ts, apps/web/src/components/ChatView.logic.browser.test.ts |
Workspace areas show a focus ring when marked for keyboard focus. Composer refocus eligibility uses the same marker. Browser tests cover the resulting focus behavior. |
Estimated code review effort: 2 (Simple) | ~12 minutes
Change: Bug fix · Severity of issue fixed: Low
Possibly related issues
- Issue 27170: The changes suppress the focus ring after pointer input, but do not address the issue’s reported scroll loss.
Suggested reviewers: t3dotgg
Merge Risk: 
Low · up to 9bda4
-
In a narrow recovery case, a stray key can still cause a ring and prevent composer refocus. The change is mergeable with awareness of this edge case.
Pre-merge checks: 
4
-
Full details: Title check
-
Explanation
The title names the main change: clicked workspace areas no longer show the focus ring after a stray key press. The changeset adds keyboard-visible focus tracking via data-workspace-keyboard-focus, switches the ring styling and window-return check to that mark, and suppresses the area's own :focus-visible outline. The title is specific and follows the conventional commit format, and it is concise. Its wording is a bit long at 81 characters, but it is clear.
Full details: Description check
-
Explanation
The description follows the repository template. It has Problem, Change, Scope and approval, and Verification sections. The Problem section gives the expected behavior and reproduction steps. The Change section explains the mechanism and why the related composer-refocus check changed. The Scope section links issue
#28166. Verification lists focused test commands with results, named failing tests before the fix, the real-app before and after comparison, and what was not checked (Wayland). The description does not include screenshots or recordings, and says they could not be attached. The template asks for before/after screenshots for UI changes, so this is a gap. The description also says the evidence is recorded in a table instead. The author should attach the screenshots or recordings, or link them, if they can be uploaded. The model line appears at the end as the template requests.
Full details: Linked Issues check
-
Explanation
Issue
#28166requires no ring when focus returns to a clicked workspace area without keyboard navigation, while preserving the ring for keyboard navigation such as F6.workspaceFocus.tsmarks only keyboard-visible arrivals and clears the mark on pointer input and disposal.index.csssuppresses the area:focus-visibleoutline and draws the ring only for the mark. The browser tests cover click, bare key input, window-return refocus, F6 navigation, dialog return, and the already-focused F6 case. The related composer-refocus check reads the same mark.
Full details: Out of Scope Changes check
-
Explanation
The changes stay within the linked issue scope. The controller state, CSS selector, composer-refocus selector, and browser tests all support correct workspace-area focus classification. The composer behavior is a direct consequence of the same incorrect
:focus-visibleclassification. No unrelated production feature or unrelated test change is present in the reviewed diff.
-
Finishing Touches
-
Generate docstrings
-
- Commit to this branch
- Create a new PR
Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
|
Thanks @juliusmarminge for the original fix and verification! #33525 carried this work into main in 6e4711d, including the focus-ring and composer-return fixes. Closing this as covered. |
Problem
A workspace area the user clicked showed the 2px
--ringoutline after any later bare key press reached the page. That includes a modifier delivered when the window is activated, as with Hyprland focus-follows-mouse or a Super-key window switch. The ring was drawn by[data-workspace-area]:focus-visible, and Chromium switches:focus-visibleon for the already focused element on keyboard input. Reproduced on main 15fe283 in the web app inside Electron 44 under Xvfb:home<main>gets focus with no ring.The same selector made
shouldRefocusComposerOnWindowFocustreat such a clicked area as "reached from the keyboard".Change
createWorkspaceFocusController(apps/web/src/lib/workspaceFocus.ts) marks an area withdata-workspace-keyboard-focuswhen focus arrives there from another element and is keyboard-visible at that moment. This covers F6, focus requests, and keyboard focus returning from a dialog. It also marks when the controller focuses the area that already has focus, which fires nofocusin(F6 with no other visible area). Window activation refocuses the same element, so it never counts as an arrival.The mark clears on focus moving elsewhere, on a pointer press, and on dispose. The ring in
index.cssand the window-return check inChatView.logic.tsread the mark instead of:focus-visible. An area's own:focus-visibleoutline is set tononeso the browser default does not come back.Scope and approval
Fixes #28166
Verification
vp test run --project browser src/lib/workspaceFocus.browser.test.ts src/components/ChatView.logic.browser.test.ts(apps/web): 18 passed. The two new tests fail on main:rings an area reached with F6, but not a clicked one after a bare key press:expected 'solid' to be 'none'refocuses the composer on window return from a clicked area after a bare key press:expected false to be trueindex.cssand also covers:vp run check:changed: format, lint, knip, typecheck, tests and React compiler all pass.solid 2pxringoutline: none)The reporter's row was re-run at the PR head 9bda46d with the same result. All other visible differences vanish at 3% fuzz (14 anti-aliased glyph pixels). Screenshots and recordings could not be attached from the triage environment, so this table records what they show.
Model: Claude Opus 5.5 (lead, tests, implementation, review B), GPT-6.1 Sol (review A, proof audit, captures), via T3 Code delegation on the Claude Code harness.
🤖 Generated with Claude Code