Примитивы
17

Accordion

Раскрывающиеся панели на <details>/<summary> — без состояния, без обработчиков, без JavaScript. Нативная пара уже является кнопкой, которая сообщает своё состояние, срабатывает по Enter и Space и находится поиском по странице: браузер сам раскроет закрытую панель, чтобы показать совпадение.

чистая разметка — библиотеки на странице нет
отрендерил aura-react
отрендерил aura-vue
отрендерил aura-svelte
собрано из классов самого aura-angular
What is Aura?
Tokens and a stylesheet, wrapped by four thin packages.
Why four packages?
The same classes, so the same picture — whichever framework you already use.
Any dependencies?
None at runtime. The CSS is the component; the wrappers only type it.
What is next?
Published when there is something to publish.
What is Aura?
Tokens and a stylesheet, wrapped by four thin packages.
Why four packages?
The same classes, so the same picture — whichever framework you already use.
Any dependencies?
None at runtime. The CSS is the component; the wrappers only type it.
What is next?
Published when there is something to publish.
What is Aura?
Tokens and a stylesheet, wrapped by four thin packages.
Why four packages?
The same classes, so the same picture — whichever framework you already use.
Any dependencies?
None at runtime. The CSS is the component; the wrappers only type it.
What is next?
Published when there is something to publish.
What is Aura?
Tokens and a stylesheet, wrapped by four thin packages.
Why four packages?
The same classes, so the same picture — whichever framework you already use.
Any dependencies?
None at runtime. The CSS is the component; the wrappers only type it.
What is next?
Published when there is something to publish.
What is Aura?
Tokens and a stylesheet, wrapped by four thin packages.
Why four packages?
The same classes, so the same picture — whichever framework you already use.
Any dependencies?
None at runtime. The CSS is the component; the wrappers only type it.
What is next?
Published when there is something to publish.

Код

index.html
<div class="aura-accordion">
  <details class="aura-accordion__item" open name="faq">
    <summary class="aura-accordion__summary">What is Aura?</summary>
    <div class="aura-accordion__panel">Tokens and a stylesheet, wrapped by four thin packages.</div>
  </details>
  <details class="aura-accordion__item" name="faq">
    <summary class="aura-accordion__summary">Why four packages?</summary>
    <div class="aura-accordion__panel">The same classes, so the same picture — whichever framework you already use.</div>
  </details>
  <details class="aura-accordion__item" name="faq">
    <summary class="aura-accordion__summary">Any dependencies?</summary>
    <div class="aura-accordion__panel">None at runtime. The CSS is the component; the wrappers only type it.</div>
  </details>
  <details class="aura-accordion__item" name="faq" inert aria-disabled="true">
    <summary class="aura-accordion__summary">What is next?</summary>
    <div class="aura-accordion__panel">Published when there is something to publish.</div>
  </details>
</div>
Demo.tsx
import { Accordion } from '@ilomee/aura-react';

const ITEMS = [
  { id: 'what', label: 'What is Aura?', content: 'Tokens and a stylesheet, wrapped by four thin packages.', open: true },
  { id: 'why', label: 'Why four packages?', content: 'The same classes, so the same picture — whichever framework you already use.' },
  { id: 'deps', label: 'Any dependencies?', content: 'None at runtime. The CSS is the component; the wrappers only type it.' },
  { id: 'roadmap', label: 'What is next?', content: 'Published when there is something to publish.', disabled: true },
];

export default function Demo() {
  // `name` задан явно, чтобы все стеки отрисовали одинаковую разметку: без него каждый фреймворк
  // выпишет свой id, и кросс-стековому дифу будет нечего сравнивать.
  return <Accordion items={ITEMS} exclusive name="faq" />;
}
Demo.vue
<script setup lang="ts">
import { Accordion } from '@ilomee/aura-vue';

const ITEMS = [
  { id: 'what', label: 'What is Aura?', content: 'Tokens and a stylesheet.', open: true },
  { id: 'why', label: 'Why four packages?', content: 'The same classes everywhere.' },
];
</script>

<template>
  <Accordion :items="ITEMS" exclusive />
</template>
Demo.svelte
<script lang="ts">
  import { Accordion } from '@ilomee/aura-svelte';

  const ITEMS = [
    { id: 'what', label: 'What is Aura?', content: 'Tokens and a stylesheet.', open: true },
    { id: 'why', label: 'Why four packages?', content: 'The same classes everywhere.' },
  ];
</script>

<Accordion items={ITEMS} exclusive />

Используется как aura-accordion.

demo.component.ts
import { AuraAccordion } from '@ilomee/aura-angular';

