Skip to content

metadata-admin 检查器的三个共享字段组件把 Label 和控件放在一起但不关联 —— 屏幕阅读器读到的是"无名编辑框",可见标签成了孤立文本 #3994

Description

@yinlianghui

发现于 #3979 的实施过程(围栏外,PR #3993 未夹带 —— #3979 的范围是 block-config.ts 的 placeholder 列)。未认领,交 PM triage。

机制

packages/app-shell/src/views/metadata-admin/inspectors/_shared.tsx 里三个共享字段组件都渲染成"一个 Label + 一个控件"的兄弟结构,Label 没有 htmlFor、控件没有 id,也没有 aria-label 兜底:

  • InspectorTextField —— _shared.tsx:157(Label)/ :158(Input)
  • InspectorNumberField —— _shared.tsx:186 / :187
  • InspectorSelectField —— _shared.tsx:225(Label)/ :231(SelectTrigger)

所以标签与控件之间只有视觉上的邻接,没有可编程的关联。辅助技术拿不到可访问名:焦点落进这些框时读出的是"编辑框",而上面那行中文/英文标签是一段没有归属的文本。同文件的 InspectorCheckboxField(:258)是对的 —— 它用包裹式 <label>,可以作为反例参照。

不是 dormant:这三个组件是 metadata-admin 检查器的通用输入件,16 个非测试文件引用它们(页面块检查器、流程节点、报表、数据集、权限等各检查器),打开任何一个检查器面板即渲染。

机械症状(已经被当作既成事实绕开了)

PageBlockInspector.sectionName.test.tsx:92-98 的注释把这件事写下来当作定位手段的理由:

The section-name boxes, in section order. Located by the placeholder because InspectorTextField renders its <Label> unassociated with the <input> (no htmlFor/id), so getByLabelText cannot reach it

也就是说:测试之所以必须按 placeholder 定位,正是因为可访问名不存在。这是同一个缺陷的可测量形态 —— getByLabelText 读的就是 AT 读的那条链。副作用是它把 placeholder 变成了事实上的定位锚(#3979 处理这一列时因此要格外小心 en 值逐字节不变)。

边界与去重

实施时值得先想清的一点(记录现象,不代人决定)

id 从哪来是个小决定:useId() 生成、还是由调用方传入(检查器里同一个字段名可能在数组项里重复出现,page:tabs.items[i].label 之类)。useId() 更难写错;但若将来要支持"点标签聚焦控件"之外的 aria-describedby(例如 #3912 的校验消息),调用方可见的 id 会更顺。留给实施者论证。

另外值得一并想:修好之后,sectionName 那类测试可以从"按 placeholder 定位"改成 getByLabelText,那才是与 AT 同一条链的断言 —— 但这会牵动若干测试,属该 PR 自己的 fixture 处置面。


Generated by Claude Code

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions