Skip to content

datalist 数据列表

<datalist> 元素与 <input> 配合使用,为输入框提供预定义的建议列表。与 <select> 的强制选择不同,<datalist> 允许用户从建议中选择,也可以自由输入不在列表中的值。这种"建议 + 自由输入"的组合在搜索、地址输入等场景中非常实用。

前置知识

阅读本节前,建议先了解:select 下拉选择

基础概念

什么是 datalist

<datalist> 是一个包含一组 <option> 元素的容器,它本身不可见。通过 <input>list 属性关联到 <datalist>id,浏览器会在用户输入时显示匹配的建议列表。

html
<!-- datalist 定义建议 -->
<datalist id="browsers">
  <option value="Chrome">
  <option value="Firefox">
  <option value="Safari">
  <option value="Edge">
</datalist>

<!-- input 通过 list 属性关联 -->
<input type="text" list="browsers" placeholder="输入浏览器名称">

datalist 与 select 对比

对比维度datalistselect
输入方式可以自由输入 + 选择建议只能从列表中选择
可见性输入时才显示始终可见(或点击展开)
筛选根据输入自动过滤无自动过滤
自定义输入支持不支持
表单提交通过关联的 input 提交直接提交
分组不支持 optgroup支持

datalist 的核心特征

特征说明
关联方式input 的 list 属性指向 datalist 的 id
显示时机用户聚焦或输入时
自动过滤根据用户输入自动筛选匹配项
自由输入用户可以输入列表之外的值
兼容性所有现代浏览器支持,Safari 支持较晚(16.4+)

语法

基本语法

html
<!-- 定义建议列表 -->
<datalist id="suggestionId">
  <option value="值1">
  <option value="值2">
  <option value="值3" label="显示文本">
</datalist>

<!-- 关联到输入框 -->
<input type="text" list="suggestionId" name="field">

option 的属性

属性说明
value字符串建议的值(选中后填入 input)
label字符串建议的显示文本(可选)
disabled布尔属性禁用该建议项(较少使用)

详细说明

基本使用

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>datalist 基本使用</title>
  <style>
    .form-group {
      margin-bottom: 20px;
    }

    label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    input {
      padding: 10px 12px;
      border: 1px solid #ccc;
      border-radius: 6px;
      font-size: 14px;
      width: 300px;
    }
  </style>
</head>
<body>
  <h2>编程语言搜索</h2>
  <form action="/search" method="get">
    <div class="form-group">
      <label for="language">搜索编程语言:</label>
      <!--
        list="languages" 关联到 datalist 的 id
        用户输入时,浏览器自动过滤匹配的语言
      -->
      <input type="text"
             id="language"
             name="q"
             list="languages"
             placeholder="输入语言名称...">

      <!-- 建议列表 -->
      <datalist id="languages">
        <option value="JavaScript">
        <option value="TypeScript">
        <option value="Python">
        <option value="Java">
        <option value="C++">
        <option value="C#">
        <option value="Go">
        <option value="Rust">
        <option value="PHP">
        <option value="Ruby">
        <option value="Swift">
        <option value="Kotlin">
      </datalist>
    </div>

    <button type="submit">搜索</button>
  </form>

  <!--
    用户行为示例:
    1. 聚焦输入框 → 显示所有语言
    2. 输入 "Ja" → 过滤显示 Java, JavaScript, Java (已删除)
    3. 点击 "JavaScript" → 输入框填入 "JavaScript"
    4. 也可以输入 "C" → 列表没有也行,自由输入
  -->
</body>
</html>

与不同 type 配合

<datalist> 可以与多种 <input> type 配合使用:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>datalist 与不同 type</title>
  <style>
    .demo {
      margin-bottom: 20px;
      padding: 16px;
      border: 1px solid #e0e0e0;
      border-radius: 8px;
    }

    label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    input, select {
      padding: 8px;
      border: 1px solid #ccc;
      border-radius: 4px;
      width: 300px;
    }
  </style>
</head>
<body>
  <h2>datalist 与不同 input type</h2>

  <!-- 与 text 配合 -->
  <div class="demo">
    <h3>text(城市输入)</h3>
    <label for="city">城市:</label>
    <input type="text" id="city" name="city" list="cityList" placeholder="输入或选择">
    <datalist id="cityList">
      <option value="北京">
      <option value="上海">
      <option value="广州">
      <option value="深圳">
      <option value="杭州">
      <option value="成都">
    </datalist>
  </div>

  <!-- 与 email 配合 -->
  <div class="demo">
    <h3>email(邮箱域名建议)</h3>
    <label for="email">邮箱:</label>
    <input type="email" id="email" name="email" list="domainList" placeholder="用户名@">
    <datalist id="domainList">
      <option value="@qq.com">
      <option value="@163.com">
      <option value="@126.com">
      <option value="@gmail.com">
      <option value="@outlook.com">
    </datalist>
  </div>

  <!-- 与 url 配合 -->
  <div class="demo">
    <h3>url(网站建议)</h3>
    <label for="website">网站:</label>
    <input type="url" id="website" name="website" list="siteList" placeholder="https://">
    <datalist id="siteList">
      <option value="https://www.baidu.com">
      <option value="https://www.google.com">
      <option value="https://github.com">
      <option value="https://stackoverflow.com">
    </datalist>
  </div>

  <!-- 与 number 配合 -->
  <div class="demo">
    <h3>number(常用数量)</h3>
    <label for="quantity">数量:</label>
    <input type="number" id="quantity" name="quantity" list="qtyList" min="1">
    <datalist id="qtyList">
      <option value="1">
      <option value="5">
      <option value="10">
      <option value="20">
      <option value="50">
      <option value="100">
    </datalist>
  </div>

  <!-- 与 date 配合 -->
  <div class="demo">
    <h3>date(常用日期)</h3>
    <label for="date">日期:</label>
    <input type="date" id="date" name="date" list="dateList">
    <datalist id="dateList">
      <option value="2025-01-01">
      <option value="2025-02-14">
      <option value="2025-10-01">
      <option value="2026-01-01">
    </datalist>
  </div>
</body>
</html>

自定义输入 + 建议列表

<datalist> 最强大的特点是不完全限制用户的选择。用户可以选择建议,也可以自由输入。

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>自定义输入 + 建议</title>
  <style>
    body {
      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
      max-width: 500px;
      margin: 40px auto;
      padding: 20px;
    }

    .form-group {
      margin-bottom: 20px;
    }

    label {
      display: block;
      font-weight: 500;
      margin-bottom: 6px;
    }

    input {
      width: 100%;
      padding: 10px 12px;
      border: 1px solid #ddd;
      border-radius: 6px;
      box-sizing: border-box;
      font-size: 14px;
    }

    .comparison {
      display: flex;
      gap: 20px;
      margin-top: 16px;
    }

    .comparison > div {
      flex: 1;
      padding: 16px;
      border: 1px solid #e0e0e0;
      border-radius: 8px;
    }

    .comparison h3 {
      margin-top: 0;
      font-size: 16px;
    }
  </style>
</head>
<body>
  <h2>对比:datalist vs select</h2>

  <div class="comparison">
    <!-- datalist:可以选择建议,也可以自由输入 -->
    <div>
      <h3>datalist(自由输入 + 建议)</h3>
      <label for="framework">框架:</label>
      <input type="text" id="framework" name="framework" list="frameworks">
      <datalist id="frameworks">
        <option value="Vue.js">
        <option value="React">
        <option value="Angular">
        <option value="Svelte">
      </datalist>
      <p style="font-size: 13px; color: #999; margin-top: 8px;">
        可以选择 Vue.js,也可以输入 Solid.js
      </p>
    </div>

    <!-- select:只能从列表中选择 -->
    <div>
      <h3>select(只能选择)</h3>
      <label for="framework2">框架:</label>
      <select id="framework2" name="framework2">
        <option value="Vue.js">Vue.js</option>
        <option value="React">React</option>
        <option value="Angular">Angular</option>
        <option value="Svelte">Svelte</option>
      </select>
      <p style="font-size: 13px; color: #999; margin-top: 8px;">
        只能选择列表中的四个选项
      </p>
    </div>
  </div>
</body>
</html>

option 的 value 与 label

<datalist> 中的 <option> 支持 valuelabel 两个属性:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>option value 与 label</title>
</head>
<body>
  <h2>datalist option 的 value 和 label</h2>
  <form>
    <label for="country">国家:</label>
    <input type="text" id="country" name="country" list="countries">

    <datalist id="countries">
      <!--
        value:选中后填入输入框的值
        label:在下拉列表中额外显示的文本(某些浏览器)

        注意:不同浏览器对 label 的显示方式不同
        Chrome:显示 value
        Firefox:显示 value (label)
      -->
      <option value="CN" label="中国">
      <option value="US" label="美国">
      <option value="JP" label="日本">
      <option value="GB" label="英国">
    </datalist>
  </form>

  <!--
    用户体验:
    - 列表中可能显示 "CN (中国)"
    - 选中后输入框填入 "CN"

    这在需要内部代码但显示友好名称时很有用
  -->
</body>
</html>

动态更新 datalist

<datalist> 的选项可以通过 JavaScript 动态添加、修改或删除:

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>动态 datalist</title>
  <style>
    .form-group { margin-bottom: 16px; }
    label { display: block; font-weight: 500; margin-bottom: 6px; }
    input, button {
      padding: 8px 12px;
      border: 1px solid #ccc;
      border-radius: 4px;
      font-size: 14px;
    }
    input { width: 300px; }
    button { cursor: pointer; }
  </style>
