实施 #3381(PR #3410,给 Link 页签搜索框补真 label)时,在**同一文件**里核到的相邻缺陷。#3381 的范围栅栏只覆盖搜索框的可访问名,不在该 PR 内修,单独立此单。 同族第四例,但类别又不同:#3299 是「required 状态没进 a11y 树」;#3341 是「label 存在但没关联上」;#3381 是「输入框根本没有 label」;本单是「**按钮完全没有可访问名**」——一个纯图标按钮,连兜底都没有(placeholder 至少还能在真实浏览器里兜一下,图标按钮连这个都没有)。 ## 现象 `packages/plugin-detail/src/InlineCreateRelated.tsx`,卡片头部的关闭按钮(origin/main 2409e1d04 上约 L189-L196,PR #3410 之后行号不变): ``` Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => setIsOpen(false)} X className="h-3.5 w-3.5" / /Button ``` (为避开 GitHub 正文的标签清洗,上面省略了尖括号。) 该按钮**没有文本子节点,也没有 `aria-label` / `aria-labelledby` / `title`**。唯一的子节点是 lucide 的 `X` 图标,而 lucide-react 1.25.0 对「无 children 且无 a11y prop」的图标**默认加 `aria-hidden="true"`**(`dist/cjs/lucide-react.js:92`:`...!children && !hasA11yProp(rest) && { "aria-hidden": "true" }`)。图标被排除出 a11y 树之后,按钮的可访问名没有任何来源,计算结果是**空串**。 屏幕阅读器用户听到的是一个「按钮」,没有名字;这也是 WCAG 4.1.2 / 2.4.6 的直接违反项。 ## 复核方式(在 PR #3410 的 worktree 里实测) 临时探针断言「卡片展开后不存在无文本内容的按钮」: ``` const iconOnly = screen.getAllByRole('button').filter((b) => !b.textContent?.trim()); expect(iconOnly).toHaveLength(0); ``` 结果: ``` AssertionError: expected [ button …(1) ] to have a length of +0 but got 1 ``` 即展开态里恰好有一个纯图标按钮(就是这个 X)。探针已删除,未进 PR #3410。 顺带核过同文件的其余按钮,都**有**文本因而有名字:折叠态的 `New {objectName}` / `Link Existing`、页签触发器、`Cancel` / `Create`、以及搜索结果行按钮。所以本单只涉及这一个关闭按钮。 ## 建议修法 给按钮一个可访问名。与本文件已确立的形状一致的做法是 `aria-label`——注意这里和 #3381 的裁定**不冲突**:#3381 否决 `aria-label` 是因为那里存在可见文案(placeholder)、用 `aria-label` 会让可见文本与可访问名解耦;而这里**没有任何可见文案**,`aria-label` 是图标按钮的标准解法(另一种是 `sr-only` 文本子节点,效果等价)。 i18n:本文件目前整体是英文硬编码(未消费 `useDetailTranslation`),而 `DETAIL_DEFAULT_TRANSLATIONS` 里已有语义相近的键可考虑(如 `detail.cancel`);是否在本单顺带把该组件接入 i18n,属于范围问题,请 PM 裁定——纯补 `aria-label`(英文字面量,与同文件其余文案同一族)是最小改动。 ## 验收建议 - `getByRole('button', { name: … })` 能拿到该关闭按钮; - `toHaveAccessibleName` 非空; - 反向验证:去掉新加的名字来源后该断言转红(注意别写成「不存在无文本按钮」这类会被其它改动带绿的间接断言)。 关联:#3381(PR #3410)、#3341(PR #3380)、#3299、#3290。
Activity
yinlianghui commentedon Aug 5, 2026
认领:objectui 分片 PM 滚动补位第 19 单(#3381/PR #3410 落地后同文件释放)
会话:
session_01GTRjn8xBqp75dk7kFupVRt分支:
claude/issue-3411-close-button-nameWorktree:
objectui-issue-3411域:objectui 分片(plugin-detail)
文件面:
packages/plugin-detail/src/InlineCreateRelated.tsx+ 相应测试 +.changeset/*.md(patch)。当前在飞 0。范围裁定(PM,否决窗口):最小修 ——
aria-label英文字面量(纯图标按钮的标准解法,与 #3381 裁定不冲突 —— 此处无可见文案无解耦问题;与同文件其余英文文案同族)。⛔ 本单不把组件接入 i18n(该文件整体英文硬编码是另一族问题,待与 #5506 同类项统一处理,别让一行 a11y 修复变成 i18n 清扫)。验收照正文:getByRole按名命中 +toHaveAccessibleName非空 + 直接反向断言(勿用会被其它改动带绿的间接形)。Generated by Claude Code
yinlianghui commentedon Aug 5, 2026
PM 验收:ACCEPT → PR #3413 已转 ready + auto-merge(CI 16/16 完成全绿),跟到 MERGED。
落地内容(最小修):
aria-label="Close"+ 图标显式aria-hidden(lucide 默认已隐藏,显式写出让意图本地化、不依赖图标库版本),形状与仓内其它 close 按钮(shadcn dialog/sheet、DashboardEditor)一致。反向验证修前 7/7 红且结构定位仍成功 —— 红的是名字不是元素移位。消费半径核实:该组件仅具名导出、无注册表消费方。刻意零衍生立单:同文件整体英文硬编码已由 PM 裁归 #5506 同族,dev 搜证无既有 tracker 后依纪律不另开孪生 —— 正确。至此
InlineCreateRelated单文件的四类 a11y 缺陷全部闭环:#3299(状态)→ #3341(关联)→ #3381(无标签)→ #3411(无名字)。objectui 分片 PM
session_01GTRjn8xBqp75dk7kFupVRtGenerated by Claude Code
fix(a11y): name InlineCreateRelated's icon-only close button (objects…