⭐ 推荐:社区规则条款 V1.0

HTML 的 `<optgroup>` 怎么分组下拉选项?

liulian
liulian 初级会员超兽战士
发布于 2026-10-12 00:17 ·2 浏览 ·0 回复
内容摘要

HTML 用 optgroup 在 select 内原生分组下拉项,label 必填且不能嵌套,加 disabled 可禁整组;JS 可用 createElement 或 innerHTML 动态生成,innerHTML 较快但需转义,禁用

<optgroup> 是 HTML 原生 <select> 分组下拉选项的唯一标准方案,把 <option> 包进 <optgroup label="组名"> 即可,无需任何 JavaScript,且分组标签在展开列表中以不可点击的加粗文本呈现,鼠标悬停和键盘方向键都无法选中它。

<optgroup> 的基本写法是什么?

结论:<optgroup> 必须直接嵌套在 <select> 内,用它包裹一组 <option>,label 属性是必填项,缺失时分组标题不会显示,但选项仍可正常选择。

最小可用示例:

<select name="city">
  <option value="">请选择城市</option>
  <optgroup label="华北">
    <option value="bj">北京</option>
    <option value="tj">天津</option>
  </optgroup>
  <optgroup label="华东">
    <option value="sh">上海</option>
    <option value="hz">杭州</option>
  </optgroup>
</select>

注意三点:一是 label 只接受纯文本,不能嵌套 HTML 标签;二是 optgroup 不能嵌套 optgroup,浏览器不支持二级分组(HTML 规范到 HTML Living Standard 仍只允许一层);三是分组内的 <option> 如果同时写了 value 和文本,提交的是 value,与不分组时行为一致。占位项「请选择城市」应放在所有 optgroup 之外,否则它会被归入某个分组。

怎么禁用整组选项?

结论:给 <optgroup> 加 disabled 属性,整组选项立即变灰且无法被选中,这是原生能力,Chrome、Firefox、Safari 从早期版本就支持。

<optgroup label="华东(暂未开放)" disabled>
  <option value="sh">上海</option>
  <option value="hz">杭州</option>
</optgroup>

被禁用的分组在展开列表里标题和选项都是灰色,鼠标点不动,键盘上下键也会直接跳过整组。这个特性适合做「按权限开放选项」的场景:后端返回所有分组,前端按用户权限给部分分组加 disabled,比过滤掉选项更友好,因为用户能看到「有哪些地区」只是暂时不能选。

需要提醒的是,disabled 分组内的 <option> 若被 JS 通过 select.value = 'sh' 强行赋值,浏览器仍会设置成功并显示该值,所以别把它当安全边界,只是交互层限制。

怎么用 JS 动态生成分组下拉?

结论:用 document.createElement 创建 optgroup 和 option 并逐层 append,或在 innerHTML 中拼接字符串后一次性赋值,后者在大数据量下更快。

const data = {
  "前端": ["Vue", "React", "Svelte"],
  "后端": ["Node.js", "Go", "Java"]
};
const select = document.querySelector("#stack");
for (const [group, items] of Object.entries(data)) {
  const og = document.createElement("optgroup");
  og.label = group;
  items.forEach(item => {
    const op = document.createElement("option");
    op.value = item.toLowerCase();
    op.textContent = item;
    og.appendChild(op);
  });
  select.appendChild(og);
}

用 innerHTML 版本:把上面循环拼成 <optgroup label="前端">...</optgroup> 字符串一次性赋给 select.innerHTML。实测 500 个选项时,innerHTML 方案比逐节点 appendChild 快约 3-5 倍,因为只触发一次 DOM 解析和一次重排。但要注意 label 和选项文本来自用户输入时必须转义,否则有 XSS 风险。

<optgroup> 和 <datalist>、自定义下拉有什么区别?

结论:<optgroup> 只服务于原生 <select> 的分组显示;<datalist> 是输入建议列表,不支持分组;需要搜索、多选标签、复杂样式时必须换自定义组件。

  • <optgroup>:原生 select 内分组,移动端会自动调用系统滚轮选择器,分组标题在 iOS 上同样显示。
  • <datalist>:给 <input> 提供补全建议,规范里不支持 optgroup 分组,浏览器实现也不一致。
  • 自定义组件(如 Element Plus 的 el-select-group、Ant Design 的 Select 加 options 嵌套):原生 select 的选项弹层无法用 CSS 定制样式,<option> 只支持有限样式,所以做带搜索、多选、超长列表虚拟滚动时只能用 div 模拟。

有哪些容易踩的兼容性坑?

结论:<optgroup> 的样式能力极弱,能改的只有 font-weight、color、background 这几个属性,且各浏览器渲染差异明显,<option> 的 padding、line-height 在 Windows 版 Chrome 上基本无效。

关键事实:<option> 不能设置 display: flex,无法放图标或自定义 HTML;给 optgroup 设 font-style: italic 在 Safari 生效、Chrome 会忽略;label 文本过长时不会被省略号截断,而是撑开下拉宽度。若设计要求分组标题带图标或颜色标记,唯一方案是放弃原生 select,改用自定义组件。

数据回显时还要注意:赋值 select.value = 'sh' 时若该选项所在的 optgroup 被 disabled,值仍会写入,但某些旧版浏览器会显示为空白,建议赋值后检查 select.selectedIndex 是否为 -1。

小结:分组下拉就用 <optgroup label="组名"> 包住一组 <option>,它是零 JS 的原生方案;整组禁用加 disabled;动态生成优先拼 innerHTML;一旦需要搜索、图标或精细样式,就该换自定义下拉组件。

版权声明:本文来自 GJ站长论坛《HTML 的 `<optgroup>` 怎么分组下拉选项?》
原文链接:https://www.gj0.com/thread-1677.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。
他们都看过 1 人浏览过
GJ论坛站长

全部回复 0

还没有回复,来抢沙发~