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

Библиотека Awesomplete не содержит встроенного механизма для работы с иконками, однако её архитектура позволяет легко интегрировать любые графические элементы внутрь списка автодополнения. Иконки могут отображаться:

  • рядом с текстом элемента;
  • перед категорией;
  • внутри поля ввода;
  • возле подсказок;
  • в списке результатов поиска;
  • внутри шаблонов item() и replace().

На практике чаще всего используются:

  • SVG-иконки;
  • шрифтовые иконки;
  • встроенные изображения;
  • CSS-псевдоэлементы;
  • сторонние библиотеки иконок.

Использование HTML внутри элементов списка

По умолчанию Awesomplete выводит обычный текст. Для вставки иконок требуется переопределить функцию item.

Пример стандартной конфигурации:

new Awesomplete(input, {
    list: ["JavaScript", "Python", "PHP"]
});

Для добавления HTML необходимо вернуть DOM-элемент:

new Awesomplete(input, {
    list: [
        {
            label: "JavaScript",
            value: "javascript"
        },
        {
            label: "Python",
            value: "python"
        }
    ],

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

        li.innerHTML = `
            <span class="icon">★</span>
            <span>${text.label}</span>
        `;

        return li;
    }
});

Результат:

<li>
    <span class="icon">★</span>
    <span>JavaScript</span>
</li>

Добавление SVG-иконок

SVG считается наиболее современным способом отображения иконок в Awesomplete.

Встроенный SVG

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

    li.innerHTML = `
        <svg class="icon" width="16" height="16" viewBox="0 0 24 24">
            <path d="M12 2L2 7l10 5 10-5z"/>
        </svg>

        <span>${text.label}</span>
    `;

    return li;
}

Стилизация SVG

.icon {
    width: 16px;
    height: 16px;
    fill: #4f46e5;
    margin-right: 8px;
    flex-shrink: 0;
}

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

Один из самых популярных вариантов — подключение Font Awesome.

Подключение CDN:

<link
    rel="stylesheet"
    href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
/>

Настройка элементов:

new Awesomplete(input, {
    list: [
        {
            label: "GitHub",
            icon: "fa-brands fa-github"
        },

        {
            label: "GitLab",
            icon: "fa-brands fa-gitlab"
        }
    ],

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

        li.innerHTML = `
            <i class="${item.icon}"></i>
            <span>${item.label}</span>
        `;

        return li;
    }
});

Выравнивание иконок и текста

Без дополнительной стилизации иконки часто смещаются относительно текста.

Правильное выравнивание:

.awesomplete li {
    display: flex;
    align-items: center;
    gap: 10px;
}

Дополнительные улучшения:

.awesomplete li i {
    width: 18px;
    text-align: center;
}

Использование изображений вместо иконок

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

Пример:

new Awesomplete(input, {
    list: [
        {
            label: "Chrome",
            image: "chrome.png"
        },

        {
            label: "Firefox",
            image: "firefox.png"
        }
    ],

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

        li.innerHTML = `
            <img src="${item.image}" class="browser-icon">
            <span>${item.label}</span>
        `;

        return li;
    }
});

CSS:

.browser-icon {
    width: 20px;
    height: 20px;
    object-fit: contain;
}

Иконки категорий

В больших списках часто используются визуальные категории.

Пример структуры данных:

[
    {
        label: "JavaScript",
        category: "Frontend",
        icon: "?"
    },

    {
        label: "Node.js",
        category: "Backend",
        icon: "?"
    }
]

Отображение:

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

    li.innerHTML = `
        <span class="category-icon">${item.icon}</span>

        <div class="content">
            <div>${item.label}</div>
            <small>${item.category}</small>
        </div>
    `;

    return li;
}

Использование CSS-псевдоэлементов

Иконки можно добавлять без изменения HTML.

Пример через ::before

.awesomplete li::before {
    content: "?";
    margin-right: 8px;
}

Использование Unicode-символов

.awesomplete li.file::before {
    content: "?";
}

.awesomplete li.folder::before {
    content: "?";
}

Назначение классов элементам

Для отображения разных иконок полезно назначать собственные классы.

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

    li.classList.add(item.type);

    li.textContent = item.label;

    return li;
}

CSS:

.awesomplete li.file::before {
    content: "?";
}

.awesomplete li.video::before {
    content: "?";
}

.awesomplete li.audio::before {
    content: "?";
}

Иконки внутри поля ввода

Иконка может находиться не только в списке, но и непосредственно внутри input.

HTML:

<div class="search-wrapper">
    <span class="search-icon">?</span>
    <input id="search">
</div>

CSS:

.search-wrapper {
    position: relative;
}

.search-icon {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
}

.search-wrapper input {
    padding-left: 36px;
}

Динамическое изменение иконок

Иконки могут зависеть от состояния элемента.

Пример:

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

    const icon = item.favorite ? "★" : "☆";

    li.innerHTML = `
        <span>${icon}</span>
        <span>${item.label}</span>
    `;

    return li;
}

Использование data-атрибутов

Иконки удобно хранить в data-* атрибутах.

li.dataset.icon = item.icon;

