Выпадающее меню и вкладки
Выпадающее меню и вкладки встречаются почти на каждом сайте. На Alpine оба собираются из уже знакомых директив: одно свойство в x-data, x-show для видимости и @click для переключения. Оба элемента — часть страницы списка дел в index.html.
Выпадающее меню
Меню действий над задачей. Минимальная версия — кнопка и список, который открывается по клику:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ open: false }">
<button @click="open = !open">Действия</button>
<ul x-show="open">
<li>Изменить</li>
<li>Удалить</li>
</ul>
</div>Кнопка открывает и закрывает список. Но меню пока закрывается только повторным кликом по кнопке.
Закрытие снаружи и по Esc
Пользователь ждёт, что меню закроется по клику в любом другом месте и по клавише Esc:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ open: false }" @keydown.escape.window="open = false" style="position: relative; display: inline-block">
<button @click="open = !open" :aria-expanded="open">Действия ▾</button>
<ul
x-show="open"
x-transition.opacity
@click.outside="open = false"
style="position: absolute; margin: 4px 0; padding: 4px 12px; border: 1px solid #ccc; background: Canvas; list-style: none"
>
<li><button @click="console.log('Изменить'); open = false">Изменить</button></li>
<li><button @click="console.log('Удалить'); open = false">Удалить</button></li>
</ul>
</div>Меню закрывается кликом мимо него, клавишей Esc и после выбора пункта, а выбранное действие появляется в консоли. Атрибут aria-expanded сообщает программам чтения с экрана, открыто ли меню.
Вкладки
Вкладки хранят имя активной вкладки. Кнопка меняет его, панель показывается, когда имя совпадает:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<style>
.tab-active { font-weight: bold; text-decoration: underline; }
</style>
<div x-data="{ tab: 'active' }">
<nav>
<button @click="tab = 'active'" :class="{ 'tab-active': tab === 'active' }">Активные</button>
<button @click="tab = 'done'" :class="{ 'tab-active': tab === 'done' }">Выполненные</button>
</nav>
<div x-show="tab === 'active'">
<p>Купить молоко</p>
<p>Позвонить Олегу</p>
</div>
<div x-show="tab === 'done'">
<p>Оплатить интернет</p>
</div>
</div>Сначала открыта вкладка «Активные» с двумя задачами. Кнопка «Выполненные» переключает панель и выделяет себя жирным.
Если вкладок много, их описывают массивом и выводят кнопки через x-for — тогда новая вкладка добавляется одной строкой данных.
Частая ошибка
Написать @keydown.escape без .window. Событие клавиатуры приходит элементу, на котором стоит фокус. А в Safari клик по кнопке не переводит на неё фокус: меню открыто, фокус остаётся на <body>, и Esc без .window ничего не закрывает. Модификатор .window слушает клавишу на всём окне, поэтому меню закрывается всегда.