@Component({
  standalone: true,
  imports: [AuraAccordion],
  template: `<aura-accordion [items]="items" [exclusive]="true" />`,
})
export class DemoComponent {
  items = [
    { id: 'what', label: 'What is Aura?', content: 'Tokens and a stylesheet.', open: true },
    { id: 'why', label: 'Why four packages?', content: 'The same classes everywhere.' },
  ];
}

Контент панели едет вместе с элементом, а не проецируется: <ng-content> в Angular рендерится только в первое совпадение, поэтому слот на панель молча потерял бы все панели, кроме первой.

Пропсы

У чистой разметки нет пропсов — классы ниже и есть весь API. Четыре пакета не делают ничего сверх того, что проставляют вам те же самые классы.
ИмяТипПо умолчаниюПримечания
itemsAuraAccordionItem[] | nullПункт — это { id, label, content?, open?, disabled? }. Отключённый рисуется с inert и aria-disabled на своём <details>: декларативно, потому что у компонента нет ни строки JavaScript, а у <summary> нет своего disabled.
exclusivebooleanfalseСобственный name браузера у <details>: панели с общим именем закрывают друг друга, и синхронизировать нечего. Где не поддержано — каждая панель открывается независимо, контент остаётся доступен.
namestringСгенерированный id берётся у самого фреймворка, поэтому он совпадает при SSR и гидратации.
renderPanel(item: AuraAccordionItem) => ReactNodeПанель, которой мало одного предложения, — список, ссылка, таблица. Заменяет item.content и сохраняет всё вокруг: <details>, <summary>, классы и inert у отключённого пункта остаются за компонентом, поэтому люк не может сломать ни семантику панели, ни кросс-стековый диф разметки. Та же форма, что у renderOption в Select.
ИмяТипПо умолчаниюПримечания
itemsAuraAccordionItem[] | nullПункт — это { id, label, content?, open?, disabled? }. Отключённый рисуется с inert и aria-disabled на своём <details>: декларативно, потому что у компонента нет ни строки JavaScript, а у <summary> нет своего disabled.
exclusivebooleanfalse
namestringСгенерированный id берётся у самого фреймворка, поэтому он совпадает при SSR и гидратации.
panelслот{ item: AuraAccordionItem }Панель, которой мало одного предложения, — список, ссылка, таблица. Заменяет item.content и сохраняет всё вокруг: <details>, <summary>, классы и inert у отключённого пункта остаются за компонентом, поэтому люк не может сломать ни семантику панели, ни кросс-стековый диф разметки. Та же форма, что у renderOption в Select.
ИмяТипПо умолчаниюПримечания
itemsAuraAccordionItem[] | nullПункт — это { id, label, content?, open?, disabled? }. Отключённый рисуется с inert и aria-disabled на своём <details>: декларативно, потому что у компонента нет ни строки JavaScript, а у <summary> нет своего disabled.
exclusivebooleanfalse
namestringСгенерированный id берётся у самого фреймворка, поэтому он совпадает при SSR и гидратации.
panelслотSnippet<[AuraAccordionItem]>Панель, которой мало одного предложения, — список, ссылка, таблица. Заменяет item.content и сохраняет всё вокруг: <details>, <summary>, классы и inert у отключённого пункта остаются за компонентом, поэтому люк не может сломать ни семантику панели, ни кросс-стековый диф разметки. Та же форма, что у renderOption в Select.
ИмяТипПо умолчаниюПримечания
itemsAuraAccordionItem[] | null[]Пункт — это { id, label, content?, open?, disabled? }. Отключённый рисуется с inert и aria-disabled на своём <details>: декларативно, потому что у компонента нет ни строки JavaScript, а у <summary> нет своего disabled.
exclusivebooleanfalse
namestring
panelTemplateTemplateRef<AuraAccordionPanelContext> | nullПанель, которой мало одного предложения, — список, ссылка, таблица. Заменяет item.content и сохраняет всё вокруг: <details>, <summary>, классы и inert у отключённого пункта остаются за компонентом, поэтому люк не может сломать ни семантику панели, ни кросс-стековый диф разметки. Та же форма, что у renderOption в Select.

Какие классы отдаёт

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

КлассРольПримечания
.aura-accordionбазаОбязательный. Без него модификатор не работает.
.aura-accordion__itemэлемент
.aura-accordion__summaryэлемент
.aura-accordion__panelэлемент

Токены и правила

components.css
рамка
1px solid var(--border) · var(--r2)
шеврон
drawn from two borders — no icon set needed
состояние
[open] — the browser owns it