Skip to content

Fix keyboard focus staying on a removed element when an overlay popup or flyout closes - #22345

Merged
MrJul merged 3 commits into
AvaloniaUI:mainfrom
dariostrm:fix/focus-stuck-on-removed-element
Oct 7, 2026
Merged

MrJul merged 3 commits into
AvaloniaUI:mainfrom
dariostrm:fix/focus-stuck-on-removed-element

Conversation

@dariostrm

Copy link
Copy Markdown
Contributor

What does the pull request do?

Follow-up to #22113
When an overlay popup or flyout closes and the element that had focus before it can't be focused (e.g. the button that opened it, disabled while its command waits for the choice), the keyboard focus stays on the removed element: Tab/Shift+Tab do nothing and Enter/Space click the removed button again. This mainly affects browser apps, where popups are always overlays.

What is the current behavior?

See #22342 for a small example with a video and code to reproduce

Additional context

Why closing a native popup looks fine (according to claude) : Popup removes the content first and hides the popup window afterwards. Hiding it runs InputElement's IsVisible handler, and the popup window still has a stale IsKeyboardFocusWithin = true, so it calls Focus(null) a second time. The first call had already set _focusRoot = null, so the second one skips the restore and clears focus. It's an accidental rescue.

What is the updated/expected behavior with this PR?

After the popup/flyout with a focused element closes, and focus cannot be restored, focus is cleared

How was the solution implemented (if it's not obvious)?

After restoring the focus fails, we do not clear the focus ONLY IF the currently focused element is still visible (in addition to other checks that were in place before this PR of course)

Checklist

Breaking changes

Obsoletions / Deprecations

Fixed issues

Fixes #22342

dariostrm and others added 2 commits September 29, 2026 11:37
When a focus scope is removed or hidden while its focused element has the
focus and the root scope's focused element can't be focused (e.g. a button
disabled while its command waits for a choice in a flyout), the keyboard
focus stays on the removed or hidden element.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e restored

Focus(null) leaves the focus alone when the focused element is in another
focus scope than the focus root, but a removed or hidden element also passes
that check. Only apply it while the focused element is attached and visible.

Fixes AvaloniaUI#22342

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@MrJul MrJul added bug backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Sep 29, 2026
@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

NuGet packages

The packages for this pull request have been published (workflow run):

@MrJul

MrJul commented Oct 7, 2026

Copy link
Copy Markdown
Member

I've added a new test to PopupTests that fails before this PR with overlay popups.

I think it's important to test the real scenario here, as mocked services aren't always enough when focus and multiple window interactions are involved.

@MrJul MrJul left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@MrJul
MrJul enabled auto-merge October 7, 2026 16:14
@MrJul
MrJul added this pull request to the merge queue Oct 7, 2026
Merged via the queue into AvaloniaUI:main with commit 16572ae Oct 7, 2026
11 checks passed
MrJul added a commit that referenced this pull request Oct 9, 2026
… or flyout closes (#22345)

* Add failing test for focus staying on a removed or hidden element

When a focus scope is removed or hidden while its focused element has the
focus and the root scope's focused element can't be focused (e.g. a button
disabled while its command waits for a choice in a flyout), the keyboard
focus stays on the removed or hidden element.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Clear focus when the focused element is removed or hidden and can't be restored

Focus(null) leaves the focus alone when the focused element is in another
focus scope than the focus root, but a removed or hidden element also passes
that check. Only apply it while the focused element is attached and visible.

Fixes #22342

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Add popup tests with actual focus services

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Julien Lebosquain <julien@lebosquain.net>
@MrJul MrJul added backported-12.1.x and removed backport-candidate-12.1.x Consider this PR for backporting to 12.1 branch labels Oct 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keyboard focus stays on a removed element when an overlay popup/flyout closes

2 participants