Элемент datalist в HTML: автозаполнение, JSON и серверный поиск
Элемент <datalist> добавляет подсказки к полю <input>. Пользователь выбирает вариант или вводит свой текст, поэтому список не ограничивает значение сам по себе. Вы свяжете элементы, загрузите варианты из JSON через fetch, настроите серверный поиск с debounce и отменой старых запросов, а затем проверите значение формы.
Элемент <datalist> и связь с input
Задайте списку уникальный id. Поле ввода получит тот же идентификатор в атрибуте list, после чего браузер покажет подсказки при вводе.

Элемент <datalist> хранит варианты для поля. Атрибут value передает значение в input. Атрибут label или текст внутри option добавляет подпись.
<label for="language">Язык</label>
<input id="language" name="language" list="languages" autocomplete="off">
<datalist id="languages">
<option value="HTML" label="Разметка страницы">HTML</option>
<option value="CSS" label="Стили страницы">CSS</option>
<option value="JavaScript" label="Скрипты в браузере">JavaScript</option>
<option value="PHP">PHP</option>
</datalist>Браузер обычно подставляет в поле значение value. Подпись из label или текстовое содержимое может отображаться рядом с ним. Храните важные данные в value, потому что вид подписи отличается.
datalist только подсказывает варианты и не ограничивает ввод. Пользователь может напечатать строку, которой нет среди option. Если форма принимает только значения списка, сравните введенное значение с option при отправке.
<form id="language-form">
<input id="language-input" list="languages" required>
<button type="submit">Сохранить</button>
</form>
<script>
(() => {
const form = document.getElementById('language-form');
const input = document.getElementById('language-input');
const list = document.getElementById('languages');
form.addEventListener('submit', (event) => {
const values = [...list.options].map((option) => option.value);
if (!values.includes(input.value)) {
event.preventDefault();
input.setCustomValidity('Выберите значение из списка.');
input.reportValidity();
return;
}
input.setCustomValidity('');
});
input.addEventListener('input', () => input.setCustomValidity(''));
})();
</script>При отправке скрипт сравнивает значение input со всеми option. При несовпадении браузер оставляет пользователя в форме и показывает сообщение.
Загрузка вариантов из JSON через fetch
Статический список подходит для нескольких значений. Для большого набора вынесите массив в файл html-elements.json рядом с HTML-страницей.
[
"article",
"aside",
"button",
"canvas",
"dialog",
"form",
"header",
"main",
"nav",
"section"
]Создайте в одной папке файлы index.html и html-elements.json. Откройте терминал в этой папке и запустите python -m http.server 8000. Затем перейдите на http://localhost:8000. Такой запуск разрешает браузеру выполнить fetch для страницы.
<label for="element-input">HTML-элемент</label>
<input id="element-input" list="element-list" placeholder="Загрузка вариантов...">
<datalist id="element-list"></datalist>Скрипт проверяет HTTP-ответ, разбирает JSON и создает option через DocumentFragment. Метод replaceChildren удаляет старые варианты перед вставкой новых.
(() => {
const dataList = document.getElementById('element-list');
const input = document.getElementById('element-input');
async function loadOptions() {
input.placeholder = 'Загрузка вариантов...';
try {
const response = await fetch('html-elements.json');
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const options = await response.json();
const fragment = document.createDocumentFragment();
options.forEach((item) => {
const option = document.createElement('option');
option.value = item;
fragment.appendChild(option);
});
dataList.replaceChildren(fragment);
input.placeholder = 'Начните вводить HTML-элемент';
} catch (error) {
dataList.replaceChildren();
input.placeholder = 'Не удалось загрузить варианты';
console.error(error);
}
}
loadOptions();
})();Проверка response.ok отбрасывает ответы с ошибками HTTP, а catch меняет placeholder при сбое сети. DocumentFragment вставляет новые option одной операцией.

