RESOLVED FIXED278019
:focus-visible incorrectly shown after programmatic focus() when trigger button has child elements
https://bugs.webkit.org/show_bug.cgi?id=278019
Summary :focus-visible incorrectly shown after programmatic focus() when trigger butt...
Nikita Ourazbaev
Reported 2024-08-13 06:07:52 PDT
Created attachment 472136 [details] Screen recording of bug on iPad When element.focus() is called from a button's event listener, whether the focused element matches the :focus-visible selector depends on whether the event’s target element has child nodes. If the button has child nodes, :focus-visible styles will be shown. If the button doesn't have child nodes and only contains text, :focus-visible styles will not be shown. If the button has child nodes but they have pointer-events: none; applied, :focus-visible styles will not be shown. Expected behaviour is that regardless of the button's contents, :focus-visible styles should not be shown if button is pressed with touch or with a mouse pointer. This happens on iPhone, on the Mac, and on iPad. https://codepen.io/magiclantern/pen/KKjyWBB/8549ed2ce5fdd141e59a3dae28cbacfb Potentially related to https://bugs.webkit.org/show_bug.cgi?id=243289
Attachments
Screen recording of bug on iPad (2.43 MB, video/quicktime)
2024-08-13 06:07 PDT, Nikita Ourazbaev
no flags
testcase (1.61 KB, text/html)
2026-04-13 21:45 PDT, Karl Dubost
no flags
Nikita Ourazbaev
Comment 1 2024-08-13 17:06:54 PDT
Just to clarify, the :focus-visible styles are shown (or not shown) on the element that is focused, but whether or not they’re shown depends on the content of the button that triggers the event listener that calls element.focus(). The content/markup of the element that gets focus does not seem to matter here, but in the code example it happens to also be a button.
Radar WebKit Bug Importer
Comment 2 2024-08-20 06:08:15 PDT
Tim Nguyen (:ntim)
Comment 3 2025-05-23 03:57:57 PDT
If you want predictable behavior, just specify `focusVisible: false` or `focusVisible: true` inside `element.focus()`. If someone feels like debugging what's going on: https://searchfox.org/wubkat/rev/98733fd3822325456ee066f400c6465b5fc8dd91/Source/WebCore/dom/Element.cpp#4076-4083 is the right place to look. You'll want to see what cases end up being `FocusVisibility::Invisible` and what cases end up being `FocusVisibility::Visible`.
Karl Dubost
Comment 4 2026-04-13 20:23:15 PDT
testing across browsers. https://codepen.io/magiclantern/pen/KKjyWBB/8549ed2ce5fdd141e59a3dae28cbacfb Focus - will show focus outline (Button with a <div> child.) Safari pink outline Firefox no outline Chrome no outline Focus - will not show focus outline (Button without child nodes, only text.) Safari. no outline Firefox. no outline Chrome no outline Focus - will not show focus outline (Button with a <div> child that has pointer-events: none; applied.) Safari. no outline Firefox. no outline Chrome no outline
Karl Dubost
Comment 5 2026-04-13 20:25:47 PDT
The code for the first case. *:focus, *:focus-visible { outline: 0; } <button data-trigger class="px-3 py-2 bg-zinc-900 text-zinc-100 rounded-md focus-visible:ring ring-pink-500 ring-offset-2" type="button"> <div>Focus</div> </button> <button id="target" type="button" class="focus-visible:ring ring-pink-500 ring-offset-2 px-5 py-2 bg-zinc-900 text-zinc-100 rounded-md"> Focus target </button> The JavaScript: document.addEventListener("DOMContentLoaded", () => { const targetEl = document.getElementById("target"); const triggerEls = document.querySelectorAll("[data-trigger]"); for (const triggerEl of triggerEls) { triggerEl.addEventListener("click", (e) => { targetEl.focus(); }); } });
Karl Dubost
Comment 6 2026-04-13 21:34:22 PDT
The bug has another interesting behavior. Once you click the button Focus target, and try to click elsewhere, it is not possible to reproduce the bug anymore until reloading the page.
Karl Dubost
Comment 7 2026-04-13 21:45:40 PDT
Created attachment 479058 [details] testcase
Karl Dubost
Comment 8 2026-04-13 22:10:20 PDT
EWS
Comment 9 2026-04-22 06:45:04 PDT
Committed 311768@main (cde532e2aee6): <https://commits.webkit.org/311768@main> Reviewed commits have been landed. Closing PR #62708 and removing active labels.
Note You need to log in before you can comment on or make changes to this bug.