Элементы
Поле с поиском
Поле ввода со списком вариантов: фильтрация по мере набора, выбор мышью и клавиатурой, пустое состояние, значение в скрытом поле.
Примеры
Часовой пояс встречи
<form action="#" method="post">
<div class="field">
<label class="field__label" for="cb-tz">Часовой пояс</label>
<div class="combo" data-ui-combobox>
<input class="field__input combo__input" type="text" id="cb-tz" role="combobox" aria-expanded="false" aria-controls="cb-tz-list" aria-autocomplete="list" autocomplete="off" placeholder="Начните вводить город" value="Москва">
<input type="hidden" name="timezone" value="Europe/Moscow">
<button class="combo__toggle" type="button" tabindex="-1" aria-label="Показать все варианты" aria-expanded="false" aria-controls="cb-tz-list">▾</button>
<div class="combo__pop" hidden>
<ul class="combo__list" id="cb-tz-list" role="listbox" aria-label="Часовые пояса">
<li class="combo__option" role="option" data-value="Europe/Kaliningrad" data-ui-search="UTC+2">Калининград <small>UTC+2</small></li>
<li class="combo__option" role="option" data-value="Europe/Moscow" data-ui-search="UTC+3" aria-selected="true" data-ui-default>Москва <small>UTC+3</small></li>
<li class="combo__option" role="option" data-value="Europe/Samara" data-ui-search="UTC+4">Самара <small>UTC+4</small></li>
<li class="combo__option" role="option" data-value="Asia/Yekaterinburg" data-ui-search="UTC+5">Екатеринбург <small>UTC+5</small></li>
<li class="combo__option" role="option" data-value="Asia/Novosibirsk" data-ui-search="UTC+7">Новосибирск <small>UTC+7</small></li>
<li class="combo__option" role="option" data-value="Asia/Irkutsk" data-ui-search="UTC+8">Иркутск <small>UTC+8</small></li>
<li class="combo__option" role="option" data-value="Asia/Vladivostok" data-ui-search="UTC+10">Владивосток <small>UTC+10</small></li>
</ul>
<p class="combo__empty" hidden>Ничего не найдено</p>
</div>
</div>
<p class="field__hint">Время встреч в приглашениях показывается в этом поясе.</p>
</div>
</form>Выбор участника без выбранного значения
- Анна Королёва anna@example.com
- Иван Петров ivan@example.com
- Мария Сидорова maria@example.com
- Олег Смирнов в отпуске
Сотрудник не найден
<div class="field">
<label class="field__label" for="cb-host">Организатор</label>
<div class="combo" data-ui-combobox>
<input class="field__input combo__input" type="text" id="cb-host" role="combobox" aria-expanded="false" aria-controls="cb-host-list" aria-autocomplete="list" autocomplete="off" placeholder="Имя или e-mail">
<input type="hidden" name="host">
<button class="combo__toggle" type="button" tabindex="-1" aria-label="Показать все варианты" aria-expanded="false" aria-controls="cb-host-list">▾</button>
<div class="combo__pop" hidden>
<ul class="combo__list" id="cb-host-list" role="listbox" aria-label="Сотрудники">
<li class="combo__option" role="option" data-value="anna" data-ui-search="anna@example.com">Анна Королёва <small>anna@example.com</small></li>
<li class="combo__option" role="option" data-value="ivan" data-ui-search="ivan@example.com">Иван Петров <small>ivan@example.com</small></li>
<li class="combo__option" role="option" data-value="maria" data-ui-search="maria@example.com">Мария Сидорова <small>maria@example.com</small></li>
<li class="combo__option" role="option" data-value="oleg" data-ui-search="oleg@example.com" aria-disabled="true">Олег Смирнов <small>в отпуске</small></li>
</ul>
<p class="combo__empty" hidden>Сотрудник не найден</p>
</div>
</div>
</div>Установка
bukatchuk-ui add combobox
Файлы
| Файл | Назначение |
|---|---|
combobox.css | стили |
combobox.js | скрипт |
example.html | образец разметки, в проект не копируется |
combobox.jinja.html | вставка для Jinja |
Клавиши
| Клавиша | Действие |
|---|---|
| ↓ | открыть список или перейти к следующему варианту |
| ↑ | перейти к предыдущему варианту |
| Enter | выбрать подсвеченный вариант |
| Esc | закрыть список; повторное нажатие очищает поле |
| Tab | закрыть список и перейти дальше |
Макрос для Jinja
{#- Поле с поиском. options — список (value, label[, note]) или словарей {value, label, note, search, disabled};
selected — выбранное значение. Значение уходит в скрытом поле name; нужен скрипт combobox. -#}
{% macro combobox(name, label, options, selected=None, placeholder='', empty='Ничего не найдено', hint=None, id=None) -%}
{%- set cid = id or ('cb-' ~ name) -%}
<div class="field">
<label class="field__label" for="{{ cid }}">{{ label }}</label>
<div class="combo" data-ui-combobox>
{%- set ns = namespace(text='') %}
{%- for o in options %}
{%- set v = o.value if o is mapping else o[0] -%}
{%- if v == selected %}{% set ns.text = o.label if o is mapping else o[1] %}{% endif %}
{%- endfor %}
<input class="field__input combo__input" type="text" id="{{ cid }}" role="combobox" aria-expanded="false" aria-controls="{{ cid }}-list" aria-autocomplete="list" autocomplete="off"{% if placeholder %} placeholder="{{ placeholder }}"{% endif %}{% if hint %} aria-describedby="{{ cid }}-h"{% endif %} value="{{ ns.text }}">
<input type="hidden" name="{{ name }}" value="{{ selected if selected is not none else '' }}">
<button class="combo__toggle" type="button" tabindex="-1" aria-label="Показать все варианты" aria-expanded="false" aria-controls="{{ cid }}-list">▾</button>
<div class="combo__pop" hidden>
<ul class="combo__list" id="{{ cid }}-list" role="listbox" aria-label="{{ label }}">
{%- for o in options %}
{%- set v = o.value if o is mapping else o[0] %}
{%- set t = o.label if o is mapping else o[1] %}
{%- set note = o.note if o is mapping else (o[2] if o|length > 2 else None) %}
{%- set search = o.search if o is mapping else None %}
<li class="combo__option" role="option" data-value="{{ v }}"{% if search %} data-ui-search="{{ search }}"{% endif %}{% if v == selected %} aria-selected="true" data-ui-default{% endif %}{% if o is mapping and o.disabled %} aria-disabled="true"{% endif %}>{{ t }}{% if note %} <small>{{ note }}</small>{% endif %}</li>
{%- endfor %}
</ul>
<p class="combo__empty" hidden>{{ empty }}</p>
</div>
</div>
{%- if hint %}
<p class="field__hint" id="{{ cid }}-h">{{ hint }}</p>
{%- endif %}
</div>
{%- endmacro %}