Accordion
<script setup lang="ts">
import { AccordionContent, AccordionHeader, AccordionItem, AccordionRoot, AccordionTrigger } from 'radix-vue'
import { Icon } from '@iconify/vue'
const accordionItems = [
{
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>
<AccordionRoot
class="bg-mauve6 w-[300px] rounded-md shadow-[0_2px_10px] shadow-black/5"
default-value="item-1"
type="single"
:collapsible="true"
>
<template
v-for="item in accordionItems"
:key="item.value"
>
<AccordionItem
class="focus-within:shadow-mauve12 mt-px overflow-hidden first:mt-0 first:rounded-t last:rounded-b focus-within:relative focus-within:z-10 focus-within:shadow-[0_0_0_2px]"
:value="item.value"
>
<AccordionHeader class="flex">
<AccordionTrigger class="text-grass11 shadow-mauve6 hover:bg-mauve2 flex h-[45px] flex-1 cursor-default items-center justify-between bg-white px-5 text-[15px] leading-none shadow-[0_1px_0] outline-none group">
<span>{{ item.title }}</span>
<Icon
icon="radix-icons:chevron-down"
class="text-green10 ease-[cubic-bezier(0.87,_0,_0.13,_1)] transition-transform duration-300 group-data-[state=open]:rotate-180"
aria-label="Expand/Collapse"
/>
</AccordionTrigger>
</AccordionHeader>
<AccordionContent class="text-mauve11 bg-mauve2 data-[state=open]:animate-slideDown data-[state=closed]:animate-slideUp overflow-hidden text-[15px]">
<div class="px-5 py-4">
{{ item.content }}
</div>
</AccordionContent>
</AccordionItem>
</template>
</AccordionRoot>
</template>Features
- Full keyboard navigation.
- Supports horizontal/vertical orientation.
- Supports Right to Left direction.
- Can expand one or multiple items.
- Can be controlled or uncontrolled.
Installation
Install the component from your command line.
$ npm add radix-vueAnatomy
Import all parts and piece them together.
<script setup>
import { AccordionContent, AccordionHeader, AccordionItem, AccordionRoot, AccordionTrigger } from 'radix-vue'
</script>
<template>
<AccordionRoot>
<AccordionItem>
<AccordionHeader>
<AccordionTrigger />
</AccordionHeader>
<AccordionContent />
</AccordionItem>
</AccordionRoot>
</template>API Reference
Root
Contains all the parts of an Accordion
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite 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[]The controlled value of the active item(s). Use this when you need to control the state of the items. Can be binded with | |
orientation | 'vertical' | 'vertical' | 'horizontal'The orientation of the accordion. |
type | 'single' | 'multiple'Determines whether a "single" or "multiple" items can be pressed at a time. This prop will be ignored if any of |
| Emit | Payload |
|---|---|
update:modelValue | [value: string | string[]]Event handler called when the expanded state of an item changes |
| Slots (default) | Payload |
|---|---|
modelValue | string | string[] | undefinedCurrent active value |
| Data Attribute | Value |
|---|---|
[data-orientation] | "vertical" | "horizontal" |
Item
Contains all the parts of a collapsible section.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite 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 | booleanWhether or not an accordion item is disabled from user interaction.
When | |
value* | stringA string value for the accordion item. All items within an accordion should use a unique value. |
| Slots (default) | Payload |
|---|---|
open | booleanCurrent open state |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Header
Wraps an AccordionTrigger. Use the asChild prop to update it to the appropriate heading level for your page.
| Prop | Default | Type |
|---|---|---|
as | 'h3' | AsTag | ComponentThe element or component this component should render as. Can be overwrite 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. |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Trigger
Toggles the collapsed state of its associated item. It should be nested inside of an AccordionHeader.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite 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. |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Content
Contains the collapsible content for an item.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite 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. |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
| CSS Variable | Description |
|---|---|
--radix-accordion-content-width | The width of the content when it opens/closes |
--radix-accordion-content-height | The height of the content when it opens/closes |
Examples
Expanded by default
Use the defaultValue prop to define the open item by default.
<template>
<AccordionRoot
type="single"
default-value="item-2"
>
<AccordionItem value="item-1">
…
</AccordionItem>
<AccordionItem value="item-2">
…
</AccordionItem>
</AccordionRoot>
</template>Allow collapsing all items
Use the collapsible prop to allow all items to close.
<template>
<AccordionRoot
type="single"
collapsible
>
<AccordionItem value="item-1">
…
</AccordionItem>
<AccordionItem value="item-2">
…
</AccordionItem>
</AccordionRoot>
</template>Multiple items open at the same time
Set the type prop to multiple to enable opening multiple items at once.
<template>
<AccordionRoot type="multiple">
<AccordionItem value="item-1">
…
</AccordionItem>
<AccordionItem value="item-2">
…
</AccordionItem>
</AccordionRoot>
</template>Rotated icon when open
You can add extra decorative elements, such as chevrons, and rotate it when the item is open.
// index.vue
<script setup>
import { AccordionContent, AccordionHeader, AccordionItem, AccordionRoot, AccordionTrigger } from 'radix-vue'
import { Icon } from '@iconify/vue'
import './styles.css'
</script>
<template>
<AccordionRoot type="single">
<AccordionItem value="item-1">
<AccordionHeader>
<AccordionTrigger class="AccordionTrigger">
<span>Trigger text</span>
<Icon
icon="radix-icons:chevron-down"
class="AccordionChevron"
/>
</AccordionTrigger>
</AccordionHeader>
<AccordionContent>…</AccordionContent>
</AccordionItem>
</AccordionRoot>
</template>/* styles.css */
.AccordionChevron {
transition: transform 300ms;
}
.AccordionTrigger[data-state="open"] > .AccordionChevron {
transform: rotate(180deg);
}Horizontal orientation
Use the orientation prop to create a horizontal Accordion
<template>
<AccordionRoot orientation="horizontal">
<AccordionItem value="item-1">
…
</AccordionItem>
<AccordionItem value="item-2">
…
</AccordionItem>
</AccordionRoot>
</template>Animating content size
Use the --radix-accordion-content-width and/or --radix-accordion-content-height CSS variables to animate the size of the content when it opens/closes:
// index.vue
<script setup>
import { AccordionContent, AccordionHeader, AccordionItem, AccordionRoot, AccordionTrigger } from 'radix-vue'
import './styles.css'
</script>
<template>
<AccordionRoot type="single">
<AccordionItem value="item-1">
<AccordionHeader>…</AccordionHeader>
<AccordionContent class="AccordionContent">
…
</AccordionContent>
</AccordionItem>
</AccordionRoot>
</template>/* styles.css */
.AccordionContent {
overflow: hidden;
}
.AccordionContent[data-state="open"] {
animation: slideDown 300ms ease-out;
}
.AccordionContent[data-state="closed"] {
animation: slideUp 300ms ease-out;
}
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--radix-accordion-content-height);
}
}
@keyframes slideUp {
from {
height: var(--radix-accordion-content-height);
}
to {
height: 0;
}
}Accessibility
Adheres to the Accordion WAI-ARIA design pattern.
Keyboard Interactions
| Key | Description |
|---|---|
Space | When focus is on an AccordionTrigger of a collapsed section, expands the section. |
Enter | When focus is on an AccordionTrigger of a collapsed section, expands the section. |
Tab | Moves focus to the next focusable element. |
Shift + Tab | Moves focus to the previous focusable element. |
ArrowDown | Moves focus to the next AccordionTrigger when orientation is vertical. |
ArrowUp | Moves focus to the previous AccordionTrigger when orientation is vertical. |
ArrowRight | Moves focus to the next AccordionTrigger when orientation is horizontal. |
ArrowLeft | Moves focus to the previous AccordionTrigger when orientation is horizontal. |
Home | When focus is on an AccordionTrigger, moves focus to the start AccordionTrigger. |
End | When focus is on an AccordionTrigger, moves focus to the last AccordionTrigger. |