# Аккордеон (Accordion)

![](https://72564723-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MXg0KhIlZk_bjQRk4u3%2F-MacusXiSxB6FztqjABh%2F-Malmq_wfXcIxNL32GJM%2Faccardion.jpg?alt=media\&token=49e63f67-4b05-4516-a481-f59cf96de41f)

## Основные данные&#x20;

Основной ресурс откуда взята информация - <https://ebay.gitbook.io/mindpatterns/disclosure/accordion>

Каждая панель аккордеона отделена интерактивным заголовком панели, которую в любой момент можно открыть.

Часто используется в боковых панелях и меню навигации для постепенного раскрытия ссылок и фильтров.

Хорошая статья с примерами настройки и применения `<details>`: <https://habr.com/ru/post/477520/>

Очень много примеров `<details>` использования с кодом: <https://freefrontend.com/html-details-summary-css/>

## Терминология

* **accordion**: шаблон в целом, состоящий из следующих частей
* **panel**: каждая панель в аккордеоне - это виджет раскрытия деталей
* **header**: заголовок, который отображает интерактивную сводку содержимого панели
* **heading**: заголовок, который находится внутри элемента и отражает суть панели
* **auto-collapse**: свойство аккордеона,  при котором автоматически сворачиваются открытые панели при открытии новой панели

## Лучшая практика

Каждый заголовок (header) находится в естественном индексе табуляции. Этот естественный tabindex нельзя удалять или изменять.

По умолчанию все панели могут быть в открытом, развернутом состоянии.

*При желании* аккордеон может быть ограничен отображением только одной панели содержимого за раз (т.е. открытие панели закроет любую другую открытую панель). Это называется автоматически сворачивающимся аккордеоном.

## Интерактивный дизайн

### Управление клавиатурой

Нажатие клавиши `TAB`должно перемещать фокус клавиатуры с одного заголовка на другой. Он также будет перемещать фокус через любые интерактивные элементы внутри открытых панелей.

Точно так же нажатие клавиш `SHIFT-TAB` перемещает фокус назад по заголовкам и содержимому интерактивной панели.

Нажатие клавиши `ПРОБЕЛ`или `ВВОД`в заголовке с фокусом клавиатуры должно открывать панель. Для автоматического сворачивания аккордеонов любая другая открытая панель должна закрываться.

### Screenreader

Виртуальный курсор **должен** иметь возможность перемещаться от одного заголовка к другому. ‌

С виртуальным курсором на заголовке, он должен иметь возможность открывать панель с помощью имитации события щелчка. Для аккордеонов с автоматическим сворачиванием любая другая открытая панель должна закрываться, но об этом не следует объявлять.

## Код

В шаблоне «аккордеон» активно используется тег "details" HTML. Старые браузеры, включая IE11 и Edge, изначально не поддерживают тег сведений, поэтому требуют полифилла.

{% hint style="danger" %}
При использовании details нет возможности анимировать открытие
{% endhint %}

HTML-элемент `<details>` используется для раскрытия скрытой (дополнительной) информации.

Виджет раскрытия обычно представлен на экране с использованием небольшого треугольника, который поворачивается, чтобы показать состояние открытия / закрытия, с меткой рядом с треугольником. Если первый дочерний элемент элемента `<details>` является `<summary>`, содержимое элемента `<summary>` используется в качестве метки для виджета раскрытия.

{% tabs %}
{% tab title="XML/HTML/SVG" %}

```markup
<ul class="accordion" role="list" aria-roledescription="accordion">
    <li>
        <details class="accordion__details" open>
            <summary><h4>Buying</h4></summary>
            <ul>
                <li><a href="http://www.ebay.com">Purchases</a></li>
                <li><a href="http://www.ebay.com">Bids/Offers</a></li>
                <li><a href="http://www.ebay.com">Didn't Win</a></li>
            </ul>
        </details>
    </li>
    <li>
        <details class="accordion__details">
            <summary><h4>Selling</h4></summary>
            <ul>
                <li><a href="http://www.ebay.com">Sold</a></li>
                <li><a href="http://www.ebay.com">Bids/Offers</a></li>
                <li><a href="http://www.ebay.com">Didn't Swell</a></li>
            </ul>
        </details>
    </li>
</ul>
```

{% endtab %}
{% endtabs %}

Обратите внимание, что в некоторых браузерах роль неявного списка удаляется, когда применяется CSS list-style-type: none, поэтому мы применили role = list в нашей разметке, чтобы гарантировать явную роль.

### CSS

Для смены стандартного треугольника раскрытия:

```css
summary { list-style-image: url(right-arrow.svg); }
summary::-webkit-details-marker { background: url(right-arrow.svg); color: transparent; }
```

Анимация раскрытия:

```css
details[open] summary ~ * {
  animation: sweep .5s ease-in-out;
}

@keyframes sweep {
  0%    {opacity: 0; margin-left: -10px}
  100%  {opacity: 1; margin-left: 0px}
}
```

### JavaScript

Тэг `details` требует [polyfill](https://github.com/javan/details-element-polyfill) для браузеров которые не поддерживают его нативно.

Код для загрузки полифила только для ие:

```javascript
<script type="text/javascript">
    if(/MSIE \d|Trident.*rv:/.test(navigator.userAgent))
        document.write('<script src="somescript.js"><\/script>');
</script>
```

Основной код указан выше и служит для того, что бы закрывать открытую вкладку при выборе новой.

## Код (с возможность анимации)

```html
<ul class="services__list" role="list" aria-roledescription="accordion">
   <li class="services__details">
      <button class="btn services__summary" aria-expanded="false">
          <h3 class="services__header">Заголовок</h3>
          <span class="services__icon"></span>
      </button>
      <div class="services__content" aria-hidden="true">
         <p class="services__text">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Praesentium, quod.</p>
      </div>
   </li>  
   <li class="services__details">
      <button class="btn services__summary" aria-expanded="false">
          <h3 class="services__header">Заголовок</h3>
          <span class="services__icon"></span>
      </button>
      <div class="services__content" aria-hidden="true">
         <p class="services__text">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Praesentium, quod.</p>
      </div>
   </li>         
 </ul>
```

```scss
 &__content {
         opacity: 0;
         max-height: 0;
         will-change: max-height;
         overflow: hidden;
         transition: opacity, max-height  0.3s ease-out;
         box-sizing: content-box;
      }

      &__content[aria-hidden="false"]{
         opacity: 1;
         padding: 10px 10px;
      }
```

```javascript
/**
 * Аккордеон с анимацией (через button)
 * el - класс аккордеона
 * closeAll - определят, требуется ли закрывать остальные вкладки при открытии
 */
class AccordionBtn {
   constructor(el, closeAll = false) {
      this.accrdion = document.querySelector(el);
      this.closeAll = closeAll;
      if (!this.accrdion) {
         console.error(`Не найден аккордеон - ${el}!`);
         return;
      }
      this.init();
   }

   init() {
      this.accItmesBtns = this.accrdion.querySelectorAll("button[aria-expanded]");
      if (!this.accItmesBtns) console.error("Не найдены кнопки содержащие аттрибут aria-expanded");

      this.accItmesBtns.forEach((itemBtn) => {
         itemBtn.addEventListener("click", (e) => {
            const btn = e.currentTarget;
            const openBtn = btn.getAttribute("aria-expanded") === "true" ? true : false;

            if (this.closeAll) {
               this.showOne(btn);
            }
            const context = btn.nextElementSibling;
            if (!context || !context.hasAttribute("aria-hidden")) console.error("Не найден блок с контентом содержащий аттрибут aria-hidden");
            const openContext = context.getAttribute("aria-hidden") === "true" ? true : false;
            const heightContext = context.style.maxHeight === "" || context.style.maxHeight === "0px" ? context.scrollHeight : 0;

            btn.setAttribute("aria-expanded", !openBtn);
            context.setAttribute("aria-hidden", !openContext);
            context.style.maxHeight = heightContext + "px";
         });
      });
   }

   showOne(btn) {
      this.accItmesBtns.forEach((itemBtn) => {
         if (itemBtn !== btn) {
            itemBtn.setAttribute("aria-expanded", "false");
            if (itemBtn.nextElementSibling.hasAttribute("aria-hidden")) {
               itemBtn.nextElementSibling.setAttribute("aria-hidden", "true");
               itemBtn.nextElementSibling.style.maxHeight = "0px";
            }
         }
      });
   }
}
```

## ARIA

* **aria-roledescription**: определяет удобочитаемое, локализованное для автора описание роли элемента. В данном случае «аккордеон».


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://danila-korotkov.gitbook.io/front-end-patterns/shablony/vkladki-spiski/akkordeon-accordion.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
