details 与 radio 无原生联动,必须用 javascript 监听 radio 的 change 事件并手动控制 details.open;details 无 name 属性,不参与表单提交,无障碍需同步 aria-expanded。

details 标签本身不提供与单选按钮的互斥显示逻辑,两者行为完全独立;所谓“配合”,只能靠 JavaScript 手动桥接状态,不能依赖 HTML 属性自动联动。
details 没有 name 属性,也不响应 radio 的 name 分组
details 元素规范中**不存在 name 属性**,写 <details name="group"></details> 是无效自定义属性,浏览器既不报错也不生效。它和 input[type="radio"] 的互斥机制毫无交集——radio 靠 name 字符串匹配实现原生互斥,details 只认自己的 open 布尔属性,且彼此无状态约束。
常见误操作包括:
- 给多个
details设相同name,以为能像 radio 一样自动关闭其他项 - 把 radio 的
name和details的name当作同一套控制体系 - 期望点击某个 radio 后,对应
details自动展开、其余收起,而未加任何 JS
想让 details 随 radio 切换而开关,必须监听 change 事件
radio 状态变化后,要驱动 details 开关,唯一可靠方式是监听 change 事件(不是 click),再手动设置目标 details.open。
关键点:
- 用
document.querySelector('input[name="xxx"]:checked')获取当前选中项的value - 用该
value匹配details的某个标识(如data-target、id或data-value) - 遍历所有同组
details,对匹配项设open = true,其余设open = false - 注意:首次加载时也要同步一次状态,否则 DOM 就绪但
details未按默认 radio 展开
示例片段:
document.querySelectorAll('input[name="panel"]').forEach(radio => {
radio.addEventListener('change', () => {
const target = radio.value;
document.querySelectorAll('details[data-panel]').forEach(d => {
d.open = d.dataset.panel === target;
});
});
});
radio 与 details 放在同一表单里 ≠ 自动联动
即使 radio 和 details 都包裹在同一个 <form></form> 中,HTML 不会因此建立任何隐式关联。表单提交时,details 的 open 状态**不会被发送到服务端**,它纯属前端 UI 状态。
容易忽略的细节:
-
details的open属性不参与表单序列化,new FormData(form)里查不到它 - 若需提交面板展开状态,必须额外加一个隐藏
input,并在 JS 中同步更新其value - 无障碍方面:
details天然支持屏幕阅读器,但若被 JS 强制控制开关,需确保aria-expanded和aria-controls手动同步,否则读屏会丢失状态
真正麻烦的地方不在写几行 JS,而在于状态同步的边界:radio 可能由 JS 动态插入、可能跨 Shadow DOM、可能被 reset() 重置——这些都会让 details.open 脱离预期,必须在每个触发点做防御性处理。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











