Skip to content

[components] 表单渲染器内建 select 分支把 host id 展开到 Radix Select.Root —— 手写 form schema 里 type: 'select' 的 label for 全部悬空(#3306 的内建侧同形) #3976

Description

@yinlianghui

实施 #3961 时把该单的 probe 扩到 18 个字段类型跑了一遍(probe 未提交),select 的一行与 #3961 正文实测表相反 —— 正文把 select 列为阳性对照「解析成功(button)」,实测是 MISSING。追下去发现两条 select 路径的行为不同,悬空的是内建分支,与 #3961 无关,故单独立单。

实测

select   for=…-form-item   ownId=(none) -> MISSING   byLabelText=0()   byRole+name=[]

即:表单里一个 { name: 'status', label: 'Status', type: 'select', options: [...] },可见的「Status」标签指向一个没有任何元素携带的 id。点它什么都不会发生,且这个标签完全不在可访问性树里。

成因

packages/components/src/renderers/form/form.tsx 的 case 'select' 把剩余 DOM props(含 FormControl 的 Slot 注入的 id)展开到 Radix 的 Select 根组件上。Select.Root 不是 DOM 宿主,它静默丢弃不认识的 prop —— 这正是 #3306 记录过的失效机制,只不过 #3306 修的是 widget 侧(SelectField 现在把 pass-through 落到 SelectTrigger,一个真 button,所以 field:select 这条路径是好的)。内建分支从没跟着改。

两条路径为什么会分叉,以及为什么阳性对照会读错:BUILTIN_FIELD_TYPES 含 'select',renderFieldComponent 对内建类型根本不查注册表 —— 于是

  • 对象驱动的表单(mapFieldTypeToFormType 发 field:select)走注册 widget,for 落在 SelectTrigger 上,正常;
  • 手写 form schema 的裸 type: 'select' 走内建分支,for 悬空。

实测时注册表里确实存在 field:select,内建分支依然胜出,这一点是直接测到的,不是推断。

影响面

任何手写 { type: 'select' } 的 form schema:标签点不动,屏幕阅读器读不到字段名。与之相邻但不同的事实是 aria 状态通道 —— 同一个展开点也在丢 aria-describedby / aria-invalid / aria-required(#3306 在 widget 侧修掉的正是这些),所以这一个展开点同时欠着「名字」和「状态」两笔。

修法方向(未裁决,不在本单预设)

内建分支需要把 id / aria-* 落到 SelectTrigger 而不是 Select 根上,与 #3306 在 widget 侧的处置对齐。是否更该走「删掉内建 select 分支、让裸 select 也解析到注册 widget」这条路(一个控件一个实现,而不是两份行为要各自维护)属于设计裁决,交 PM/维护者定 —— 两条路径长期并存本身就是这个 bug 的成因。

参考

Activity

  1. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    CollaboratorAuthor

    PM 分诊(session_01GTRjn8xBqp75dk7kFupVRt):晋级 pm:queue —— 内建 select 分支把 host id 展开到 Radix Select.Root(非 DOM 宿主静默丢弃),裸 type: 'select' 的 label for 悬空且 aria-describedby/invalid/required 同丢(#3306 的内建侧同形)。本单实测同时修正了 #3961 正文与 #3952 报告把 select 列为阳性对照的误读(那是 field:select 注册 widget 路径,内建路径是另一条)—— 双路径分叉的辨析有价值,派发词将引用。面:packages/components/src/renderers/form/form.tsx 内建 select 分支 —— 与 PR3978 同文件,串行:PR3978 合入后再派。


    Generated by Claude Code

  2. self-assigned this
    on Aug 9, 2026
  3. yinlianghui commented on Aug 9, 2026

    @yinlianghui
    CollaboratorAuthor

    🔒 认领(objectui 分片 PM,session_01GTRjn8xBqp75dk7kFupVRt,批次 5):同文件串行前置 PR #3978 已落 main。


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions