Как сделать простой поисковый бар на JavaScript

Поисковая строка — привычный элемент интерфейса, который полезен на любых сайтах с данными. В этой инструкции показан минимальный, понятный и полностью клиентский пример на HTML/CSS/JavaScript. Мы создадим: интерфейс, статический список строк и простую логику фильтрации, которая обновляет выпадающий список при вводе.
Важно: этот подход работает хорошо для небольших статических списков. Для больших наборов данных или динамических источников потребуется оптимизация (дебаунс, поиск на сервере, пагинация).
Что вы получите
- Рабочий пример поисковой строки с выпадающим списком.
- Пошаговые инструкции по HTML, CSS и JS файлам.
- Советы, когда использовать клиентскую фильтрацию, а когда — серверный поиск.
- Чек-листы, тест-кейсы и критерии приёмки.
Как добавить интерфейс для поисковой строки
Ваш сайт должен содержать поле ввода, где пользователь набирает поисковый запрос. Проще всего использовать и стилизовать его как поисковую строку.
- Создайте папку для сайта. Внутри создайте файл index.html.
- Заполните файл базовой структурой HTML. Пример:
Searchbar
- Внутри div.container добавьте input. При каждом вводе символа будет вызываться функция search(), которую мы реализуем позже.
Search Countries
Примечание: атрибут autocomplete=”off” предотвращает автозаполнение браузера на основе прошлых вводов.
- Создайте файл 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;
}- Подключите CSS в head index.html:
- Откройте index.html в браузере и проверьте интерфейс.

Как создать массив строк для поиска
Перед поиском нужно иметь набор данных. В простейшем случае это массив строк (Array of strings). Мы динамически создадим список элементов в DOM при загрузке страницы.
- Под полем ввода добавьте div, в котором будет отображаться выпадающий список:
- Создайте файл script.js в той же папке.
- В script.js объявите функцию loadSearchData() и инициализируйте массив строк. Это небольшой статический пример:
function loadSearchData() {
// Data to be used in the searchbar
let countries = [
'Australia',
'Austria',
'Brazil',
'Canada',
'Denmark',
'Egypt',
'France',
'Germany',
'USA',
'Vietnam'
];
}- Внутри loadSearchData() найдите элемент списка и добавьте для каждого элемента массива тег :
// Get the HTML element of the list
let list = document.getElementById('list');
// Add each data item as an tag
countries.forEach((country)=>{
let a = document.createElement("a");
a.innerText = country;
a.classList.add("listItem");
list.appendChild(a);
})- В теле index.html добавьте атрибут onload, чтобы вызвать loadSearchData() при загрузке:
- В конце тела подключите script.js:
- Добавьте стили для выпадающего списка в styles.css:
#list {
border: 1px solid lightgrey;
border-radius: 5px;
display: block;
}
.listItem {
display: flex;
flex-direction: column;
text-decoration: none;
padding: 5px 20px;
color: black;
}
.listItem:hover {
background-color: lightgrey;
}- Откройте index.html — вы увидите список всех элементов (поиск ещё не работает).

Как сделать выпадающий список с совпадающими результатами
Теперь добавим логику фильтрации, чтобы при вводе показывались только совпадающие элементы.
- Сначала скройте список по умолчанию (замените display: block на display: none):
#list {
border: 1px solid lightgrey;
border-radius: 5px;
display: none;
}- В script.js создайте функцию search(), которая будет вызываться при каждом нажатии клавиши:
function search() {
// search functionality goes here
}- Внутри search() получите контейнер списка и элементы с классом listItem:
let listContainer = document.getElementById('list');
let listItems = document.getElementsByClassName('listItem');- Получите текущее значение инпута и приведите его к нижнему регистру:
let input = document.getElementById('searchbar').value
input = input.toLowerCase();- Сравните введённый текст с каждым элементом списка. Если элемент содержит подстроку — покажите его, иначе скройте:
let noResults = true;
for (i = 0; i < listItems.length; i++) {
if (!listItems[i].innerHTML.toLowerCase().includes(input) || input === "") {
listItems[i].style.display="none";
continue;
}
else {
listItems[i].style.display="flex";
noResults = false;
}
}- Если совпадений нет, скрывайте контейнер целиком:
listContainer.style.display = noResults ? "none" : "block";- Проверьте в браузере: откройте index.html и начните вводить текст — список будет обновляться.

