自定义元素默认不可访问,必须手动补全无障碍四要素:role明确类型、aria-labelledby或aria-label提供名称、aria-*属性同步状态、tabindex="0"加keydown监听实现可聚焦与可操作;表单集成需继承htmlelement、声明formassociated=true并在shadow dom内桥接真实input;attributechangedcallback中布尔属性值为字符串,须用newvalue !== null判断;toolbar容器必须用并配aria-label;所有初始化必须在connectedcallback中执行。

自定义元素默认不可访问,必须手动补全四要素
浏览器不会给 <my-button></my-button> 自动赋予任何语义或交互能力,它在屏幕阅读器里就是“自定义元素”,不朗读内容、不响应 Tab、按空格也不触发。想让它真正可用,必须同时满足:用 role 明确类型(如 role="button")、用 aria-labelledby 或 aria-label 提供可访问名称、用 aria-checked/aria-expanded 等同步实时状态、用 tabindex="0" + keydown 监听 Enter/Space 实现可聚焦与可操作。
常见错误包括:<my-toggle role="switch"></my-toggle> 没设 aria-checked,读屏器只知“这是开关”,不知当前开/关;<my-tab role="tab"></my-tab> 没加 tabindex="0",键盘用户根本进不去;aria-labelledby 引用的 ID 在 Shadow DOM 外查找,结果失效。
表单集成必须继承 HTMLElement 并声明 formAssociated = true
如果组件要参与表单提交、重置或被 form.elements 收集(比如 <my-checkbox></my-checkbox>),光写 role="checkbox" 不够,必须:
- 构造函数第一行调用
super() - 声明
static formAssociated = true - 在 Shadow DOM 内挂载真实
<input type="checkbox">,并通过getter/setter桥接checked、disabled、value等属性
漏掉任意一项,<my-checkbox checked></my-checkbox> 就只是个带样式的 div,form.reset() 不会清空它,form.checkValidity() 也查不到它的验证状态。
attributeChangedCallback 中布尔属性值是字符串,不是布尔值
监听 checked 或 disabled 属性时,newValue 是 "true"、null 或空字符串 "",不是 true/false。错误写法:input.checked = newValue === true —— 这永远为 false。
正确处理方式:
-
checked:用newValue !== null判断是否被显式设置 -
disabled:同样用newValue !== null,因为disabled=""和disabled="false"都传入"",但后者语义上不该禁用 - 所有转换逻辑必须在
attributeChangedCallback中执行,不能依赖 JS 属性赋值
toolbar 容器必须用 <div role="toolbar">,不能用 <code><toolbar></toolbar>
<toolbar></toolbar> 是无效 HTML 标签,浏览器直接忽略,所有 ARIA 行为失效。正确做法是:
- 用
<div role="toolbar"> 包裹工具按钮 <li>必须配 <code>aria-label(如aria-label="编辑工具栏"),空字符串或缺失会被跳过 - 子元素只能是可聚焦控件:
<button></button>、<input>、<select></select>、<textarea></textarea>;禁止放<a></a>或<div onclick> <li>确保每个子控件都已补全无障碍四要素,否则整个 toolbar 对键盘用户不可用</li> <p>最易被忽略的是:所有这些初始化(<code>tabindex、role、事件绑定)必须在connectedCallback中执行,constructor里 DOM 尚未挂载,操作无效且可能被覆盖。











