Автозаполнение поля: 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` хуже виджета?
Внешний вид почти не поддаётся стилизации, поведение отличается между браузерами, а фильтрация только по подстроке с начала — своей логики не задать. Зато ноль JavaScript и доступность из коробки.
Почему при вводе улетает сто запросов на сервер?
Потому что нет задержки. Нужен debounce: ждать паузу в наборе и только потом запрашивать. У jQuery UI для этого есть delay, в своём коде — setTimeout с очисткой.
Как отменить запрос, который устарел?
AbortController. Иначе ответы приходят вразнобой, и результат по старому запросу может перезаписать актуальный — это гонка, а не редкость.
Что взять для автодополнения в 2026?
Простой список вариантов — datalist. Нужны стилизация, своя фильтрация и подсветка — свой компонент на input + список, с debounce и AbortController. Ради одного поля тянуть jQuery UI не стоит.