ENG-1719: label[for=""] Must Not Match input[id=""]

Bug (ENG-1719): When a <label for=""> and an <input id=""> both had empty string values, the explicit for/id comparison (for === id) was true because "" === "". This caused every label[for=""] on the page to associate with every input[id=""], producing a spurious concatenated accessible name.

Impact: Test 374 violations (missing accessible name on radio) were hidden because the engine reported a (wrong) accessible name instead of no name.

Test Logic:

Common Scenario:

Fix (AccName.js): Added node.id && guard before the for/id comparison:

(node.id && labels[i].getAttribute("for") === node.id)

When node.id is "" (falsy), the comparison short-circuits and no explicit association is made.
Input with id=""
Label with for=""
Valid explicit for/id association

N/A Tests — Not Affected by This Fix

Radio without id attribute at all (attribute absent) — id="na-radio-no-id"

No empty id involved — fix irrelevant. aria-label provides name so Test 374 does not fire. Should not be flagged.

Hidden radio with id="" (display:none) — id="", excluded by visibility

Hidden element — data-ae_vis absent, excluded from all tests. Should not be flagged.

Checkbox with id="" — same fix, different test rule — id=""

Fix blocks label[for=""] matching checkbox[id=""]. aria-label provides name so checkbox accessible-name test does not fire. Should not be flagged.

PASS Tests — Correct Behavior

Radio with id="" and sibling label[for=""] — no accessible name assigned — all id=""

Color Swatch (broken markup — all ids empty)

AFTER FIX: No accessible name from labels. Test 374 correctly fires on all three. Should be flagged.

Radio with valid id + label[for] — still named correctly (regression)

Size (valid markup)

Valid non-empty for/id pairs still associate correctly. No regression from the fix.

Radio wrapped in <label> (implicit association) — id="plan-monthly", id="plan-annual"

Subscription Plan

Implicit label unaffected by fix. Accessible names: "Monthly", "Annual". Should not be flagged.

Mix: one radio with valid id, one with empty id — id="good-option" (named) / id="" (no name)

Mixed Quality Markup

id="good-option": accessible name "Good option" — should not be flagged. id="": no name — should be flagged.

Radio with id="" alongside unrelated label[for=""] — search id="" / radios id=""

Search field (unrelated to radio group):


Radio Group

Search: aria-label provides name — should not be flagged. Radios: no name after fix — should be flagged. No cross-contamination from the search label.

Bug Reproduction — Pre-Fix Behavior

What the engine used to do: 3 radios + 3 labels, all with empty id/for — all id="", should be flagged

Pre-fix, each radio would receive an accessible name of "Whitewash Chambray North Pole" (all label texts concatenated). The engine treated every label[for=""] as associated with every input[id=""] on the page.

Color (broken empty-id markup)

Pre-fix accessible name (each radio): "Whitewash Chambray North Pole"
Post-fix accessible name (each radio): null ✓ (Test 374 correctly fires)

Cross-element contamination scenario — id="real-id" should not be flagged / id="" should be flagged

Pre-fix: the radio below would inherit "Pick me" as its accessible name from the unrelated label above it, because both use empty id/for.


Pre-fix: second radio accessible name = "Pick me Should not bleed" (all empty-for labels) ❌
Post-fix: second radio accessible name = null

Real World Examples

FAIL: E-commerce color swatch picker — all id="", should be flagged

Product: Classic T-Shirt

Select Color
Whitewash
Chambray
North Pole
Pewter

Accessible name: null (no name on any radio). Test 374 fires — radios need accessible names. Developer fix: add unique id per radio + matching for on label, OR wrap each input in its label.

PASS: Same swatch picker correctly implemented — id="color-white/blue/offwhite/gray", should not be flagged

Product: Classic T-Shirt

Select Color

Each radio wrapped in its label — implicit association. Accessible names: "Whitewash", "Chambray", "North Pole", "Pewter". Test 374 passes.

FAIL: CMS-generated form — all id="", should be flagged

Newsletter Frequency

CMS template emits id="" as placeholder. Pre-fix: each radio got "Daily Weekly Monthly" as name (hiding the bug). Post-fix: no name — Test 374 fires, exposing the real problem. Developer must fix the CMS template to emit unique IDs.

PASS: Survey — id="rate-1/rate-2/rate-3", should not be flagged

Rate your experience

All radios have unique, non-empty ids. Explicit for/id associations work correctly. Accessible names: "1 — Poor", "2 — Fair", "3 — Good".