Подгрузка вариантов с сервера по мере ввода
Большой каталог лучше искать на сервере по мере ввода. Обработчик input ждет паузу debounce, ограничивает минимальную длину запроса и отменяет устаревший запрос.
Сохраните серверный файл как api/html-elements.php. Запустите сайт из корневой папки командой php -S localhost:8000. API будет доступно по адресу /api/html-elements.php?q=he.
<?php
header('Content-Type: application/json; charset=utf-8');
$items = [
'header',
'head',
'html',
'main',
'nav',
'section',
'article',
'aside',
'button',
'canvas'
];
$query = trim($_GET['q'] ?? '');
$result = array_values(array_filter(
$items,
static fn(string $item): bool => $query === '' || stripos($item, $query) !== false
));
echo json_encode($result, JSON_UNESCAPED_UNICODE);PHP получает параметр q и возвращает JSON-массив строк. Документация PHP пригодится при замене массива запросом к базе данных.
<label for="server-input">HTML-элемент</label>
<input id="server-input" list="server-list" placeholder="Введите минимум 2 символа" autocomplete="off">
<datalist id="server-list"></datalist>
<script>
(() => {
const serverInput = document.getElementById('server-input');
const serverList = document.getElementById('server-list');
let timer;
let controller;
serverInput.addEventListener('input', () => {
clearTimeout(timer);
const query = serverInput.value.trim();
if (controller) {
controller.abort();
controller = null;
}
if (query.length < 2) {
serverList.replaceChildren();
serverInput.placeholder = 'Введите минимум 2 символа';
return;
}
timer = setTimeout(async () => {
controller = new AbortController();
serverInput.placeholder = 'Поиск вариантов...';
try {
const response = await fetch(
`/api/html-elements.php?q=${encodeURIComponent(query)}`,
{ signal: controller.signal }
);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
const options = await response.json();
const fragment = document.createDocumentFragment();
options.forEach((item) => {
const option = document.createElement('option');
option.value = item;
fragment.appendChild(option);
});
serverList.replaceChildren(fragment);
serverInput.placeholder = 'Введите минимум 2 символа';
} catch (error) {
if (error.name !== 'AbortError') {
serverList.replaceChildren();
serverInput.placeholder = 'Не удалось загрузить варианты';
console.error(error);
}
}
}, 300);
});
})();
</script>Скрипт ждет 300 миллисекунд после последнего ввода. Запрос короче 2 символов он не отправляет.
Новый запрос отменяет предыдущий через AbortController. Перед вставкой код очищает datalist методом replaceChildren, а DocumentFragment добавляет текущие option одной операцией.
Чем datalist отличается от select
Оба элемента показывают варианты, но подходят для разных полей. Выбирайте datalist для подсказок, а select – для обязательного выбора из закрытого набора.
| Свойство | datalist | select |
|---|---|---|
| Свободный ввод | Пользователь может ввести любое значение | Пользователь выбирает вариант списка |
| Фильтрация | Браузер фильтрует подсказки при вводе | Обычно показывает варианты без свободного поиска |
| Оформление | Выпадающий список почти не стилизуется через CSS | Вид зависит от браузера и операционной системы |
| Мобильное поведение | Вид подсказок зависит от клавиатуры и браузера | Система часто открывает нативный список выбора |
Возьмите datalist, когда человеку удобно напечатать значение вручную. Используйте select, когда форма принимает только один вариант из закрытого набора.
Ограничения datalist и кастомный combobox
У datalist простое подключение без JavaScript, но браузер управляет внешним видом и частью поведения. Поэтому компонент подходит не каждой форме.
- Слабая стилизация. CSS почти не меняет внешний вид выпадающих подсказок.
- Разная фильтрация. Один браузер ищет совпадение с начала строки, другой может искать подстроку.
- Нет события выбора. У datalist нет отдельного надежного события выбора option, поэтому отслеживайте input и проверяйте значение.
- Разное поведение на мобильных. Клавиатура и состояние списка зависят от браузера.
Если нужны группы, собственное оформление, сложная фильтрация и предсказуемые события, соберите кастомный combobox по шаблону combobox из WAI-ARIA APG. Такой компонент требует больше кода, зато дает контроль над ролями, клавиатурой и состоянием списка.
Поддержка браузерами
datalist поддерживается в Chrome, Firefox, Safari, Opera и Edge для текстовых полей. Детали интерфейса зависят от браузера, устройства и типа input.
| Браузер | Поддержка | Оговорки |
|---|---|---|
| Chrome | Есть | Поддержка datalist для текстовых полей |
| Edge | Есть | Поддержка datalist для текстовых полей |
| Firefox | Есть | В Firefox для Android выпадающее меню может не появляться |
| Opera | Есть | Поведение зависит от типа поля |
| Safari | Есть | Внешний вид списка зависит от версии и устройства |
В Firefox для Android отдельно учитывайте input с типами date, color и range: такие сочетания поддерживаются частично. Для критичной формы протестируйте ввод, клавиатуру и мобильный экран в целевых браузерах.
Когда datalist подходит для формы
Выбирайте datalist для подсказок, свободного ввода и простого списка вариантов. Если форма принимает только значения из закрытого набора, используйте select; для сложной фильтрации и полного контроля соберите combobox по шаблону WAI-ARIA APG.
Совет от нашей редакции: храните в value проверяемое значение и валидируйте его при отправке формы.
Популярное за неделю
- Как создать сайт самому в 2026: 4 способа + пошаговая инструкция 34 мин чтения
- Лучшие конструкторы для создания сайтов — плюсы, минусы и сравнения 22 мин чтения
- Форма авторизации на HTML и CSS: код входа и регистрации 8 мин чтения
- Как сделать отступ в HTML: табуляция и margin 3 мин чтения
- Как посмотреть исходный HTML-код страницы в браузере 4 мин чтения
- Как редактировать html файл в Chrome 1 мин чтения
Комментарии