Автодополнение в интерфейсах с направлением текста справа налево (RTL) требует учета не только визуального отображения, но и поведения ввода, курсора и позиционирования выпадающего списка. В контексте Awesomplete эти аспекты проявляются особенно заметно, поскольку библиотека изначально ориентирована на LTR-сценарии, но допускает адаптацию через CSS и кастомизацию логики.
RTL-языки включают арабский, иврит, персидский и ряд других систем письма, где направление текста влияет на:
Основной механизм переключения направления текста задается через атрибут:
<input class="awesomplete" dir="rtl" />
или на уровне контейнера:
<div dir="rtl">
<input class="awesomplete" />
</div>
Awesomplete не требует специальной конфигурации для работы с
dir="rtl", однако визуальное поведение компонентов
меняется.
Ключевой момент: библиотека не управляет направлением текста, она опирается на браузерный rendering engine. Это означает, что корректность RTL во многом зависит от CSS и поведения input-элемента.
В стандартной реализации Awesomplete dropdown позиционируется относительно input слева направо. В RTL-сценариях это может приводить к следующим эффектам:
Решение заключается в переопределении CSS:
.awesomplete [role="listbox"] {
left: auto;
right: 0;
text-align: right;
}
Дополнительно может потребоваться:
.awesomplete {
direction: rtl;
}
.awesomplete ul {
direction: rtl;
}
Важно учитывать, что Awesomplete использует абсолютное
позиционирование, поэтому left/right должны быть строго
согласованы.
В RTL-интерфейсах критично обеспечить единое направление для:
Базовая настройка:
.awesomplete input {
text-align: right;
direction: rtl;
}
.awesomplete li {
text-align: right;
}
При этом внутреннее форматирование подсветки (например,
<mark> или кастомные шаблоны) также должно
наследовать направление:
.awesomplete mark {
background: transparent;
font-weight: bold;
}
Awesomplete использует строковые операции для фильтрации списка. В RTL-языках это приводит к дополнительным нюансам:
Стандартный фильтр:
Awesomplete.FILTER_CONTAINS = function (text, input) {
return text.toLowerCase().includes(input.trim().toLowerCase());
};
Для RTL-языков более устойчивый вариант:
function normalize(str) {
return str
.normalize("NFKC")
.replace(/\u200f|\u200e/g, ""); // удаление directional marks
}
Awesomplete.FILTER_CONTAINS = function (text, input) {
return normalize(text)
.toLowerCase()
.includes(normalize(input).toLowerCase());
};
В RTL-интерфейсах важно контролировать порядок частей строки, особенно если используются комбинации “имя + описание” или “значение + код”.
Awesomplete позволяет переопределить форматирование через
item:
new Awesomplete(input, {
list: [
"موسكو - Москва",
"الرياض - Riyadh",
"القاهرة - Cairo"
],
item: function (text, input) {
const li = document.createElement("li");
li.textContent = text;
li.style.direction = "rtl";
li.style.textAlign = "right";
return li;
}
});
В RTL-среде часто требуется инвертировать порядок отображения:
function formatCity(item) {
const [native, latin] = item.split(" - ");
return `${latin} — ${native}`;
}
Awesomplete использует стандартное поведение input-элемента для вставки значения. В RTL-полях возможны эффекты:
Для стабилизации поведения применяется принудительная нормализация направления:
input.addEventListener("awesomplete-selectcomplete", function () {
this.setAttribute("dir", "rtl");
this.style.direction = "rtl";
this.style.textAlign = "right";
});
Awesomplete подсвечивает совпадения через
<mark>-элементы. В RTL-режиме важно учитывать, что
визуальная подсветка может не совпадать с логическим порядком
строки.
Расширенный вариант фильтрации и подсветки:
Awesomplete.ITEM = function (text, input) {
const li = document.createElement("li");
li.dir = "rtl";
const index = text.toLowerCase().indexOf(input.toLowerCase());
if (index >= 0) {
li.innerHTML =
text.substring(0, index) +
"<mark>" +
text.substring(index, index + input.length) +
"</mark>" +
text.substring(index + input.length);
} else {
li.textContent = text;
}
return li;
};
При работе с RTL важно помнить, что визуальный порядок может не совпадать с индексами строки.
Частая ситуация — сочетание арабского текста и латинских идентификаторов:
В таких случаях возникают проблемы bidi-алгоритма браузера. Решение — использование изолирующих символов:
function bidiSafe(text) {
return "\u2068" + text + "\u2069";
}
И применение в списке:
list: data.map(item => bidiSafe(item))
Если страница поддерживает переключение LTR/RTL динамически, Awesomplete требует пересчета позиции:
function updateDirection(input, isRTL) {
input.setAttribute("dir", isRTL ? "rtl" : "ltr");
const aw = input.awesomplete;
if (aw) {
aw.open();
aw.close();
}
}
Дополнительно полезно принудительно сбрасывать inline-стили:
const list = document.querySelector(".awesomplete [role='listbox']");
list.style.left = "";
list.style.right = isRTL ? "0" : "auto";
Сводная конфигурация, обеспечивающая предсказуемое поведение:
.awesomplete {
direction: rtl;
width: 100%;
}
.awesomplete input {
direction: rtl;
text-align: right;
}
.awesomplete [role="listbox"] {
direction: rtl;
right: 0;
left: auto;
text-align: right;
}
.awesomplete li {
direction: rtl;
text-align: right;
}
dir="rtl" на input, при наличии
RTL-данных;left
вместо right;Мобильные WebView и браузеры по-разному интерпретируют RTL:
text-align в
dropdown;Для стабилизации поведения часто требуется дополнительная фиксация:
input {
unicode-bidi: plaintext;
}
или
.awesomplete input {
unicode-bidi: isolate;
}
При использовании динамических источников (API, JSON) важно нормализовать данные до передачи в Awesomplete:
fetch("/cities")
.then(r => r.json())
.then(data => {
new Awesomplete(input, {
list: data.map(item => ({
label: bidiSafe(item.name),
value: item.code
}))
});
});
Это предотвращает нарушение порядка символов и визуальные артефакты в dropdown.