Вложенные аккордеоны

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

В Radix UI каждый аккордеон состоит из трёх ключевых элементов:

  • Accordion.Root – контейнер для всей структуры аккордеона. Может иметь режим single или multiple.
  • Accordion.Item – отдельный элемент аккордеона, который содержит заголовок и панель с контентом.
  • Accordion.Trigger и Accordion.Content – элементы, управляющие открытием и отображением содержимого.

Для вложенного аккордеона важно соблюдать правильную структуру DOM, чтобы каждый уровень имел свой собственный Accordion.Root. Это предотвращает конфликты состояния между уровнями.

import * as Accordion from '@radix-ui/react-accordion';

<Accordion.Root type="single" collapsible>
  <Accordion.Item value="item-1">
    <Accordion.Trigger>Первый уровень</Accordion.Trigger>
    <Accordion.Content>
      Контент первого уровня
      <Accordion.Root type="multiple">
        <Accordion.Item value="nested-1">
          <Accordion.Trigger>Вложенный уровень 1</Accordion.Trigger>
          <Accordion.Content>Контент вложенного уровня 1</Accordion.Content>
        </Accordion.Item>
        <Accordion.Item value="nested-2">
          <Accordion.Trigger>Вложенный уровень 2</Accordion.Trigger>
          <Accordion.Content>Контент вложенного уровня 2</Accordion.Content>
        </Accordion.Item>
      </Accordion.Root>
    </Accordion.Content>
  </Accordion.Item>
</Accordion.Root>

Управление состоянием вложенных аккордеонов

Каждый Accordion.Root в Radix UI имеет собственное состояние, которое можно контролировать как внутренне, так и внешне. Для внешнего управления используется проп value и событие onValueChange.

const [outerValue, setOuterValue] = React.useState('');
const [innerValue, setInnerValue] = React.useState([]);

<Accordion.Root type="single" value={outerValue} onValueCha nge={setOuterValue}>
  <Accordion.Item value="item-1">
    <Accordion.Trigger>Первый уровень</Accordion.Trigger>
    <Accordion.Content>
      <Accordion.Root type="multiple" value={innerValue} onValueCha nge={setInnerValue}>
        <Accordion.Item value="nested-1">
          <Accordion.Trigger>Вложенный 1</Accordion.Trigger>
          <Accordion.Content>Контент 1</Accordion.Content>
        </Accordion.Item>
        <Accordion.Item value="nested-2">
          <Accordion.Trigger>Вложенный 2</Accordion.Trigger>
          <Accordion.Content>Контент 2</Accordion.Content>
        </Accordion.Item>
      </Accordion.Root>
    </Accordion.Content>
  </Accordion.Item>
</Accordion.Root>

Использование разделения состояний на каждом уровне обеспечивает точный контроль над открытыми панелями и предотвращает случайное закрытие вложенных элементов при манипуляции родительским аккордеоном.

Доступность и клавиатурная навигация

Radix UI автоматически обеспечивает доступность компонентов аккордеона:

  • Атрибут aria-controls и id для связи Trigger и Content.
  • Поддержка клавиш Enter и Space для открытия/закрытия панели.
  • Поддержка навигации стрелками (Arrow Up/Down) для переключения между Trigger внутри одного Accordion.Root.

При вложенных аккордеонах важно, чтобы каждый уровень имел уникальные идентификаторы, иначе поведение клавиатурного управления может быть нарушено.

<Accordion.Item value="item-1" id="parent-1">
  <Accordion.Trigger id="trigger-1" aria-controls="content-1">Первый уровень</Accordion.Trigger>
  <Accordion.Content id="content-1">...</Accordion.Content>
</Accordion.Item>

Стилизация и анимации

Radix UI не навязывает визуальный стиль, но предоставляет ключевые состояния для стилизации через CSS и сторонние библиотеки:

  • data-state="open" или data-state="closed" у Accordion.Item.
  • data-disabled="true" для отключённых элементов.
  • Возможность анимировать открытие с помощью max-height или библиотек анимаций, например, Framer Motion.
[data-state="open"] {
  animation: expand 0.3s ease-out forwards;
}

[data-state="closed"] {
  animation: collapse 0.3s ease-in forwards;
}

@keyframes expand {
  from { max-height: 0; opacity: 0; }
  to { max-height: 500px; opacity: 1; }
}

@keyframes collapse {
  from { max-height: 500px; opacity: 1; }
  to { max-height: 0; opacity: 0; }
}

Практические советы по вложенным аккордеонам

  1. Изоляция состояний – каждый уровень аккордеона должен управлять своим состоянием отдельно.
  2. Уникальные value и id – предотвращают конфликты при рендеринге нескольких уровней.
  3. Использование type="multiple" для вложенных элементов – часто позволяет пользователю одновременно открывать несколько панелей на подуровне.
  4. Минимизация глубины вложенности – слишком глубокие структуры снижают удобство навигации и могут вызвать проблемы с доступностью.
  5. Анимации должны быть локальными – для плавного открытия/закрытия вложенных панелей лучше использовать отдельные анимации для каждого уровня.

Вложенные аккордеоны Radix UI позволяют создавать сложные интерактивные интерфейсы с полным контролем над состоянием и визуальной презентацией, сохраняя при этом принципы доступности и предсказуемого поведения компонентов.