Accordion
An accordion is a set of sections that share a frame: one border round the lot, a rule between each. That framing is the difference from a DisclosureGroup, which coordinates the same expanding behaviour without drawing anything — reach for the group when the sections are already inside cards or a layout of their own.
import {
Accordion,
AccordionBody,
AccordionHeading,
AccordionIndicator,
AccordionItem,
AccordionPanel,
AccordionTrigger,
} from "ropav";AccordionItem is one section. Inside it, AccordionHeading holds AccordionTrigger — the pressable row — and AccordionPanel holds AccordionBody, the padded box that appears.
accordion-basic.vue
<script setup lang="ts">
import {
Accordion,
AccordionBody,
AccordionHeading,
AccordionIndicator,
AccordionItem,
AccordionPanel,
AccordionTrigger,
} from "ropav";
const questions = [
{
answer: "Every component ships its own stylesheet, and the theme decides the colours.",
id: "styling",
title: "How is it styled?",
},
{
answer: "One tab stop per control, and the keyboard interactions the ARIA pattern asks for.",
id: "keyboard",
title: "What about the keyboard?",
},
{
answer: "Server rendering works, and the client hydrates what the server drew.",
id: "ssr",
title: "Does it render on the server?",
},
] as const;
</script>
<template>
<Accordion class="panel" :default-expanded-keys="['styling']">
<AccordionItem v-for="question in questions" :id="question.id" :key="question.id">
<AccordionHeading>
<AccordionTrigger>
{{ question.title }}
<AccordionIndicator />
</AccordionTrigger>
</AccordionHeading>
<AccordionPanel>
<AccordionBody>{{ question.answer }}</AccordionBody>
</AccordionPanel>
</AccordionItem>
</Accordion>
</template>
<style scoped>
.panel {
width: 100%;
max-width: var(--rp-container-md);
}
</style>One at a time, or several
By default opening a section closes the last. allows-multiple-expanded lets them stand open together, which is what you want when the sections are reference material a reader compares rather than steps they work through.
Each item needs an id to be keyed by — one is generated if you leave it out, but then expanded-keys has nothing stable to name. default-expanded-keys starts the accordion somewhere and v-model:expanded-keys hands the state to the caller.
hide-separator drops the rules between items, and is-disabled on the accordion disables every item in it while an item can still disable itself.
Accessibility
- Every trigger is inside a real heading, so the sections appear in a document outline and a reader navigating by heading finds them.
- The trigger carries
aria-expandedandaria-controls, and the panel is what those point at. - The panel is a
role="group"by default. Where a section is a region of the page in its own right,role="region"onAccordionPanelsays so. - With one section open at a time, opening one closes another under the reader. That is a reason to prefer
allows-multiple-expandedwherever the sections are things to read rather than a sequence to work through.
API
Accordion
| Prop | Type | Default | Description |
|---|---|---|---|
allowsMultipleExpanded | boolean | — | Whether more than one item can be expanded at a time. |
defaultExpandedKeys | Iterable<DisclosureKey> | — | Expanded item keys in uncontrolled mode. |
expandedKeys | Iterable<DisclosureKey> | — | Expanded item keys in controlled mode. Pairs with v-model:expanded-keys. |
hideSeparator | boolean | false | Removes the separator drawn between items. |
isDisabled | boolean | — | Disables every item in the accordion. |
variant | "default" | "surface" | — | Visual variant. |
Slots: default.
| Event | Payload |
|---|---|
expandedChange | Set<DisclosureKey> |
update:expandedKeys | Set<DisclosureKey> |
AccordionBody
Slots: default.
AccordionHeading
Slots: default.
AccordionIndicator
Slots: default.
AccordionItem
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Identity of the item within the group, and the value carried in expandedKeys. Generated when omitted. |
isDisabled | boolean | — | Disables this item only. |
Slots: default.
AccordionPanel
| Prop | Type | Default | Description |
|---|---|---|---|
role | string | "group" | ARIA role of the panel. Matches React Aria's default. |
Slots: default.
AccordionTrigger
Slots: default.