<script setup lang="ts">
import {
AAccordionContent,
AAccordionHeader,
AAccordionItem,
AAccordionRoot,
AAccordionTrigger,
} from 'akar';
const items = [
{
value: 'item-1',
title: 'Is it accessible?',
content: 'Yes. It adheres to the WAI-ARIA design pattern.',
},
{
value: 'item-2',
title: 'Is it unstyled?',
content: 'Yes. It\'s unstyled by default, giving you freedom over the look and feel.',
},
{
value: 'item-3',
title: 'Can it be animated?',
content: 'Yes! You can use the transition prop to configure the animation.',
},
];
</script>
<template>
<AAccordionRoot
class="px-4 rounded-md bg-background w-[300px]"
default-value="item-1"
type="single"
:collapsible="true"
>
<template
v-for="item in items"
:key="item.value"
>
<AAccordionItem
class="border-b border-border last:border-b-none"
:value="item.value"
>
<AAccordionHeader class="flex">
<AAccordionTrigger class="group text-sm font-medium py-3.5 flex flex-1 gap-1.5 min-w-0 items-center focus-visible:outline-primary">
<span>{{ item.title }}</span>
<i
class="i-lucide:chevron-down ms-auto shrink-0 size-5 transition-transform-280 ease-[cubic-bezier(0.87,_0,_0.13,_1)] group-data-[state=open]:rotate-180"
aria-label="Expand/Collapse"
/>
</AAccordionTrigger>
</AAccordionHeader>
<AAccordionContent class="overflow-hidden data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down">
<div class="text-sm color-text-muted pb-4 pt-1">
{{ item.content }}
</div>
</AAccordionContent>
</AAccordionItem>
</template>
</AAccordionRoot>
</template>
Import all parts and piece them together.
<script setup>
import { AAccordionContent, AAccordionHeader, AAccordionItem, AAccordionRoot, AAccordionTrigger } from 'akar';
</script>
<template>
<AAccordionRoot>
<AAccordionItem>
<AAccordionHeader>
<AAccordionTrigger />
</AAccordionHeader>
<AAccordionContent />
</AAccordionItem>
</AAccordionRoot>
</template>
One benefit of using Akar is its flexibility and low-level control over the components. However, this also means that you may need to manually construct more complex UI elements by combining multiple Akar components together.
If you feel there's a lot of elements that needs to be constructed manually using Akar, consider using Pohon UI instead. It provides a higher-level abstraction over Akar components with pre-defined styles and behaviors that can help you build UIs faster.
Contains all the parts of an Accordion
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
collapsible | false | booleanWhen type is 'single', allows closing content when clicking trigger for an open item. When type is 'multiple', this prop has no effect. |
defaultValue | string | string[]The default active value of the item(s). Use when you do not need to control the state of the item(s). | |
dir | 'ltr' | 'rtl'The reading direction of the accordion when applicable. If omitted, assumes LTR (left-to-right) reading mode. | |
disabled | false | booleanWhen |
modelValue | string | string[] | |
orientation | 'vertical' | 'horizontal' | 'vertical'The orientation of the accordion. |
type | 'multiple' | 'single'Determines whether a 'single' or 'multiple' items can be pressed at a time. This prop will overwrite the inferred type from | |
unmountOnHide | true | booleanWhen |
| Event | Type |
|---|---|
update:modelValue | [value: string | string[]]Event handler called when the expanded state of an item changes |
| Slot | Type |
|---|---|
modelValue | AcceptableValue | AcceptableValue[] The controlled value of the active item(s). Use this when you need to control the state of the items. Can be binded with |
| Attribute | Value |
|---|---|
[data-orientation] | 'vertical' | 'horizontal' |
Contains all the parts of a collapsible section.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanWhen | |
unmountOnHide | booleanWhen | |
value* | stringA string value for the accordion item. All items within an accordion should use a unique value. |
| Slot | Type |
|---|---|
open | booleanCurrent open state |
| Attribute | Value |
|---|---|
[data-state] | 'open' | 'closed' |
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
Wraps an AAccordionTrigger. Use the asChild prop to update it to the appropriate heading level for your page.
| Prop | Default | Type |
|---|---|---|
as | 'h3' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Attribute | Value |
|---|---|
[data-state] | 'open' | 'closed' |
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
Toggles the collapsed state of its associated item. It should be nested inside of an AAccordionHeader.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Attribute | Value |
|---|---|
[data-state] | 'open' | 'closed' |
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
Contains the collapsible content for an item.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |
| Attribute | Value |
|---|---|
[data-state] | 'open' | 'closed' |
[data-disabled] | Present when disabled |
[data-orientation] | 'vertical' | 'horizontal' |
| Variable | Description |
|---|---|
--akar-accordion-content-width | The width of the content when it opens/closes |
--akar-accordion-content-height | The height of the content when it opens/closes |
Use the defaultValue prop to define the open item by default.
<template>
<AAccordionRoot
type="single"
default-value="item-2"
>
<AAccordionItem value="item-1">
…
</AAccordionItem>
<AAccordionItem value="item-2">
…
</AAccordionItem>
</AAccordionRoot>
</template>
Use the collapsible prop to allow all items to close.
<template>
<AAccordionRoot
type="single"
collapsible
>
<AAccordionItem value="item-1">
…
</AAccordionItem>
<AAccordionItem value="item-2">
…
</AAccordionItem>
</AAccordionRoot>
</template>
Set the type prop to multiple to enable opening multiple items at once.
<template>
<AAccordionRoot type="multiple">
<AAccordionItem value="item-1">
…
</AAccordionItem>
<AAccordionItem value="item-2">
…
</AAccordionItem>
</AAccordionRoot>
</template>
You can add extra decorative elements, such as chevrons, and rotate it when the item is open.
// index.vue
<script setup>
import { AAccordionContent, AAccordionHeader, AAccordionItem, AAccordionRoot, AAccordionTrigger } from 'akar';
</script>
<template>
<AAccordionRoot type="single">
<AAccordionItem value="item-1">
<AAccordionHeader>
<AAccordionTrigger class="group">
<span>Trigger text</span>
<i
class="i-lucide:chevron-down transition-transform-280 group-data-[state=open]:rotate-180"
/>
</AAccordionTrigger>
</AAccordionHeader>
<AAccordionContent>…</AAccordionContent>
</AAccordionItem>
</AAccordionRoot>
</template>
Use the orientation prop to create a horizontal Accordion
<template>
<AAccordionRoot orientation="horizontal">
<AAccordionItem value="item-1">
…
</AAccordionItem>
<AAccordionItem value="item-2">
…
</AAccordionItem>
</AAccordionRoot>
</template>
Use the --akar-accordion-content-width and/or --akar-accordion-content-height CSS variables to animate the size of the content when it opens/closes:
// index.vue
<script setup>
import { AAccordionContent, AAccordionHeader, AAccordionItem, AAccordionRoot } from 'akar';
import './styles.css';
</script>
<template>
<AAccordionRoot type="single">
<AAccordionItem value="item-1">
<AAccordionHeader>…</AAccordionHeader>
<AAccordionContent class="AAccordionContent">
…
</AAccordionContent>
</AAccordionItem>
</AAccordionRoot>
</template>
/* styles.css */
.AAccordionContent {
overflow: hidden;
}
.AAccordionContent[data-state='open'] {
animation: accordion-down 300ms ease-out;
}
.AAccordionContent[data-state='closed'] {
animation: accordion-up 300ms ease-out;
}
@keyframes accordion-down {
from {
height: 0;
}
to {
height: var(--akar-accordion-content-height);
}
}
@keyframes accordion-up {
from {
height: var(--akar-accordion-content-height);
}
to {
height: 0;
}
}
animate-accordion-up and animate-accordion-down are available right out of the box, saving you the step of manually creating them.By default hidden content will be removed, use :unmountOnHide="false" to keep the content always available.
This will also allow browser to search the hidden text, and open the accordion.
<template>
<AAccordionRoot :unmount-on-hide="false">
<AAccordionItem value="item-1">
…
</AAccordionItem>
<AAccordionItem value="item-2">
…
</AAccordionItem>
</AAccordionRoot>
</template>
Adheres to the Accordion WAI-ARIA design pattern.
| Key | Description |
|---|---|
Space | When focus is on an |
Enter | When focus is on an |
Tab | Moves focus to the next focusable element. |
Shift + Tab | Moves focus to the previous focusable element. |
ArrowDown | Moves focus to the next |
ArrowUp | Moves focus to the previous |
ArrowRight | Moves focus to the next |
ArrowLeft | Moves focus to the previous |
Home | When focus is on an |
End | When focus is on an |