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-hidden
/>
</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 install radix-vue
Anatomy
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 | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change 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 | boolean When 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 value of the item to expand when type is "single" or the default values of the items to expand when type is "multiple". 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 | boolean When |
modelValue | string | string[] The controlled value of the item to expand when type is "single" or the controlled values of the items to expand when type is "multiple". | |
orientation | 'vertical' | 'vertical' | 'horizontal' The orientation of the accordion. |
type* | 'single' | 'multiple' Determines whether one or multiple items can be opened at the same time. |
Emit | Payload |
---|---|
update:modelValue | [value: string | string[]] Event handler called when the expanded state of an item changes |
Slots (default) | Payload |
---|---|
modelValue | string | string[] | undefined Current active value |
Data Attribute | Value |
---|---|
[data-orientation] | "vertical" | "horizontal" |
Item
Contains all the parts of a collapsible section.
Prop | Default | Type |
---|---|---|
as | 'div' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | boolean Whether or not an accordion item is disabled from user interaction.
When | |
value* | string A string value for the accordion item. All items within an accordion should use a unique value. |
Slots (default) | Payload |
---|---|
open | boolean Current 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 | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change 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 | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change 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 | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change 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" aria-hidden />
</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 . |