Quick Launch Click Handling#
Bug (fixed in PR #7105): Quick Launch opened the currently selected (hover-tracked) result instead of the result the user actually clicked or tapped. The bug affected mouse, trackpad, and touchscreen inputs alike.
Root Cause#
The component tracked the "active" result via currentItemIndex state, which was set only by the onMouseEnter handler (handleItemHover). The onClick handler (handleItemClick) then called openCurrentItem, which opened results[activeItemIndex] — the hover-tracked index — not the index of the element that received the click.
On touch devices (and sometimes on mouse), the mouseenter event for the tapped item could fire after the click was processed, so currentItemIndex still pointed to whatever was previously selected (defaulting to index 0 when currentItemIndex was null).
The critical sequence:
activeItemIndexdefaults to0(or the last hover-highlighted item)- User taps result at index
2 handleItemClickfires → callsopenCurrentItem→ readsresults[activeItemIndex]→ opens index0mouseenter/hover update never ran on touch, so the index was never updated
A diagnostic test confirmed the correct <button data-index="2"> received the click event; Homepage still navigated to the wrong result.
The Fix#
PR #7105 resolved the issue by making handleItemClick read the target's own data-index attribute instead of relying on activeItemIndex:
// Before (buggy)
function handleItemClick(event) {
closeAndReset();
openCurrentItem(event.metaKey); // uses state-tracked activeItemIndex
}
// After (fixed)
function handleItemClick(event) {
closeAndReset();
// in case hover doesnt fire, use the clicked item, not the highlighted one
openCurrentItem(event.metaKey, parseInt(event.currentTarget.dataset.index, 10));
}
The fix modified openCurrentItem to accept an optional index parameter (defaulting to activeItemIndex for keyboard navigation), then passed the clicked button's data-index directly from handleItemClick. Every result <button> already carries data-index={i} , so the index is available on the click event without any state dependency.
Workaround (for versions prior to the fix)#
For users on older versions, the reporter published a custom.js patch that dispatches a synthetic mouseover on pointerdown — firing before the click — so currentItemIndex is updated to the correct item before handleItemClick runs :
document.addEventListener(
"pointerdown",
(event) => {
const item = event.target.closest("button[data-index]");
if (!item) return;
item.dispatchEvent(new MouseEvent("mouseover", { bubbles: true, cancelable: true, view: window }));
},
true,
);
Note: The workaround fires
mouseover, notmouseenter. The component listens toonMouseEnter, which React maps to the nativemouseenterevent. React's synthetic event system still triggersonMouseEnteron the direct target when a bubblingmouseoverarrives, so the workaround succeeds in practice.
Key References#
| Reference | Description |
|---|---|
quicklaunch.jsx | Full component source |
handleItemHover (L177–179) | Sets currentItemIndex via mouseenter |
handleItemClick (L181–184) | Bug site: calls openCurrentItem without reading click target |
openCurrentItem (L127–134) | Opens results[activeItemIndex] — the hover-state index |
activeItemIndex (L240) | Defaults to 0 when no hover state is set |
| Discussion #7103 | Bug report with reproduction steps, diagnostic evidence, and workaround |