Стилизация элементов списка

Выпадающий список в Awesomplete строится как обычный HTML-элемент <ul> с набором <li>, что делает его полностью контролируемым через CSS и JavaScript. Архитектура библиотеки преднамеренно минималистична: визуальная часть не абстрагирована сложными компонентами, а оставлена в виде стандартной DOM-структуры, что упрощает глубокую стилизацию.

В момент активации автодополнения Awesomplete создаёт или использует уже существующий элемент списка:

<ul class="awesomplete" role="listbox">
    <li role="option">Элемент 1</li>
    <li role="option">Элемент 2</li>
</ul>

Каждый пункт списка является отдельным DOM-узлом. Это означает, что стилизация не ограничивается контейнером — можно управлять как всем списком, так и отдельными элементами.

Ключевая особенность заключается в том, что библиотека не навязывает сложную систему тем, а предоставляет набор классов и состояний, которые можно свободно переопределять.

Базовые CSS классы

Основные классы, используемые Awesomplete:

  • .awesomplete — контейнер списка
  • .awesomplete > ul — непосредственно список
  • .awesomplete > ul > li — элемент списка
  • .awesomplete [aria-selected="true"] — активный элемент

Минимальная базовая стилизация может выглядеть следующим образом:

.awesomplete {
    position: relative;
}

.awesomplete ul {
    position: absolute;
    top: 100%;
    left: 0;
    z-index: 1000;
    list-style: none;
    margin: 0;
    padding: 0;
    background: #fff;
    border: 1px solid #ccc;
    width: 100%;
}

.awesomplete ul li {
    padding: 8px 12px;
    cursor: pointer;
}

Такая структура задаёт основу, на которую накладываются состояния взаимодействия.

Состояния элементов списка

В Awesomplete состояния элементов реализуются через атрибуты и псевдоклассы:

Наведение курсора

.awesomplete ul li:hover {
    background: #f0f0f0;
}

Активный (выбранный клавиатурой) элемент

.awesomplete ul li[aria-selected="true"] {
    background: #2d7ef7;
    color: #fff;
}

Использование aria-selected позволяет синхронизировать визуальное состояние с доступностью (accessibility). Библиотека обновляет этот атрибут при навигации стрелками.

Скрытое состояние списка

.awesomplete[hidden] {
    display: none;
}

или

.awesomplete:not(.open) {
    display: none;
}

(в зависимости от конфигурации и версии поведения).

Стилизация структуры контейнера

Контейнер списка в Awesomplete часто позиционируется абсолютно относительно поля ввода:

.awesomplete {
    display: block;
}

.awesomplete ul {
    box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    border-radius: 6px;
    overflow: hidden;
}

Важный аспект — управление перекрытием:

.awesomplete ul {
    max-height: 240px;
    overflow-y: auto;
}

Это предотвращает выход списка за пределы экрана при большом количестве элементов.

Переопределение шаблона элементов

Awesomplete позволяет переопределять способ рендеринга элементов через item функцию:

new Awesomplete(input, {
    list: ["Apple", "Apricot", "Avocado"],
    item: function(text, input) {
        const li = document.createElement("li");
        li.textContent = text;
        return li;
    }
});

Это даёт возможность добавлять дополнительные элементы внутрь <li>:

item: function(text) {
    const li = document.createElement("li");

    const title = document.createElement("span");
    title.textContent = text;

    const meta = document.createElement("small");
    meta.textContent = "фрукт";

    li.appendChild(title);
    li.appendChild(meta);

    return li;
}

Такой подход полностью снимает ограничения стандартного отображения.

HTML-разметка внутри элементов

При кастомном рендеринге в Awesomplete можно формировать сложную структуру:

item: function(text) {
    const li = document.createElement("li");

    li.innerHTML = `
        <div class="item-row">
            <span class="title">${text}</span>
            <span class="badge">match</span>
        </div>
    `;

    return li;
}