Как использовать выбранный результат
Вы можете превратить каждый элемент в ссылку на страницу или в элемент, который при клике заполняет инпут:
- Для перехода на страницу добавьте href к .
- Для автозаполнения инпута и закрытия списка — в обработчике клика присвойте input.value = this.innerText и спрячьте список.
Пример добавления обработчика при генерации списка:
countries.forEach((country)=>{
let a = document.createElement("a");
a.innerText = country;
a.classList.add("listItem");
a.href = "#"; // можно указать реальную ссылку
a.addEventListener('click', function(e){
e.preventDefault();
document.getElementById('searchbar').value = this.innerText;
document.getElementById('list').style.display = 'none';
});
list.appendChild(a);
})Когда этот подход не подойдёт
Important: клиентская фильтрация хороша для небольших наборов (< несколько тысяч строк) и когда данные статичны. Она не подойдёт, если:
- Данные слишком большие (производительность и потребление памяти).
- Нужен поиск по множеству полей или сложная релевантность.
- Требуется учёт пользовательских прав и приватных данных (поиск должен выполняться на бэкенде).
В таких случаях используйте серверный поиск, полнотекстовый движок (Elasticsearch, Typesense) или сторонние API.
Альтернативные подходы
- Дебаунсинг ввода: задержка перед запуском поиска, чтобы уменьшить количество операций.
- Поиск на сервере: отправлять запросы по мере ввода (с пагинацией).
- Использование библиотек автодополнения: Awesomplete, Algolia Autocomplete, Downshift (для React).
- Индексирование на клиенте: Lunr.js для небольших статических сайтов.
Пошаговая мини-методология (быстрая проверка перед релизом)
- Реализовать базовую версию (UI + статический список + фильтр).
- Протестировать на 100–1000 строк. Оценить время отклика и потребление памяти.
- Добавить дебаунс (например, 200–400 мс) если запуски search() происходят слишком часто.
- Если данные > 5000 строк — перенести поиск на сервер или использовать индекс.
- Добавить обработку клавиатуры (стрелки, Enter, Esc) для улучшения UX.
Чек-листы по ролям
Дизайнер:
- Проверить видимость поля на мобильных устройствах.
- Убедиться, что цвет фона и hover-контраст соответствуют WCAG.
Фронтенд-разработчик:
- Реализовать aria-атрибуты (role=”listbox”, aria-expanded, aria-activedescendant).
- Обработать клавиши вверх/вниз/Enter/Escape.
- Добавить тесты на фильтрацию и клики.
QA-инженер:
- Тестировать поведение при пустом вводе, при специальных символах, при вводе в разном регистре.
- Тестировать на мобильных браузерах.
Критерии приёмки
- При пустом инпуте список скрыт.
- При вводе строки отображаются только элементы, содержащие эту подстроку (без учёта регистра).
- Клик по элементу заполняет инпут и закрывает список (если предусмотрено).
- Навигация по клавишам работает: стрелки изменяют выбранный элемент, Enter подтверждает.
Тест-кейсы / Приёмочные сценарии
- Ввод “a” показывает все элементы с буквой “a”.
- Ввод “zz” показывает пустой результат и список скрыт.
- Клик по элементу заполняет инпут и прячет список.
- Нажатие Escape закрывает список без изменения инпута.
- Навигация стрелками подсвечивает элементы, Enter выбирает подсвеченный элемент.
Безопасность и приватность
- Не храните чувствительные данные в клиентских списках. Если поиск затрагивает приватную информацию — выполняйте его на сервере с проверкой прав.
- Обход XSS: если вы вставляете значения в innerHTML — экранируйте/очищайте данные. В нашем примере используем innerText, что безопаснее.
Ограничения и кейсы-края
- Поиск чувствителен к диакритике — вы можете нормализовать строки через .normalize(‘NFD’).replace(/\p{Diacritic}/gu, ‘’) для сравнения.
- Для языков с неудобным разбиением слов (например, китайский) потребуется иная логика токенизации.
Короткая сводка
- Простая клиентская фильтрация — быстрый способ добавить поиск на сайт с небольшими наборами данных.
- Для больших данных и требований к релевантности используйте серверный поиск или индекс.
- Обязательно протестируйте UX на клавиатуре и мобильных устройствах.
Сводка основных действий: реализуйте HTML-инпут, динамически заполните список, реализуйте search(), улучшите UX клавиатурой и защитой данных.
1‑строчный глоссарий
- Debounce — задержка между серией быстрых вызовов функции, чтобы выполнить её один раз после паузы.
- Client-side search — поиск, выполняемый в браузере без обращения к серверу.
- Server-side search — поиск, выполняемый на сервере; подходит для больших данных и контроля доступа.
Краткая инструкция по расширению: добавьте debounce для search(), aria-атрибуты для доступности, и замените статический массив на fetch() запрос к API при необходимости.
Похожие материалы
RDP: полный гид по настройке и безопасности
Android как клавиатура и трекпад для Windows
Советы и приёмы для работы с PDF
Calibration в Lightroom Classic: как и когда использовать
Отключить Siri Suggestions на iPhone