</head>
<body>
  <h2>动态建议列表</h2>
  <form>
    <div class="form-group">
      <label for="tag">标签:</label>
      <input type="text" id="tag" name="tag" list="tagList" placeholder="输入或选择标签">
      <datalist id="tagList"></datalist>
    </div>
  </form>

  <div style="margin-top: 16px;">
    <label for="newTag">添加新标签:</label>
    <input type="text" id="newTag" placeholder="输入新标签名称">
    <button type="button" id="addBtn">添加</button>
  </div>

  <div id="tagCount" style="margin-top: 12px; color: #666;"></div>

  <script>
    const datalist = document.getElementById('tagList');
    const newTagInput = document.getElementById('newTag');
    const tagCount = document.getElementById('tagCount');

    // 已有标签
    const existingTags = ['JavaScript', 'HTML', 'CSS', 'Vue.js', 'React'];

    // 初始化 datalist
    function renderDatalist() {
      datalist.innerHTML = '';
      existingTags.forEach(tag => {
        const option = document.createElement('option');
        option.value = tag;
        datalist.appendChild(option);
      });
      tagCount.textContent = `当前标签数:${existingTags.length}`;
    }

    // 添加新标签
    document.getElementById('addBtn').addEventListener('click', function() {
      const newTag = newTagInput.value.trim();
      if (!newTag) return;
      if (existingTags.includes(newTag)) {
        alert('标签已存在');
        return;
      }
      existingTags.push(newTag);
      renderDatalist();
      newTagInput.value = '';
    });

    // 初始化
    renderDatalist();
  </script>
</body>
</html>

通过 AJAX 动态加载建议

html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>AJAX datalist</title>
  <style>
    .search-box {
      max-width: 500px;
      margin: 40px auto;
    }

    input {
      width: 100%;
      padding: 12px 16px;
      font-size: 16px;
      border: 2px solid #ddd;
      border-radius: 24px;
      box-sizing: border-box;
    }

    input:focus {
      outline: none;
      border-color: #4a90d9;
    }
  </style>
</head>
<body>
  <div class="search-box">
    <h2>用户搜索</h2>
    <!--
      实际项目中,datalist 的选项通常来自服务器端搜索
      由于 datalist 的原生过滤机制,可以直接更新 option
    -->
    <form action="/search" method="get">
      <input type="text"
             id="userSearch"
             name="q"
             list="userSuggestions"
             placeholder="搜索用户名..."
             autocomplete="off">
      <datalist id="userSuggestions"></datalist>
    </form>
  </div>

  <script>
    const searchInput = document.getElementById('userSearch');
    const datalist = document.getElementById('userSuggestions');

    let debounceTimer = null;

    searchInput.addEventListener('input', function() {
      clearTimeout(debounceTimer);
      const query = this.value.trim();

      if (!query || query.length < 2) {
        datalist.innerHTML = '';
        return;
      }

      // 防抖 300ms
      debounceTimer = setTimeout(async () => {
        try {
          // 模拟 AJAX 请求
          // const response = await fetch(`/api/users?q=${encodeURIComponent(query)}`);
          // const users = await response.json();

          // 模拟数据
          const users = [
            { id: 1, name: query + '_user1' },
            { id: 2, name: query + '_user2' },
            { id: 3, name: query + '_admin' },
          ];

          // 更新 datalist
          datalist.innerHTML = users.map(user =>
            `<option value="${user.name}">`
          ).join('');
        } catch (error) {
          console.error('搜索失败', error);
        }
      }, 300);
    });
  </script>
</body>
</html>

注意事项

  1. Safari 的兼容性:Safari 从 16.4 版本开始支持 <datalist>。在旧版 Safari 中,<datalist> 被忽略,输入框正常工作但没有建议功能。

  2. 浏览器对建议列表的样式控制有限:不同浏览器对 <datalist> 下拉列表的样式有差异,且 CSS 控制能力非常有限。

  3. datalist 不验证输入:用户可以选择列表外的值,<datalist> 不会限制或验证输入。

  4. 大量选项的性能:如果 datalist 中有数百个选项,某些浏览器可能出现卡顿。建议限制在 100~200 个选项以内。

  5. label 属性的浏览器差异<option>label 属性在不同浏览器中的显示方式不一致,Chrome 主要显示 value,Firefox 可能显示 value (label)

最佳实践

  1. 需要自由输入 + 建议时用 datalist:如果用户可能输入不在预设列表中的值,使用 datalist 而非 select。

  2. 需要严格限制选项时用 select:如果用户只能从预设选项中选择,使用 select。

  3. 限制建议数量:不要在 datalist 中放置过多选项,影响性能和可读性。

  4. 配合 placeholder 引导:用 placeholder 提示用户可以自由输入。

  5. Safari 兼容方案:对于需要兼容旧版 Safari 的场景,可以提供自定义的自动补全组件作为替代。

下一节

继续学习:optgroup 选项分组

参考链接