Skip to content

Accordion

A vertically stacked set of interactive headings that each reveal an associated section of content.

vue
<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.

sh
$ npm add radix-vue

Anatomy

Import all parts and piece them together.

vue
<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

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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 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
boolean

When true, prevents the user from interacting with the accordion and all its items

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 v-model

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 v-model or defaultValue is defined, as the type will be inferred from the value.

EmitPayload
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 AttributeValue
[data-orientation]"vertical" | "horizontal"

Item

Contains all the parts of a collapsible section.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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 true, prevents the user from interacting with the item.

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 AttributeValue
[data-state]"open" | "closed"
[data-disabled]Present when disabled
[data-orientation]"vertical" | "horizontal"

Wraps an AccordionTrigger. Use the asChild prop to update it to the appropriate heading level for your page.

PropDefaultType
as
'h3'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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 AttributeValue
[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.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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 AttributeValue
[data-state]"open" | "closed"
[data-disabled]Present when disabled
[data-orientation]"vertical" | "horizontal"

Content

Contains the collapsible content for an item.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

forceMount
boolean

Used to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries.

Data AttributeValue
[data-state]"open" | "closed"
[data-disabled]Present when disabled
[data-orientation]"vertical" | "horizontal"
CSS VariableDescription
--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.

vue
<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.

vue
<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.

vue
<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.

vue
// 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>
css
/* 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

vue
<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:

vue
// 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>
css
/* 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

KeyDescription
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.