Jenkins and plugins versions report
Pre-existing on current master (verified at master 063b6a7, Jenkins 2.568+); present in recent weeklies/LTS that ship the tippy.js-based dropdowns (src/main/js/components/dropdowns, tippy.js 6.3.7). Not introduced by #26884 (that PR only changed the tippy appendTo target; this race exists regardless of where the popper is appended). Client-side / web-UI only; no plugins required to reproduce.
What Operating System are you using (both controller, and any agents involved in the problem)?
Controller OS is irrelevant (client-side). Reproduces in any modern browser on a touch-capable input: a laptop touchpad with tap-to-click, a touchscreen, or browser DevTools touch emulation. A conventional mouse does not reproduce.
Reproduction steps
- Open
/newJob (New Item). Choose "Copy existing item" / "Duplicate existing" and focus the "Copy from" field (an INPUT.auto-complete). Type a prefix so multiple suggestions appear. (The INPUT.combobox2 field at /project-relationship behaves identically.)
- Using a touchpad tap or touchscreen tap (not a physical mouse button, not the keyboard), single-tap one of the suggestions.
Expected Results
A single tap selects the suggestion and fills the field, identical to a single mouse click or pressing Enter on a keyboard-highlighted item.
Actual Results
The first tap dismisses the suggestion list without selecting anything; a second tap is required to select. A single mouse click and keyboard Enter both work on the first interaction.
Anything else?
Root cause, verified against the source:
The input registers a focusout handler that hides the dropdown on a fixed 200 ms timer:
src/main/js/components/dropdowns/autocomplete.js:103-105
// otherwise menu won't hide on tab with nothing selected
// needs delay as without that it blocks click selection of an item
e.addEventListener("focusout", () =>
setTimeout(() => e.dropdown && e.dropdown.hide(), 200),
);
src/main/js/components/dropdowns/combo-box.js:81-83 has the same pattern.
A dropdown item's selection is wired only to the click event (no mousedown/pointerdown/touchend listener): src/main/js/components/dropdowns/templates.js:247 (element.addEventListener("click", opt.onClick)), where opt.onClick is the confirm() closure (autocomplete.js:14-20, combo-box.js:6-10).
Event sequence on a touch tap:
- Tap fires
touchstart/touchend; focus leaves the input, so focusout schedules dropdown.hide() at now + 200 ms.
- The browser synthesizes
mousedown/mouseup/click only after the platform's synthetic-click latency (~300 ms; on touchpads similarly > 200 ms).
- At ~200 ms the timer fires
tippy.hide(), which synchronously sets the popper to visibility: hidden (and unmounts it ~250 ms later via animation: "dropdown", duration: 250, templates.js:38-39).
- At ~300 ms the synthesized
click arrives, but the item is already hidden/unmounted, so the click listener (templates.js:247, which runs confirm()) never fires. The first tap is lost; the second tap (field re-focused, list re-shown) selects.
Why mouse works: mousedown and click fire essentially synchronously (under 200 ms), so confirm() runs before the timer (the in-code comment notes the delay exists "as without that it blocks click selection of an item").
Why keyboard works: src/main/js/util/keyboard.js:71-74 calls selectedItem.click() directly on Enter, which is synchronous, with no pointer hit-testing and no focusout.
Not a tippy issue: the popper is interactive: true (templates.js:29), so tippy's own onDocumentPress is exempt for presses inside the popper; the decisive teardown is the app-level 200 ms focusout timer, which is simply shorter than the platform's synthetic-click delay.
Affects both INPUT.auto-complete and INPUT.combobox2. No automated coverage: test/src/test/java/lib/form/ComboBoxTest.java is HtmlUnit-based and cannot synthesize touch-to-mouse timing, so this must be verified manually on a touch device.
Are you interested in contributing a fix?
Yes. A fix should distinguish focus leaving the field entirely (Tab/blur, which should hide) from focus leaving into a tap on a suggestion (which must not pre-empt the click), for example by selecting on pointerdown/mousedown, or by cancelling the pending hide when a tap lands on an item.
Jenkins and plugins versions report
Pre-existing on current
master(verified at master063b6a7, Jenkins 2.568+); present in recent weeklies/LTS that ship the tippy.js-based dropdowns (src/main/js/components/dropdowns, tippy.js 6.3.7). Not introduced by #26884 (that PR only changed the tippyappendTotarget; this race exists regardless of where the popper is appended). Client-side / web-UI only; no plugins required to reproduce.What Operating System are you using (both controller, and any agents involved in the problem)?
Controller OS is irrelevant (client-side). Reproduces in any modern browser on a touch-capable input: a laptop touchpad with tap-to-click, a touchscreen, or browser DevTools touch emulation. A conventional mouse does not reproduce.
Reproduction steps
/newJob(New Item). Choose "Copy existing item" / "Duplicate existing" and focus the "Copy from" field (anINPUT.auto-complete). Type a prefix so multiple suggestions appear. (TheINPUT.combobox2field at/project-relationshipbehaves identically.)Expected Results
A single tap selects the suggestion and fills the field, identical to a single mouse click or pressing Enter on a keyboard-highlighted item.
Actual Results
The first tap dismisses the suggestion list without selecting anything; a second tap is required to select. A single mouse click and keyboard Enter both work on the first interaction.
Anything else?
Root cause, verified against the source:
The input registers a
focusouthandler that hides the dropdown on a fixed 200 ms timer:src/main/js/components/dropdowns/autocomplete.js:103-105src/main/js/components/dropdowns/combo-box.js:81-83has the same pattern.A dropdown item's selection is wired only to the
clickevent (nomousedown/pointerdown/touchendlistener):src/main/js/components/dropdowns/templates.js:247(element.addEventListener("click", opt.onClick)), whereopt.onClickis theconfirm()closure (autocomplete.js:14-20,combo-box.js:6-10).Event sequence on a touch tap:
touchstart/touchend; focus leaves the input, sofocusoutschedulesdropdown.hide()at now + 200 ms.mousedown/mouseup/clickonly after the platform's synthetic-click latency (~300 ms; on touchpads similarly > 200 ms).tippy.hide(), which synchronously sets the popper tovisibility: hidden(and unmounts it ~250 ms later viaanimation: "dropdown",duration: 250,templates.js:38-39).clickarrives, but the item is already hidden/unmounted, so theclicklistener (templates.js:247, which runsconfirm()) never fires. The first tap is lost; the second tap (field re-focused, list re-shown) selects.Why mouse works:
mousedownandclickfire essentially synchronously (under 200 ms), soconfirm()runs before the timer (the in-code comment notes the delay exists "as without that it blocks click selection of an item").Why keyboard works:
src/main/js/util/keyboard.js:71-74callsselectedItem.click()directly on Enter, which is synchronous, with no pointer hit-testing and nofocusout.Not a tippy issue: the popper is
interactive: true(templates.js:29), so tippy's ownonDocumentPressis exempt for presses inside the popper; the decisive teardown is the app-level 200 msfocusouttimer, which is simply shorter than the platform's synthetic-click delay.Affects both
INPUT.auto-completeandINPUT.combobox2. No automated coverage:test/src/test/java/lib/form/ComboBoxTest.javais HtmlUnit-based and cannot synthesize touch-to-mouse timing, so this must be verified manually on a touch device.Are you interested in contributing a fix?
Yes. A fix should distinguish focus leaving the field entirely (Tab/blur, which should hide) from focus leaving into a tap on a suggestion (which must not pre-empt the click), for example by selecting on
pointerdown/mousedown, or by cancelling the pending hide when a tap lands on an item.