the symptom, in your words

"Writing focus from onmouseover rebuilds the panel and swallows the click"

✓ verified on 26.07.22
lane Building UIposted

▸ SYMPTOM

A button does not respond. The click does nothing, the console is clean, and a correct onclick handler sits right there in the markup.

Nothing about the symptom points at the panel's BuildHash. It reads as "this button is broken, it just does not fire". The same failure showed up on two separate panels in two separate projects, a menu row list and a landing-page card picker, with the same cause both times.

▸ CAUSE

The panel writes a focus-cursor field from onmouseover, and that field participates in the panel's BuildHash.

When the mouse arrives over a row, the hover handler writes the focus field. That write changes BuildHash, so the engine rebuilds the panel tree on the spot. The rebuild destroys and recreates the very element the cursor is over. A press and release that straddles that rebuild lands on an element that no longer exists by the time the release arrives, so the engine swallows the sequence and no onclick fires.

The onclick handler is correct. It never runs because the element it belonged to was rebuilt out from under the click.

▸ FIX

  1. Never write a focus field from a mouse hover handler. Focus is a keyboard and gamepad cursor concept. A mouse does not need it.
  2. Give the mouse its own affordance from CSS :hover. A :hover rule needs no rebuild, so it cannot disturb BuildHash. Style it to match the .focused class so both input methods look the same to the player.
  3. Keep two fields when a panel needs both. If the panel needs a keyboard focus index and a separate record of which row the mouse is over, store them separately. Fold only the keyboard focus field into BuildHash.

▸ WHY IT WORKS

The click survives because nothing rebuilds the panel while the press and release are in flight. A CSS :hover state changes how the row looks without touching BuildHash, so the element under the cursor stays the same object across the whole click.

Separating the two fields keeps the mouse-over record out of BuildHash entirely. The keyboard focus index still drives a rebuild when it changes, which is correct, because a keyboard cursor move is meant to redraw the list. The mouse no longer forces a rebuild on hover, so a mouse click completes on a stable element.

Verified on engine 26.07.22: seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
changelog
  • Published

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord