demo · v143

Onerror-style handoff

The reason this exists: window.ongamepadconnected = fn now matches every other window event handler attribute (onresize, onerror, onbeforeunload…). The old addEventListener route still works — only one handler can win on the attribute slot.

support probe

two registration styles, head-to-head

old: addEventListener (multiple handlers ok)

window.addEventListener(
  "gamepadconnected",
  (e) => log("listener A", e.gamepad.id)
);
window.addEventListener(
  "gamepadconnected",
  (e) => log("listener B", e.gamepad.id)
);

v143: handler attribute (single slot)

window.ongamepadconnected =
  (e) => log("attr v1", e.gamepad.id);

// reassign — replaces v1
window.ongamepadconnected =
  (e) => log("attr v2", e.gamepad.id);

event log

Plug in a real gamepad and press any button to see both addEventListener handlers fire; only the latest attribute assignment fires (last-write-wins).

the call

// Now valid in v143 (matches onresize, onerror, etc.)
window.ongamepadconnected = (e) => console.log("connected", e.gamepad.id);
window.ongamepaddisconnected = (e) => console.log("gone", e.gamepad.id);

// Or via attribute in markup
<body ongamepadconnected="handle(event)">

why this angle

The other concept shows the handler firing. This one contrasts the two registration mechanisms head-to-head — the spec change isn't about gamepads, it's about API symmetry. Showing why both exist (multi-listener vs single-slot) is the real story.

see also