v144 · user input · demo

Hover Menu

A real-world nav dropdown: hovering a trigger appends a <ul> to the DOM; moving away removes it entirely. Chrome 144 ensures pointerleave fires on the correct ancestor even when the dropdown vanishes mid-hover — watch the event log below to see boundary events flowing in the right order.

Boundary events now fire on nearest attached ancestor (Chrome 144+)

Show:
timetypetargetrelatedTarget
  1. Hover a menu item to see events…

what Chrome 144 fixes

Prior to Chrome 144, removing a child element from the DOM mid-hover could swallow or misroute pointerleave events. In a conditional-render dropdown pattern the dropdown is appended on hover and removed on leave — exactly the sequence that triggered the bug. After Chrome 144, the browser re-evaluates the hover chain after each DOM mutation and dispatches boundary events to the correct nearest still-attached ancestor, matching Safari and Firefox.

the pattern

// trigger: insert dropdown into DOM on hover
trigger.addEventListener('pointerenter', () => {
  const ul = buildDropdown(items);
  menuItem.appendChild(ul);
  dropdownEl = ul;
});

// trigger: schedule removal on leave
trigger.addEventListener('pointerleave', () => {
  removeTimer = setTimeout(maybeRemove, 50);
});

// dropdown: cancel removal while inside
dropdown.addEventListener('pointerenter', () => {
  clearTimeout(removeTimer);
});

// dropdown: schedule removal when leaving it too
dropdown.addEventListener('pointerleave', () => {
  removeTimer = setTimeout(maybeRemove, 50);
});

// Chrome 144: pointerleave fires on .menu-item even
// after the dropdown child is removed from the DOM.

see also