自定义元素需手动补全无障碍四要素:语义(显式声明role)、名称(aria-label或aria-labelledby)、状态(动态同步aria-checked等)、交互(tabindex+keydown处理);表单集成须启用formAssociated并同步原生input属性。

自定义元素默认没有无障碍能力,必须手动补全语义、名称、状态和交互四要素,缺一不可。
必须显式声明 role 和可访问名称
浏览器不会给 <my-toggle> 自动赋予按钮、开关或复选框的语义。需同时设置:
-
role="switch"(或其他匹配角色,如button、checkbox) -
aria-label="启用通知"或aria-labelledby="label-id"提供明确名称 - 若用
aria-labelledby,目标元素 ID 必须存在且未被aria-hidden="true"或display: none隐藏
状态属性要随交互实时同步
ARIA 状态不是静态配置,而是动态反映组件当前行为:
- 开关切换后,必须执行
this.setAttribute('aria-checked', this.checked ? 'true' : 'false') - 折叠面板展开时设
aria-expanded="true",收起时设为"false" - 表单校验失败时设
aria-invalid="true"并绑定aria-describedby="error-id",通过后必须移除这两项
键盘交互与焦点管理不能依赖原生行为
自定义元素不继承原生控件的键盘响应逻辑,需主动实现:
- 添加
tabindex="0"让元素可聚焦 - 监听
keydown事件,对Enter和Space做相同处理(注意调用e.preventDefault()) - 模态对话框等场景还需捕获 Tab 键,在内部焦点循环,并在打开时将焦点移入首个可聚焦子元素
表单集成需走 formAssociated 流程
若组件要参与表单提交、重置或验证(如 <my-checkbox checked>),光有 role 不够:
- 类定义中声明
static formAssociated = true - 构造函数第一行调用
super() - 在 Shadow DOM 内嵌真实
<input type="checkbox">,并通过 getter/setter 同步checked、disabled、value等属性 - 属性变更监听中,
attributeChangedCallback的newValue是字符串,判断布尔属性应写newValue !== null,而非=== true


















