Библиотека Awesomplete не содержит встроенного механизма для работы с иконками, однако её архитектура позволяет легко интегрировать любые графические элементы внутрь списка автодополнения. Иконки могут отображаться:
item() и replace().На практике чаще всего используются:
По умолчанию 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 считается наиболее современным способом отображения иконок в Awesomplete.
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;
}
.icon {
width: 16px;
height: 16px;
fill: #4f46e5;
margin-right: 8px;
flex-shrink: 0;
}
Один из самых популярных вариантов — подключение 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;
}
Иконки можно добавлять без изменения HTML.
::before.awesomplete li::before {
content: "?";
margin-right: 8px;
}
.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-* атрибутах.
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;
}
Иногда иконки загружаются как отдельные файлы.
li.innerHTML = `
<img src="/icons/js.svg" class="icon">
<span>${item.label}</span>
`;
CSS:
.icon {
width: 18px;
height: 18px;
}
Большое количество SVG и изображений может замедлять работу автодополнения.
Основные методы оптимизации:
Плохо:
<li>
<div>
<span>
<svg></svg>
</span>
</div>
</li>
Лучше:
<li>
<svg></svg>
<span>JavaScript</span>
</li>
CSS-псевдоэлементы работают быстрее множества SVG.
.awesomplete li.js::before {
content: "JS";
}
При большом количестве элементов полезно хранить 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);
}
Подключение:
<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 через 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;
}
Подключение:
<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);
}
}
Для точного позиционирования:
.awesomplete li {
display: inline-flex;
align-items: center;
}
.dark .awesomplete li .icon {
filter: brightness(1.4);
}
SVG:
.dark .awesomplete svg {
fill: #fff;
}