如何实现可访问、不可修改的只读复选框与单选按钮?
可复用只读输入组件的可访问性实现方案推荐
我正在开发支持多种输入类型的可复用输入组件,需要确定可访问且不可修改的只读输入的推荐实现方案,典型场景是用户查看已提交表单内容的情况,核心问题是如何正确渲染这类输入。
核心限制与现有方案问题
readonly属性(包括aria-readonly)仅对文本类输入有效,对复选框(checkbox)和单选按钮(radio)完全无效,这类输入需要单独处理。- 使用
disabled属性的问题:输入会被移出tab切换顺序,且disabled传达的是“输入无关”的状态,和“只读但相关”的需求不符。示例代码:
<label> <input type="checkbox" disabled /> A checkbox </label>
- 非编辑模式下移除输入元素:文本输入容易实现,但对单选组这类输入,需要手动向屏幕阅读器传达“属于单选组、已选中”等原生语义,模拟成本高且容易出错。
aria-disabled="true"+手动阻止修改:同样无法准确传达“相关但不可编辑”的状态,语义上仍偏向“禁用”,示例代码:
<label> <input id="my-checkbox" type="checkbox" aria-disabled="true" /> A checkbox </label>
document.getElementById("my-checkbox")?.addEventListener("click", event => { event.preventDefault(); })
推荐实现方案
1. 文本类输入(input[type=text/email/url等]、textarea)
直接使用原生readonly属性,这是最优解:
- 保留输入元素的tab聚焦顺序,用户可通过键盘访问
- 原生语义明确,屏幕阅读器能正确识别“只读”状态
- 无需额外JS阻止修改,浏览器原生支持
示例代码:
<label for="username">用户名</label> <input type="text" id="username" value="张三" readonly />
2. 复选框与单选按钮
这类输入无法使用readonly,推荐以下组合方案:
- 保留原生输入元素,确保语义完整性(比如单选组的
name属性关联、复选框的选中状态) - 添加
aria-readonly="true",明确告知屏幕阅读器该输入为只读状态 - 通过CSS移除交互样式(比如禁用鼠标指针变化)
- 使用JavaScript阻止所有可能的修改操作(点击、键盘切换等)
- 可选添加
tabindex="0",确保输入可被键盘聚焦(如果需要让用户能通过tab访问到该控件)
示例代码(复选框):
<label> <input id="readonly-checkbox" type="checkbox" checked aria-readonly="true" tabindex="0" /> 已同意用户协议 </label>
#readonly-checkbox { pointer-events: none; /* 阻止鼠标交互 */ opacity: 0.8; /* 视觉上区分只读状态 */ }
const checkbox = document.getElementById("readonly-checkbox"); if (checkbox) { // 阻止点击修改 checkbox.addEventListener("click", e => e.preventDefault()); // 阻止键盘切换(比如空格、回车) checkbox.addEventListener("keydown", e => { if (e.key === " " || e.key === "Enter") { e.preventDefault(); } }); }
示例代码(单选组):
<fieldset> <legend>性别</legend> <label> <input type="radio" name="gender" value="male" checked aria-readonly="true" tabindex="0" /> 男 </label> <label> <input type="radio" name="gender" value="female" aria-readonly="true" tabindex="0" /> 女 </label> </fieldset>
input[type="radio"][aria-readonly="true"] { pointer-events: none; opacity: 0.8; }
const radios = document.querySelectorAll('input[type="radio"][aria-readonly="true"]'); radios.forEach(radio => { radio.addEventListener("click", e => e.preventDefault()); radio.addEventListener("keydown", e => { if (["ArrowLeft", "ArrowRight", " ", "Enter"].includes(e.key)) { e.preventDefault(); } }); });
方案优势
- 保留原生输入的语义结构,屏幕阅读器能正确识别控件类型、组关系和选中状态
aria-readonly="true"准确传达“只读但相关”的状态,避免disabled的语义偏差- 保留tab聚焦能力(可选),符合可访问性要求
- 视觉上通过CSS区分只读状态,用户能直观感知
内容的提问来源于stack exchange,提问作者Norah
相关产品推荐
相关产品推荐

