useAccordion для аккордеонов

Хук useAccordion предназначен для управления состоянием и поведением аккордеонов, обеспечивая доступность (accessibility) и соответствие стандартам ARIA. Он интегрируется с компонентами React, позволяя создавать сложные интерактивные интерфейсы без необходимости вручную управлять фокусом и атрибутами ARIA.


Импорт и структура

import { useAccordion } from "@react-aria/accordion";
import { useAccordionItem } from "@react-aria/accordion";
import { useAccordionState } from "@react-stately/accordion";
  • useAccordionState — управляет состоянием аккордеона, хранит информацию о выбранных элементах, открытых панелях и позволяет контролировать множественный выбор.
  • useAccordion — создает свойства для контейнера аккордеона, включая атрибуты ARIA.
  • useAccordionItem — применяется к каждому элементу аккордеона, задавая правильные роли и связывая кнопку и панель контента.

Создание состояния аккордеона

Состояние аккордеона создается с помощью useAccordionState:

const state = useAccordionState({
  allowsMultiple: true, // разрешает открытие нескольких панелей одновременно
  defaultSelectedKeys: ["item1"], // начально открытая панель
});

Ключевые параметры:

  • allowsMultipletrue позволяет открывать несколько элементов одновременно, false — только один.
  • selectedKeys — контролируемый список открытых элементов.
  • defaultSelectedKeys — начальные открытые элементы.
  • onSelectionChange — callback при изменении открытых элементов.

Основной контейнер аккордеона

const { accordionProps } = useAccordion({ type: "multiple" }, state);
  • accordionProps содержит необходимые атрибуты ARIA, включая role="presentation" и другие, обеспечивающие корректную работу вспомогательных технологий.
  • Параметр type принимает значения "single" или "multiple", отражающие режим открытия элементов.

Пример использования:

<div {...accordionProps}>
  {items.map(item => (
    <AccordionItem key={item.id} item={item} state={state} />
  ))}
</div>

Элементы аккордеона

Для каждого элемента используется useAccordionItem:

function AccordionItem({ item, state }) {
  const ref = React.useRef();
  const { buttonProps, regionProps } = useAccordionItem(
    { key: item.id },
    state,
    ref
  );

  return (
    <div>
      <h3>
        <button {...buttonProps} ref={ref}>
          {item.title}
        </button>
      </h3>
      <div {...regionProps}>
        {item.content}
      </div>
    </div>
  );
}

Ключевые моменты:

  • buttonProps — свойства для кнопки, включающие aria-expanded, aria-controls и управление клавиатурой.
  • regionProps — свойства панели контента, включая role="region" и id, связанный с кнопкой.
  • ref нужен для правильного управления фокусом и анимациями.

Поддержка клавиатуры

React Aria автоматически обрабатывает стандартные клавиши аккордеона:

  • ArrowDown / ArrowUp — переход между заголовками.
  • Home / End — переход к первому или последнему элементу.
  • Enter / Space — открытие или закрытие панели.

Это исключает необходимость вручную добавлять обработчики событий клавиатуры.


Контролируемые и неконтролируемые аккордеоны

useAccordionState поддерживает оба режима:

  • Неконтролируемый — управление внутренним состоянием через defaultSelectedKeys.
  • Контролируемый — через selectedKeys и onSelectionChange.

Пример контролируемого:

const [selected, setSelected] = React.useState(["item1"]);
const state = useAccordionState({
  selectedKeys: selected,
  onSelectionChange: setSelected,
  allowsMultiple: false
});

Доступность и ARIA

Хук useAccordion гарантирует соответствие WAI-ARIA:

  • role="button" и aria-expanded для заголовка.
  • role="region" и aria-labelledby для панели.
  • Управление фокусом и клавишами для поддержки скринридеров.

Все это делает аккордеон полностью доступным без ручной настройки атрибутов.


Пример комплексного аккордеона

function MyAccordion() {
  const state = useAccordionState({
    allowsMultiple: true,
    defaultSelectedKeys: ["item1"]
  });
  
  const { accordionProps } = useAccordion({}, state);

  const items = [
    { id: "item1", title: "Заголовок 1", content: "Контент 1" },
    { id: "item2", title: "Заголовок 2", content: "Контент 2" },
    { id: "item3", title: "Заголовок 3", content: "Контент 3" }
  ];

  return (
    <div {...accordionProps}>
      {items.map(item => (
        <AccordionItem key={item.id} item={item} state={state} />
      ))}
    </div>
  );
}

В этом примере:

  • Аккордеон поддерживает множественное открытие элементов.
  • Все кнопки и панели имеют правильные ARIA-атрибуты.
  • Состояние контролируется через useAccordionState.

Настройка кастомного поведения

React Aria позволяет расширять стандартный аккордеон:

  • Обрабатывать события открытия/закрытия.
  • Добавлять анимации при раскрытии панели.
  • Встраивать в сложные компоненты, сохраняя доступность.
  • Использовать кастомные роли и стили без нарушения ARIA.

Хук useAccordion создает основу, на которой строится надежный, доступный и интерактивный аккордеон.


Эта реализация обеспечивает гибкость, соответствие стандартам и простоту интеграции с React-компонентами.