Автозаполнение поля: jQuery UI Autocomplete и datalist
Содержание
О проверке кода. Примеры не запускались в браузере — в отличие от материалов по Node.js, где приводится фактический вывод. Код дан по документации jQuery UI и MDN. Говорим прямо, а не ставим бейдж «проверено» без проверки.
Автодополнение в поле — задача, где за девять лет изменился не синтаксис, а сам ответ на вопрос «чем это делать».
Виджет jQuery UI
$('#city').autocomplete({
source: ['Москва', 'Казань', 'Пермь', 'Сочи'],
minLength: 2,
delay: 300,
select: (event, ui) => console.log('выбрано:', ui.item.value),
});
// с сервера
$('#city').autocomplete({
source: '/api/cities', // получит ?term=введённое
minLength: 2,
delay: 300,
});
Работает, и delay: 300 здесь неспроста — это встроенный debounce. Ключевые опции: source (массив, URL или функция), minLength, delay, select.
Но jQuery UI сегодня в режиме поддержки. Критические правки выходят, развития нет. Это не «сломается завтра» — это «не берите в новый проект».
Нативный datalist: ноль JavaScript
Большинство не знает, что у браузера есть встроенное автодополнение:
<input list="cities" id="city">
<datalist id="cities">
<option value="Москва">
<option value="Казань">
<option value="Пермь">
</datalist>
Ни строки JavaScript. Работает везде, доступно с клавиатуры и для скринридеров из коробки.
Честные ограничения:
- почти не стилизуется — выпадающий список рисует браузер, и он выглядит по-своему в каждом;
- фильтрация только встроенная — своя логика (по синонимам, с опечатками, с подсветкой) невозможна;
- поведение различается между браузерами: где-то список показывается сразу, где-то после ввода.
Если нужен просто список подсказок и дизайн не критичен — это правильный ответ. Половина случаев закрывается им.
Свой компонент: две вещи, о которых забывают
Когда нужны стилизация и своя логика, пишут руками. Это не сложно — сложно не наступить на две мины.
Мина первая: запрос на каждый символ
// ❌ «Москва» = шесть запросов на сервер
input.addEventListener('input', async (e) => {
const res = await fetch(`/api/cities?term=${e.target.value}`);
render(await res.json());
});
Пользователь печатает — улетает запрос на каждую букву. При сотне пользователей сервер получает шквал, из которого нужен только последний ответ.
// ✅ debounce: ждём паузу в наборе
let timer;
input.addEventListener('input', (e) => {
clearTimeout(timer);
timer = setTimeout(() => search(e.target.value), 300);
});
Это ровно то, что делает delay: 300 в jQuery UI. Просто в своём коде о нём нужно помнить.
Мина вторая: ответы приходят вразнобой
Даже с debounce остаётся гонка, и она коварнее:
// пользователь напечатал "Мо", потом "Мос"
// запрос "Мо" ушёл первым, но ответ пришёл ВТОРЫМ
// в списке — подсказки для "Мо", хотя в поле "Мос"
Сеть не гарантирует порядок ответов. Медленный ответ по старому запросу перезапишет актуальный.
// ✅ отменяем предыдущий запрос
let controller;
async function search(term) {
controller?.abort(); // старый запрос больше не нужен
controller = new AbortController();
try {
const res = await fetch(`/api/cities?term=${encodeURIComponent(term)}`,
{ signal: controller.signal });
render(await res.json());
} catch (err) {
if (err.name !== 'AbortError') throw err; // отмена — не ошибка
}
}
Тот же AbortController, что отменяет операции в Node — механизм общий для платформы.
И обязательно encodeURIComponent: без него пробел или & в запросе развалят URL.
Что выбрать
<datalist>
Простой список вариантов
- Ноль JavaScript
- Доступность из коробки
- Не стилизуется
- Своя фильтрация невозможна
- Берите, если дизайн не критичен
Свой компонент
Нужны вид и логика
- Полный контроль
- Обязательны
debounceиAbortController - Доступность пишете сами:
aria-expanded, стрелки, Escape - ~50 строк кода
jQuery UI Autocomplete
Только если jQuery UI уже в проекте
delayи клавиатура готовы- Проект в режиме поддержки
- Тянет jQuery + jQuery UI
- Для нового кода — нет
Отдельно про доступность своего компонента: это та часть, где виджеты реально экономят время. Навигация стрелками, Escape, role="combobox", aria-expanded, aria-activedescendant — всё пишется руками. Пропустить легко, и тогда поле не работает с клавиатуры.
Что было на этой странице в 2017 году
Первая версия вышла 2 августа 2017 года и разбирала виджет jQuery UI: опции, источники данных, события. Для своего времени — правильный ответ: datalist тогда поддерживался неровно, а писать своё означало возиться с кроссбраузерностью.
Что изменилось за девять лет:
- jQuery UI перешёл в режим поддержки. Не сломался — просто перестал развиваться, как Sails.js и Memcached. Та же история: технологию не убили, её перестали выбирать.
datalistдозрел. Теперь он закрывает простой случай без единой строки кода — вариант, которого в статье не было вовсе.AbortControllerпоявился в платформе. В 2017-м отменить запрос было нечем; гонку ответов либо терпели, либо городили флаги. Сегодня это одна строка.
Синтаксис виджета не устарел. Устарело то, что он был единственным вариантом.
Смежные темы: изменение стилей; изменить содержимое элемента — про безопасную вставку подсказок; промисы и AbortController; уроки JavaScript.
Частые вопросы
jQuery UI ещё поддерживается?
Чем `datalist` хуже виджета?
Почему при вводе улетает сто запросов на сервер?
delay, в своём коде — setTimeout с очисткой.Как отменить запрос, который устарел?
AbortController. Иначе ответы приходят вразнобой, и результат по старому запросу может перезаписать актуальный — это гонка, а не редкость.Что взять для автодополнения в 2026?
datalist. Нужны стилизация, своя фильтрация и подсветка — свой компонент на input + список, с debounce и AbortController. Ради одного поля тянуть jQuery UI не стоит.