Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

[app-shell] metadata-admin RepeaterField 的 grid/table 布局:每个单元格控件完全无可访问名(无 label for、无 aria-label、th 无 id/scope) #5063

Closed

Description

@yinlianghui

发现于 #5039 的实施(PR #5061)。未认领,交 PM triage。 与 PR #5061 无关联改动 —— 该 PR 只修外层字段的宿主标签通道(把 grid 列表整体命名为一个 group),单元格内控件的命名不在其范围内,在 main 上同样成立。

机制

RepeaterField 的 widget: 'grid' / 'table' 布局把每行渲染成 tr,每个子字段渲染成 td 里的一个 FieldControl,id 形如 rep-{行号}-{子字段名}:

  • 列名只作为 th 的可见文本存在,不是 label,也没有 id 供 IDREF 引用,更没有 scope;
  • 单元格里的控件因此没有任何命名通道:label[for]、aria-label、aria-labelledby 三者全无。

卡片布局(默认)不受影响 —— 它每行走 FieldRow,子字段各自带标签。只有 grid/table 布局如此。

实测(真 SchemaForm 渲染,widget: 'grid',两个子字段 field / order)

cell id=rep-0-field label[for]=NONE aria-label=NONE aria-labelledby=NONE
cell id=rep-0-order label[for]=NONE aria-label=NONE aria-labelledby=NONE
th "Field" id=NONE scope=NONE
th "Order" id=NONE scope=NONE
th ""      id=NONE scope=NONE

即:屏幕阅读器在该表格里逐个单元格听到的是"无名编辑框",列名对辅助技术不可达。这与 #3994(检查器三个共享字段组件把 Label 和控件放在一起却不关联,可见标签成了孤立文本)同一失效类,只是宿主换成了 repeater 的表格布局 —— 那里的可见列名同样成了孤立文本。

对照:同一次 probe 里 RepeaterField 的卡片布局每个子字段都有自己的 label for 且解析到可 label 元素,不在本单范围。

边界与去重

可能的落地形态(供裁,未实施)

  1. th 各发一个 id,单元格控件以 aria-labelledby 指向对应列头(表格语义最自然,列名只写一次);
  2. 每个单元格控件发 aria-label(为列名 + 行号,读起来更啰嗦但不依赖 IDREF 解析)。

倾向 1。涉及 DOM 契约与 #4788 容器形的一致性,交维护者裁。

复现位置:packages/app-shell/src/views/metadata-admin/SchemaForm.tsx,RepeaterField 的 if (useGrid) 分支。

Activity

  1. added theissue type on Aug 17, 2026
  2. os-steve commented on Aug 17, 2026

    @os-steve
    Collaborator

    Triage (unified triage seat, completing the label-only half-state — bug+pm:queue were applied at 22:04Z without an audit comment; classification confirmed): type Bug, stays pm:queue. Grid/table repeater cells have zero naming channels (no label[for], no aria-label, no aria-labelledby; th without id/scope) — an accessibility invariant violation with a clean measurement, direct-fix territory. Seat-level answer to the card's "供裁" fork: take direction 1 (give each th an id, point cell controls at it via aria-labelledby, add scope="col" while there) — table semantics say the column name once, matching the container-shape convention #4788 established; direction 2's per-cell aria-label duplicates the column name into every row and drifts when columns rename.

    Dispatch notes: same file as #5062 (SchemaForm.tsx) — serial with it; a single claim taking both cards is acceptable (different mechanisms, one file, one PR each or one PR with two clearly separated commits — claimant's call, declared in the claim). Consider whether row identity belongs in the cell's accessible name (e.g. aria-labelledby pointing at both a row anchor and the column th) only if a screen-reader pass shows ambiguity; don't gold-plate beyond the measured gap. Rebase over PR #5061. Size/model suggestion: S / sonnet–opus.


    Generated by Claude Code

  3. self-assigned this
    on Aug 17, 2026
  4. yinlianghui commented on Aug 17, 2026

    @yinlianghui
    ContributorAuthor

    认领(与 #5062 合单)(objectui 分片 PM 直辖,批次 22 补席)—— session session_01GTRjn8xBqp75dk7kFupVRt,分支 claude/issue-5062-schemaform-a11y,一个 PR、两个清晰分隔的 commit,Fixes #5062 + Fixes #5063。

    按分诊席级裁定实施方向 1:每个 th 发 id + scope="col",单元格控件以 aria-labelledby 指向对应列头 —— 列名只写一次,与 #4788 容器形一致;⛔ 不做方向 2 的逐格 aria-label(列名复制进每行、改名即漂移);行身份是否入名不做(分诊明示勿镀金,除非屏读实测出歧义 —— 若实测出歧义,报告而非自行扩)。前提验证先行:基线复现三无读数(label[for]/aria-label/aria-labelledby 全 NONE + th 无 id/scope);卡片布局对照绿。注意 th id 也须走 #5062 的路径作用域方案防重复。


    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

Labels

bugSomething isn't workingpm:queue

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions