radio校验依赖name一致性而非required属性:同组必须name相同且至少一个checked;required对单个radio无效,JS验证应查:checked数量;无障碍需label关联和fieldset包裹。

radio 必选校验靠 name 一致性,不是靠 required 属性
HTML 原生 required 对单个 <input type="radio"> 无效——浏览器只检查该元素自身值是否为空,而未选中的 radio 值始终为空字符串,哪怕同组其他项已选。真正起作用的是:**同一组 radio 必须共享相同的 name 值,且至少一个被设为 checked(或用户手动选中)**。否则提交时表单会因“无有效值”被阻止(现代浏览器行为),但这个阻止依赖于整个 name 组的完整性,而非单个元素的 required。
- 必须给同组所有 radio 设置完全一致的
name,比如name="gender" - 任意一个 radio 可加
checked实现默认选中(非必需,但能避免初始无选中状态) - 不要给每个 radio 单独加
required;它对 radio 组无效,还可能干扰可访问性(屏幕阅读器误判) - 若用 JS 手动验证,应查
document.querySelectorAll('input[name="xxx"]:checked').length > 0,而不是检查单个元素的 validity
用 :valid/:invalid 伪类配合 CSS 显示校验状态
虽然单个 radio 不响应 required,但整个 radio 组在表单提交失败时,浏览器会将该组中「第一个」radio 元素标记为 :invalid(前提是表单有 novalidate 被移除,且使用原生提交)。这可用于视觉反馈:
input[type="radio"][name="plan"] + label {
color: #333;
}
input[type="radio"][name="plan"]:invalid + label {
color: #d32f2f;
}
form:invalid input[type="radio"][name="plan"]:first-of-type {
outline: 2px solid #d32f2f;
}
- 仅当表单未设
novalidate且用户触发了提交(如点击<button type="submit">)后,:invalid才生效 -
:invalid只附加到同名组里的第一个 radio 元素上,不是全部 - 若需更早提示(如离开字段时),必须用 JS 监听
blur或change并手动添加 class
JS 手动校验时别漏掉动态插入的 radio
如果 radio 是通过 JS 动态生成(比如从 API 加载选项),原生表单校验不会自动识别它们——除非这些元素在 DOM 中且属于同一 name 组,并在提交前已存在。常见坑点:
- 用
innerHTML插入 radio 后,需确保name值与已有项完全一致(注意空格、大小写) - 动态插入后,若用户尚未操作,
document.querySelector('input[name="topic"]:checked')仍返回null,得靠 JS 主动检查 - 推荐封装校验函数:
function isRadioGroupSelected(name) { return document.querySelectorAll(`input[name="${name}"]:checked`).length > 0; } - 提交前调用该函数,返回
false就event.preventDefault()并提示用户
无障碍(a11y)要求:每个 radio 必须有明确关联的 label
光有 name 和 required 不够。屏幕阅读器依赖 <label for="id"> 或包裹结构来宣告选项含义。没正确关联的 radio 组,即使功能正常,也会被 WCAG 判定为失败。
立即学习“前端免费学习笔记(深入)”;
- 每个 radio 应有唯一
id,对应<label for="xxx">;或者直接把 radio 包在<label>内 - 避免仅用文字描述(如 “男 / 女”)而无语义化标签
- 组标题建议用
<fieldset>+<legend>,例如:<fieldset><legend>请选择身份</legend>...</fieldset> - 不加
aria-required="true"—— 它对 radio 组无效,反而造成冗余
name 值拼写不一致,以及无障碍结构缺失导致的测试通过但残障用户无法操作。



















