Простая поисковая строка на чистом JavaScript
Краткое: этот материал показывает, как быстро создать простую поисковую строку (searchbar) на чистом JavaScript: HTML-интерфейс, стили CSS и логика поиска в статическом массиве строк. Приведены готовые примеры, улучшения (дебаунс, подсветка совпадений, клавиатурная навигация), рекомендации по производительности и список критериев приёмки.
Введение

Поисковая строка — распространённый элемент интерфейса. Если ваш сайт хранит данные (товары, статьи, контакты), удобный поиск повышает UX и повышает конверсию. В этой статье показан минимальный рабочий пример, а также варианты улучшения и тестов. Под «минимальным» понимается реализация без бэкенда, где поиск выполняется в массиве строк на клиенте.
Важно: этот подход подходит для небольших списков (десятки — сотни элементов). Для тысяч и более следует рассматривать серверный поиск, индексы или специализированные библиотеки.
Что вы получите
- Полный рабочий пример: index.html, styles.css, script.js.
- Объяснение ключевых частей кода.
- Варианты улучшений: дебаунс, подсветка, клавиатура, локализация, доступность (ARIA).
- Контроль качества: тесты и критерии приёмки.
1. Интерфейс поисковой строки (UI)
Для начала нужен простой input, который выглядит как поисковая строка. HTML-структура минимальна: контейнер, заголовок, поле ввода и блок для списка совпадений.
Пример базового HTML (файл index.html):
Searchbar
Search Countries
Пояснения: autocomplete=”off” предотвращает родной выпадающий список браузера; onkeyup вызывает функцию поиска при каждом изменении; id=”list” — контейнер для результатов.
2. Стили для страницы и выпадающего списка
Простой CSS (файл styles.css) для читабельности и базовой зоны клика:
body {
margin: 0;
padding: 0;
background-color: #f7f7f7;
}
* {
font-family: "Arial", sans-serif;
}
.container {
padding: 100px 25%;
display: flex;
flex-direction: column;
line-height: 2rem;
font-size: 1.2em;
color: #202C39;
}
#searchbar {
padding: 15px;
border-radius: 5px;
}
input[type=text] {
-webkit-transition: width 0.15s ease-in-out;
transition: width 0.15s ease-in-out;
}
#list {
border: 1px solid lightgrey;
border-radius: 5px;
display: none; /* по умолчанию скрыто: будет показано при совпадениях */
}
.listItem {
display: flex;
flex-direction: column;
text-decoration: none;
padding: 5px 20px;
color: black;
}
.listItem:hover {
background-color: lightgrey;
}
.highlight {
background-color: #fffa8b;
}После подключения CSS откройте index.html — вы увидите поле и пустой контейнер для результатов.
3. Данные для поиска: массив строк
Для примера создадим статический массив стран в script.js и динамически добавим элементы в DOM.
Пример script.js — загрузка данных и отрисовка элементов:
function loadSearchData() {
// Данные для поиска
let countries = [
'Australia',
'Austria',
'Brazil',
'Canada',
'Denmark',
'Egypt',
'France',
'Germany',
'USA',
'Vietnam'
];
// Получаем HTML-элемент списка
let list = document.getElementById('list');
// Добавляем каждую строку как
countries.forEach((country)=>{
let a = document.createElement("a");
a.innerText = country;
a.classList.add("listItem");
a.setAttribute('href', '#');
list.appendChild(a);
})
}Этот код должен быть подключён внизу body, либо вызывать loadSearchData при событии загрузки, как показано выше.
4. Логика поиска: показать совпадающие элементы
Добавим функцию search(), которая будет вызываться на onkeyup. Идея: получить текущее значение input, пробежать по всем элементам списка и отфильтровать видимость.
Пример реализации:
function search() {
let listContainer = document.getElementById('list');
let listItems = document.getElementsByClassName('listItem');
let input = document.getElementById('searchbar').value;
input = input.toLowerCase();
let noResults = true;
for (let i = 0; i < listItems.length; i++) {
let itemText = listItems[i].innerHTML.toLowerCase();
if (!itemText.includes(input) || input === "") {
listItems[i].style.display = "none";
continue;
} else {
listItems[i].style.display = "flex";
noResults = false;
}
}
listContainer.style.display = noResults ? "none" : "block";
}После ввода текста список будет обновляться в реальном времени и показывать только те элементы, которые содержат введённую подстроку.
5. Частые улучшения и варианты реализации
Ниже — практические улучшения, которые обычно внедряют в производственных приложениях.
5.1 Дебаунс (снижение частоты вызовов)
Проблема: при быстром наборе символов функция search вызывается слишком часто. Решение — дебаунс: запускать поиск только через N миллисекунд после последнего ввода.
Пример простого дебаунса:
let debounceTimer;
function onInputDebounced() {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(() => search(), 250); // 250 мс
}
// В HTML: onkeyup="onInputDebounced()"5.2 Подсветка совпадений
Чтобы пользователю было легче увидеть совпадение, можно оборачивать совпадающую часть в span с классом highlight.
Пример: внутри цикла в search() заменять HTML элемента так:
let idx = itemText.indexOf(input);
if (idx !== -1) {
let original = listItems[i].innerText;
let before = original.slice(0, idx);
let match = original.slice(idx, idx + input.length);
let after = original.slice(idx + input.length);
listItems[i].innerHTML = `${before}${match}${after}`;
}5.3 Клавиатурная навигация
Добавьте обработку клавиш ArrowUp, ArrowDown и Enter: фокус на элементах списка, возможность выбора клавишей Enter. Это важно для доступности и ускорения работы.
Короткий алгоритм:
- Отслеживать индекс выбранного элемента.
- При ArrowDown увеличивать индекс и добавлять класс active.
- При Enter — переход по ссылке или заполнение input.
5.4 Поиск по объектам (не только строки)
Если ваши элементы — объекты (например, {id, name, tags}), то сравнивайте по нужному полю: item.name.toLowerCase().includes(input). Для сложных требований — используйте фильтрацию по нескольким полям и ранжирование.
5.5 Серверный поиск и пагинация
Для больших наборов делайте запросы на сервер с параметром q; на сервере — индексируйте текст (search index) или используйте поисковые движки (Elasticsearch, Algolia). Клиент получает только ограниченное количество результатов (пагинация) и дополняет по необходимости.
6. Доступность (Accessibility)
- Добавьте role=”listbox” для контейнера результатов и role=”option” для элементов.
- Управляйте атрибутом aria-expanded у поля ввода.
- Обеспечьте контраст и фокус-стили для активного элемента.
- Используйте semantic HTML: ul > li или элементы с понятными href.
Пример ARIA-атрибутов:
В скрипте обновляйте aria-expanded в зависимости от наличия результатов.
7. Локализация и регистрозависимость
При поиске учитывайте локаль: для языков с диакритикой используйте нормализацию строк:
function normalize(str) {
return str.normalize('NFD').replace(/\p{Diacritic}/gu, '').toLowerCase();
}Это позволит корректно сопоставлять, например, «é» и «e». Для языков со специфичными правилами сортировки и сравнения используйте Intl.Collator.
8. Тестирование и критерии приёмки
Критерии приёмки (обязательные):
- Поле ввода отображается и принимает ввод.
- При вводе отображаются только совпадающие элементы; при пустом вводе список скрыт.
- Доступность: можно навигировать клавишами (Tab, стрелки, Enter).
- Подсветка совпадений корректна и не ломает разметку.
- Производительность: при 200 элементах интерфейс остаётся отзывчивым; при 10 000 — требуется измерение и переход на серверный поиск.
Тесты (ручные и автоматические):
- Ввод «a» показывает ожидаемые элементы.
- Быстрый ввод не вызывает «подергиваний» UI (проверить с и без дебаунса).
- Переход по клавишам выделяет элементы и Enter активирует выбранный.
- Проверка с Unicode-символами и диакритикой.
9. Когда этот подход не годится (ограничения)
- Большие объёмы данных (> тысячи записей): клиентский фильтр медленен и потребляет RAM.
- Нужна полнотекстовая релевантность, синонимы или морфология — нужен поисковый движок.
- Секретные данные, которые не должны быть на клиенте — нельзя помещать весь массив в браузер.
10. Альтернативные подходы
- Клиентские библиотеки: Fuse.js (fuzzy search), Lunr.js.
- Облачные поисковые сервисы: Algolia, Elasticsearch (Hosted).
- Комбинированный: автодополнение на клиенте + серверный поиск при сложных запросах.
11. Рекомендации по производству (мини-процесс)
- Прототип: реализовать базовую версию на статическом массиве.
- Замеры: протестировать на реальных данных (объёмы и латентность).
- Улучшения: добавить дебаунс, подсветку, клавиатурную навигацию и ARIA.
- Перенос на сервер: когда объёмы или требования релевантности превысят возможности клиента.
12. Быстрые сниппеты и чек-листы
Чек-лист разработчика перед релизом:
- ARIA-атрибуты и фокусные стили.
- Дебаунс для событий ввода.
- Обработка пустого ввода и «нет результатов».
- Тесты на Unicode/диакритику.
- Клавиатурная доступность и мобильные тесты.
Полезный сниппет: очистка списка и заполнение заново (альтернативный подход для динамики):
function renderResults(matches) {
const list = document.getElementById('list');
list.innerHTML = ''; // очищаем
matches.forEach(m => {
const a = document.createElement('a');
a.className = 'listItem';
a.href = '#';
a.innerText = m;
list.appendChild(a);
});
}13. Безопасность и конфиденциальность
- При вставке HTML (подсветка) избегайте XSS: используйте textContent или безопасную экранизацию.
- Не кладите конфиденциальные данные (персональные, токены) в массивы, доступные из клиентского JS.
14. Локальные особенности для русскоязычных проектов
- Нормализация диакритики редко нужна, но учтите букву ё vs е и разницу в регистре.
- Подумайте о склонениях: для расширенного поиска можно применить простую стемминг-библиотеку.
Резюме
Важно: простая клиентская поисковая строка на Vanilla JS отлично подходит для прототипов и небольших списков. При росте объёма данных или требований к релевантности следует использовать серверный поиск или готовые библиотеки. Внедрите дебаунс, подсветку и ARIA для улучшенного UX.
Важно
- Для больших наборов данных планируйте серверный поиск.
- Всегда учитывайте доступность и защиту от XSS.
Критерии приёмки
- Поле ввода отвечает на ввод.
- Список корректно фильтруется и скрывается при пустом запросе.
- Клавиатурная навигация и ARIA реализованы.
Ссылки и следующее чтение
- Рассмотрите Fuse.js для нечёткого поиска.
- Для крупных проектов — Algolia или Elasticsearch.
Короткое объявление (для команды)
Прототип поисковой строки на чистом JavaScript готов: включает UI, фильтрацию по строкам, подсветку и рекомендации по улучшению. Для продакшна добавить дебаунс, ARIA и рассмотреть серверный поиск при больших объёмах.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента