Accordion
Розкривні секції з анімацією висоти без JS-вимірювань.
Акордеон для секцій, які мають бути під рукою, але не на виду: розкривні
налаштування, FAQ, деревоподібні фільтри. Типово кілька секцій можуть
бути відкриті одночасно; single лишає рівно одну — для FAQ і майстрів,
де секції взаємовиключні.
Приклад
API
Props
| Назва | Тип | Типово | Опис |
|---|---|---|---|
items* | AccordionItem[] | — | Секції акордеона. |
modelValue | string[] | undefined | Відкриті секції. Використовуйте через `v-model`. Без `v-model` компонент керує станом сам, починаючи з `defaultOpen`. |
defaultOpen | string[] | [] | Початково відкриті id — лише в некерованому режимі. |
headingLevel | 2 | 3 | 4 | 5 | 6 | 3 | Рівень заголовків секцій. Має продовжувати структуру сторінки: акордеон під `h2` — це `3`, у модалці з заголовком `h2` — теж `3`, у секції з `h3` — `4`. Інакше скрінрідер будує хибний зміст. |
showToggle | boolean | true | Показувати шеврон праворуч. |
single | boolean | false | Лише одна відкрита секція: відкриття наступної закриває попередню. Для FAQ і майстрів налаштувань, де секції взаємовиключні. |
Події
| Назва | Payload | Опис |
|---|---|---|
update:modelValue | [ids: string[]] | Набір відкритих секцій змінився. Використовуйте через `v-model`. |
open | [id: string] | Секцію відкрито. |
close | [id: string] | Секцію закрито. |
Слоти
| Назва | Опис |
|---|---|
label | Власний рендер заголовка секції. |
Коли використовувати
Коли вмісту більше, ніж місця, і він не потрібен одночасно весь.
Керований режим через v-model — коли стан відкритих секцій треба
читати або писати згори (фільтри в URL, синхронізація між панелями).
У керованому режимі стан приходить лише згори: клік емітить
update:modelValue, але секція відкриється тільки тоді, коли батько
прийме нове значення. Батько, що відхилив зміну, більше не бачить
відкритої секції, якої немає в його modelValue.
Коли НЕ використовувати
Для навігаційних розділів — навігація має бути видимою, а не схованою за кліком.
Не вкладайте акордеон в акордеон: замість ієрархії виходить лабіринт.
Доступність
Кожен заголовок — <button> всередині заголовка рівня headingLevel
(типово <h3>), з aria-expanded і aria-controls; панель —
role="region" з aria-labelledby. Рівень має продовжувати структуру
сторінки: акордеон у секції з <h3> — це heading-level="4", інакше
скрінрідер будує хибний зміст. Секція «розкрита» для скрінрідера
залишалась би зрозумілою навіть без анімації — анімація тут прикраса, не
носій сенсу.
Якщо секцію з фокусом усередині закрили згори (v-model), фокус
повертається на її заголовок до того, як inert сховає панель, — а не
падає в <body>. На дотику заголовок має щонайменше 44px заввишки.
Заголовки зв'язані клавіатурною навігацією: ↑/↓ переходить до попередньої/наступної секції, Home/End — до першої/останньої (лише фокус; відкриття — Enter/Space або клік, як у вкладках).
Деталі реалізації
Плавне розкриття — через grid-template-rows: 0fr → 1fr: висота
анімується без JS-вимірювань і без жорсткої max-height. Глобальний
prefers-reduced-motion вимикач зупиняє transition сам.