Fixes #20077: Fix form field focus bug on Edge #171

Closed
opened 2026-04-05 16:22:39 +02:00 by MrUnknownDE · 0 comments
Owner

Originally created by @jeremystretch on 3/11/2026

Fixes: #20077

Root cause: TomSelect's open() method calls focus(), which:

  1. Synchronously calls control_input.focus() (moving browser focus to this instance)
  2. Schedules setTimeout(() => { ignoreFocus = false; onFocus(); }, 0)

When Edge's autofill rapidly focuses multiple inputs, the sequence becomes a ping-pong loop:

  • Edge focuses select1 → open() → focus() → control_input.focus() → setTimeout A
  • Edge focuses select2 → select1 gets onBlur() → select1 closes (isOpen=false)
  • setTimeout A fires → select1 calls onFocus() → open() (since isOpen=false again!) → focus() → steals focus back from select2
  • select2 closes → select2's pending setTimeout fires → steals focus back from select1 → infinite loop

Changes:

  • New file netboxTomSelect.ts: NetBoxTomSelect extends TomSelect with the patched focus()
  • dynamicTomSelect.ts: DynamicTomSelect now extends NetBoxTomSelect instead of TomSelect
  • static.ts: initStaticSelects() and initColorSelects() use NetBoxTomSelect instead of TomSelect (static selects with pre-loaded options are equally susceptible to the loop)

I've verified that this addresses the problematic behavior using the Edge browser.

*Originally created by @jeremystretch on 3/11/2026* ### Fixes: #20077 Root cause: TomSelect's open() method calls focus(), which: 1. Synchronously calls `control_input.focus()` (moving browser focus to this instance) 2. Schedules `setTimeout(() => { ignoreFocus = false; onFocus(); }, 0)` When Edge's autofill rapidly focuses multiple inputs, the sequence becomes a ping-pong loop: - Edge focuses select1 → open() → focus() → control_input.focus() → setTimeout A - Edge focuses select2 → select1 gets onBlur() → select1 closes (isOpen=false) - setTimeout A fires → select1 calls onFocus() → open() (since isOpen=false again!) → focus() → steals focus back from select2 - select2 closes → select2's pending setTimeout fires → steals focus back from select1 → infinite loop Changes: - New file `netboxTomSelect.ts`: NetBoxTomSelect extends TomSelect with the patched `focus()` - `dynamicTomSelect.ts`: DynamicTomSelect now extends NetBoxTomSelect instead of TomSelect - `static.ts`: `initStaticSelects()` and `initColorSelects()` use NetBoxTomSelect instead of TomSelect (static selects with pre-loaded options are equally susceptible to the loop) I've verified that this addresses the problematic behavior using the Edge browser.
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github/netbox#171