You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[fields] a boolean field's visible form label is associated with nothing — BooleanField overrides the control id with the field name, so the form's label for dangles #3952
Found while browser-verifying #3910 (docs field examples moved to form hosting). Out of that card's scope — pre-existing and independent of the hosting change, so filed rather than fixed.
What happens
Render any boolean field inside a form ({ type: 'form', fields: [{ name: 'notifications', label: 'Email Notifications', type: 'boolean' }] }) and the form emits two labels carrying the same text, of which the visible one points at an element that does not exist:
labels = [
{ for: "_r_3_-form-item", text: "Email Notifications", srOnly: false }, <-- visible
{ for: "notifications", text: "Email Notifications", srOnly: true } <-- widget's own
]
switch id = "notifications" role=switch
all ids in form = ["notifications"]
label for="_r_3_-form-item" -> target exists? false
label for="notifications" -> target exists? true
Cause
packages/components/src/renderers/form/form.tsx renders its FormLabel with the for that FormItem/FormControl generate (the _r_N_-form-item id). But packages/fields/src/widgets/BooleanField.tsx:16-17 replaces the control's id with the field name:
and then puts that id on the Switch/Checkbox (:30, :44) with its own sr-only label pointing at it (:35, :49). So the id the form told the control to use is discarded, the form's visible label references a now-nonexistent id, and the widget supplies a second, duplicate label.
Impact
Clicking the visible label does not toggle the switch — the normal affordance for a checkbox/switch row is dead. This is every boolean/checkbox field on every generated form in every app, not a docs-only artifact.
The accessible name survives only because the widget's sr-only label happens to be correctly wired; the form's own label contributes nothing. Any future change that drops the widget's internal label would silently leave the switch unnamed.
Duplicate label text in the DOM is also why a naive getByText(label) on a boolean field returns two nodes.
Only the widgets that override the id are affected. Text/number/etc. leave FormControl's id alone and their visible label works.
Suggested direction (not decided here)
The host should own the control id: BooleanField should use the id handed to it (the id prop the form's FormControl supplies) and fall back to useId()/name only when standalone — and then its internal sr-only label is redundant inside a form and should not be emitted twice. Worth checking the other widgets for the same id override while in there.
Reproduce
render(<SchemaRendererschema={{type: 'form',showSubmit: false,showCancel: false,fields: [{name: 'notifications',label: 'Email Notifications',type: 'boolean'}]}}/>);// then compare every label's `for` against the ids present in the form
Confirmed in jsdom and in a real browser on /docs/fields/boolean (all three demos).
Activity
yinlianghui commentedon Aug 9, 2026
PM 分诊(session_01GTRjn8xBqp75dk7kFupVRt):晋级
pm:queue—— 明确 bug 且方向清晰(host 拥有控件 id,BooleanField应使用FormControl下发的 id,独立渲染时才回退useId()/name),影响所有生成表单的 boolean/checkbox 字段(可见 label 点击失效),jsdom 与真实浏览器双重实证在册。修复时按正文建议顺带排查其它覆写 id 的 widget。Generated by Claude Code
yinlianghui commentedon Aug 9, 2026
🔒 认领(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt,恢复批次 4)
claude/issue-3952-boolean-label-forfor指向存在的 id + 点击可见 label 切换开关)。packages/fields/src/widgets/*(基于已含 PR refactor(fields)!: 文档字段例子改表单托管,删 registerFields + createFieldRenderer (#3910) #3953 的 main 切分支,无同包在飞)。Generated by Claude Code
fix(fields): BooleanField 使用 host 下发的控件 id,可见 label 不再悬空 (objectstack…
fix(app-shell): ActionParamDialog 的 boolean 分支下发控件 id,可访问名不再是两份 label…