Form builder: renaming a field swallows the next click in its row (id-keyed each-block remounts the row on blur) #84

Open
opened 2026-08-03 20:07:59 +00:00 by laoc · 0 comments
Owner

Symptom

In the form builder (/forms/new): rename a field, then click anything in that row — the option input, the Required checkbox, a chip's × — and the first click is silently swallowed. Typed text after clicking the option input goes nowhere (document.activeElement is BODY); a second identical click works.

Found and measured by TestOER while verifying PR #80 in real Chrome (their probe's positive control failed, not its subject), at human timing — click, wait 600 ms, type at 40 ms/key — so this is not an automation-speed artifact.

after renaming a field, then… result control (no rename)
click the option input, pause, type activeElement is BODY, every keystroke lost, no chip focus held, text lands, chip commits
click Required checkbox stays unchecked; 2nd click works
click a chip's × chip not deleted; 2nd click works

Mechanism (measured, then read — cites verified at dev = 65a16f1b)

  1. The label input's onchange (which fires on blur) regenerates field.id when !existingsrc/lib/components/forms/FormBuilderFieldRow.svelte:289-294.
  2. FormBuilder.svelte keys its each-block on (field.id + '-' + i)src/lib/components/forms/FormBuilder.svelte:514.
  3. So leaving the label input destroys and recreates the whole row. The mousedown that caused the blur lands on a DOM node that is unmounted mid-gesture; the click never reaches the recreated row.

Scope and attribution

  • Pre-existing on dev — reproduced byte-for-byte at the dev baseline (also at 2e5237f9 on the PR #80 branch with identical numbers), so it is independent of the current form-builder PR stack. It does not block #80.
  • From the !existing guard this should affect /forms/new only, not editing a published form — that part is a code read; the edit route was not driven.
  • Same failure family as the bug #80 fixes (user input silently lost), arguably worse: rename a field, click the next control, nothing happens.

Repro probes

TestOER wrote two failing real-Chrome probes (option-remount.test.js, option-remount-clicks.test.js, drop-in for e2e/ — each with an in-run no-rename positive control). They are deliberately NOT on any branch since they fail by design; they will ride the fix PR as its red-first tests.

Fix direction (not started)

The row identity should not change on rename: either key the each-block on a stable per-row identity (not the regenerated field.id), or stop regenerating field.id on blur (generate once on creation, or only until first blur). Needs a decision on whether field.id stability after publish matters to anything downstream (it becomes the question id in responses).

Discussion: Buzz #edufeed-app, EKKW thread, TestOER's report of 2026-08-03 20:04Z.

## Symptom In the form builder (`/forms/new`): rename a field, then click anything in that row — the option input, the Required checkbox, a chip's × — and **the first click is silently swallowed**. Typed text after clicking the option input goes nowhere (`document.activeElement` is `BODY`); a second identical click works. Found and measured by TestOER while verifying PR #80 in real Chrome (their probe's positive control failed, not its subject), at **human timing** — click, wait 600 ms, type at 40 ms/key — so this is not an automation-speed artifact. | after renaming a field, then… | result | control (no rename) | |---|---|---| | click the option input, pause, type | `activeElement` is BODY, every keystroke lost, no chip | focus held, text lands, chip commits | | click Required | checkbox stays unchecked; 2nd click works | — | | click a chip's × | chip not deleted; 2nd click works | — | ## Mechanism (measured, then read — cites verified at `dev` = `65a16f1b`) 1. The label input's `onchange` (which fires on **blur**) regenerates `field.id` when `!existing` — `src/lib/components/forms/FormBuilderFieldRow.svelte:289-294`. 2. `FormBuilder.svelte` keys its each-block on `(field.id + '-' + i)` — `src/lib/components/forms/FormBuilder.svelte:514`. 3. So leaving the label input **destroys and recreates the whole row**. The mousedown that caused the blur lands on a DOM node that is unmounted mid-gesture; the click never reaches the recreated row. ## Scope and attribution - **Pre-existing on `dev`** — reproduced byte-for-byte at the dev baseline (also at `2e5237f9` on the PR #80 branch with identical numbers), so it is independent of the current form-builder PR stack. It does **not** block #80. - From the `!existing` guard this should affect `/forms/new` only, not editing a published form — that part is a code read; the edit route was not driven. - Same failure family as the bug #80 fixes (user input silently lost), arguably worse: rename a field, click the next control, nothing happens. ## Repro probes TestOER wrote two failing real-Chrome probes (`option-remount.test.js`, `option-remount-clicks.test.js`, drop-in for `e2e/` — each with an in-run no-rename positive control). They are deliberately NOT on any branch since they fail by design; they will ride the fix PR as its red-first tests. ## Fix direction (not started) The row identity should not change on rename: either key the each-block on a stable per-row identity (not the regenerated `field.id`), or stop regenerating `field.id` on blur (generate once on creation, or only until first blur). Needs a decision on whether `field.id` stability after publish matters to anything downstream (it becomes the question id in responses). Discussion: Buzz #edufeed-app, EKKW thread, TestOER's report of 2026-08-03 20:04Z.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
edufeed/edufeed-app#84
No description provided.