CSS:

.awesomplete li::before {
    content: attr(data-icon);
    margin-right: 10px;
}

Комбинирование иконок и подсветки совпадений

Awesomplete автоматически подсвечивает совпадения через <mark>.

При использовании innerHTML важно сохранить эту функциональность.

Правильный вариант:

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

    const regex = new RegExp(input, "gi");

    const highlighted = item.label.replace(regex, match => {
        return `<mark>${match}</mark>`;
    });

    li.innerHTML = `
        <span class="icon">?</span>
        <span>${highlighted}</span>
    `;

    return li;
}

Использование разных иконок для разных типов данных

Структура:

[
    {
        label: "index.html",
        type: "html"
    },

    {
        label: "styles.css",
        type: "css"
    },

    {
        label: "app.js",
        type: "js"
    }
]

Рендеринг:

item: function(item) {
    const icons = {
        html: "?",
        css: "?",
        js: "⚙️"
    };

    const li = document.createElement("li");

    li.innerHTML = `
        <span>${icons[item.type]}</span>
        <span>${item.label}</span>
    `;

    return li;
}

Использование внешних SVG-файлов

Иногда иконки загружаются как отдельные файлы.

li.innerHTML = `
    <img src="/icons/js.svg" class="icon">
    <span>${item.label}</span>
`;

CSS:

.icon {
    width: 18px;
    height: 18px;
}

Оптимизация производительности

Большое количество SVG и изображений может замедлять работу автодополнения.

Основные методы оптимизации:

Минимизация DOM

Плохо:

<li>
    <div>
        <span>
            <svg></svg>
        </span>
    </div>
</li>

Лучше:

<li>
    <svg></svg>
    <span>JavaScript</span>
</li>

Использование CSS-иконок

CSS-псевдоэлементы работают быстрее множества SVG.

.awesomplete li.js::before {
    content: "JS";
}

Кэширование SVG

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

const icons = {
    js: `<svg>...</svg>`,
    css: `<svg>...</svg>`
};

Анимация иконок

Awesomplete позволяет использовать CSS-анимации.

Эффект увеличения

.awesomplete li .icon {
    transition: transform 0.2s;
}

.awesomplete li:hover .icon {
    transform: scale(1.2);
}

Поворот

.awesomplete li:hover .icon {
    transform: rotate(10deg);
}

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

Подключение:

<link
    href="https://fonts.googleapis.com/icon?family=Material+Icons"
    rel="stylesheet"
/>

Пример:

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

    li.innerHTML = `
        <span class="material-icons">search</span>
        <span>${item.label}</span>
    `;

    return li;
}

Создание сложных элементов с иконками

Awesomplete допускает практически полноценные карточки.

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

    li.innerHTML = `
        <div class="user-card">
            <img src="${item.avatar}" class="avatar">

            <div>
                <div class="name">${item.name}</div>
                <div class="role">${item.role}</div>
            </div>

            <span class="status-icon">
                ${item.online ? "?" : "⚪"}
            </span>
        </div>
    `;

    return li;
}

CSS:

.user-card {
    display: flex;
    align-items: center;
    gap: 12px;
}

.avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
}

.status-icon {
    margin-left: auto;
}

Проблемы безопасности при использовании HTML

При вставке HTML через innerHTML существует риск XSS-атак.

Опасный код:

li.innerHTML = item.label;

Безопаснее:

const span = document.createElement("span");
span.textContent = item.label;

li.appendChild(span);

Использование шаблонных функций

Для упрощения работы с иконками удобно создавать отдельные функции.

function renderIcon(type) {
    const icons = {
        js: "?",
        php: "?",
        python: "?"
    };

    return icons[type] || "?";
}

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

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

    li.innerHTML = `
        <span>${renderIcon(item.type)}</span>
        <span>${item.label}</span>
    `;

    return li;
}

Интеграция с Bootstrap Icons

Подключение:

<link
    rel="stylesheet"
    href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css"
/>

Пример:

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

    li.innerHTML = `
        <i class="bi bi-search"></i>
        <span>${item.label}</span>
    `;

    return li;
}

Управление размерами иконок

.awesomplete li .icon {
    width: 20px;
    height: 20px;
    font-size: 20px;
}

Адаптивный вариант:

.awesomplete li .icon {
    width: clamp(14px, 2vw, 20px);
}

Использование цветных иконок

.awesomplete li.html .icon {
    color: #e34f26;
}

.awesomplete li.css .icon {
    color: #1572b6;
}

.awesomplete li.js .icon {
    color: #f7df1e;
}

Иконки загрузки

При асинхронном поиске часто используется индикатор загрузки.

HTML:

<div class="loader"></div>

CSS:

.loader {
    width: 18px;
    height: 18px;
    border: 2px solid #ccc;
    border-top-color: #333;
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

Использование inline-flex

Для точного позиционирования:

.awesomplete li {
    display: inline-flex;
    align-items: center;
}

Поддержка тёмной темы

.dark .awesomplete li .icon {
    filter: brightness(1.4);
}

SVG:

.dark .awesomplete svg {
    fill: #fff;
}