CSS для подобной структуры:

.awesomplete li .item-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.awesomplete li .badge {
    font-size: 10px;
    padding: 2px 6px;
    background: #eee;
    border-radius: 10px;
}

Подсветка совпадений

Встроенный механизм подсветки в Awesomplete использует регулярные выражения для выделения совпавших частей строки.

Базовый CSS для подсветки:

.awesomplete mark {
    background: yellow;
    color: inherit;
}

HTML-структура формируется автоматически:

<li>App<mark>le</mark></li>

Можно переопределить поведение через filter и replace:

new Awesomplete(input, {
    list: ["Apple", "Banana"],
    replace: function(suggestion) {
        this.input.value = suggestion;
    }
});

Стилизация при фокусе и клавиатурной навигации

Клавиатурная навигация в Awesomplete опирается на индекс активного элемента. Это позволяет применять стили без Jav * aScript:

.awesomplete ul li {
    transition: background 0.15s ease;
}

.awesomplete ul li[aria-selected="true"] {
    transform: translateX(2px);
}

Дополнительный визуальный эффект можно добавить через псевдоэлементы:

.awesomplete ul li[aria-selected="true"]::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 3px;
    background: #2d7ef7;
}

Адаптивность списка

В Awesomplete адаптивность достигается через стандартные CSS-механизмы:

.awesomplete ul {
    width: 100%;
    min-width: 200px;
    max-width: 100%;
}

@media (max-width: 600px) {
    .awesomplete ul {
        font-size: 14px;
    }

    .awesomplete ul li {
        padding: 10px;
    }
}

Темизация через CSS переменные

Гибкая стилизация может быть построена на CSS custom properties:

:root {
    --awesomplete-bg: #ffffff;
    --awesomplete-border: #ddd;
    --awesomplete-hover: #f5f5f5;
    --awesomplete-active: #2d7ef7;
}

Использование:

.awesomplete ul {
    background: var(--awesomplete-bg);
    border: 1px solid var(--awesomplete-border);
}

.awesomplete ul li:hover {
    background: var(--awesomplete-hover);
}

.awesomplete ul li[aria-selected="true"] {
    background: var(--awesomplete-active);
    color: #fff;
}

Такой подход позволяет менять внешний вид без модификации логики Awesomplete.

Управление состоянием через классы

Хотя библиотека опирается на атрибуты, часто добавляются собственные классы для расширенной стилизации:

input.addEventListener("awesomplete-open", () => {
    input.classList.add("is-open");
});

input.addEventListener("awesomplete-close", () => {
    input.classList.remove("is-open");
});

CSS:

.awesomplete.is-open {
    z-index: 9999;
}

Работа с переполнением и скроллом

При большом списке Awesomplete важно управлять поведением прокрутки:

.awesomplete ul {
    max-height: 300px;
    overflow-y: auto;
    scrollbar-width: thin;
}

Для WebKit:

.awesomplete ul::-webkit-scrollbar {
    width: 6px;
}

.awesomplete ul::-webkit-scrollbar-thumb {
    background: #ccc;
    border-radius: 3px;
}

Интеграция кастомных иконок

Каждый <li> может содержать иконки без ограничений:

item: function(text) {
    const li = document.createElement("li");

    li.innerHTML = `
        <svg class="icon" width="14" height="14"></svg>
        <span>${text}</span>
    `;

    return li;
}

CSS:

.awesomplete li .icon {
    margin-right: 6px;
    opacity: 0.6;
}

Такая структура часто используется для отображения типов данных (файлы, пользователи, категории).

Гибридная стилизация через data-атрибуты

Дополнительные данные можно передавать через data-*:

li.dataset.type = "user";

CSS:

.awesomplete li[data-type="user"] {
    font-weight: 600;
}

.awesomplete li[data-type="file"] {
    font-style: italic;
}

В Awesomplete такой подход позволяет строить сложные интерфейсы без изменения ядра библиотеки.