Fix GlOutsideDirective closing dropdowns on mousedown in Safari
Summary
This MR fixes issue gitlab-org/gitlab#605177 (closed)
Safari doesn't focus <button> elements (and similar non-text controls) on click — it's a
long-standing, deliberate WebKit behavior. Instead of focusing the clicked button, Safari blurs
whatever was previously focused.
This breaks any GlOutsideDirective-based dropdown/popover that has a focused element inside it
(e.g. a searchable listbox's search input) and also contains a <button> action, such as a
"Clear"/reset button:
- User opens the dropdown; the search input is focused.
- User clicks the "Clear" button inside the dropdown.
- On
mousedown, Safari blurs the search input without focusing the button, moving focus to<body>instead. - That fires a native
focusintargeting<body>, which is outside the dropdown's bound element, soGlOutsideDirective's capture-phasefocusinlistener treats it as an outside interaction and closes the dropdown immediately — before the subsequentclickevent ever reaches the button. - The button is now gone from the DOM, so its
@clickhandler never runs.
Chrome and Firefox don't hit this because they do focus the button on click, so the resulting
focusin targets an element inside the dropdown and is correctly ignored.
Fix
GlOutsideDirective already had a mousedown-based fallback for click events, to handle text
selection ending outside the element it started in. This MR extends that same fallback to
focusin events: if a focusin follows a mousedown that started inside the bound element, it's
treated as an inside interaction, regardless of where the browser decided to move focus.
Also tightened the mousedown listener bookkeeping (now tracked via activeEventTypes) so it's
only ever attached/detached once, since it's now shared between the click and focusin paths
instead of being tied only to click.
Screenshots
| before | after |
|---|---|