Accordion

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

Yes. It adheres to the WAI-ARIA design pattern.

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

Features

  • Full keyboard navigation.
  • Supports horizontal/vertical orientation.
  • Supports Right to Left direction.
  • Can expand one or multiple items.
  • Can be controlled or uncontrolled.

Anatomy

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>

Pohon

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.

API Reference

Root

Contains all the parts of an Accordion

Props

Prop Default Type
as'div'APrimitiveAsTag | Component

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

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

collapsiblefalseboolean

When type is 'single', allows closing content when clicking trigger for an open item. When type is 'multiple', this prop has no effect.

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

disabledfalseboolean

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

modelValuestring | 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 modelValue and defaultValue.

unmountOnHidetrueboolean

When true, the element will be unmounted on closed state.

Emits

Event Type
update:modelValue[value: string | string[]]

Event handler called when the expanded state of an item changes

Slots

Slot Type
modelValueAcceptableValue | 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 v-model

Data Attributes

Attribute Value
[data-orientation]'vertical' | 'horizontal'

Item

Contains all the parts of a collapsible section.

Props

Prop Default Type
as'div'APrimitiveAsTag | Component

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

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

disabledboolean

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

unmountOnHideboolean

When true, the element will be unmounted on closed state.

value*string

A string value for the accordion item. All items within an accordion should use a unique value.

Slots

Slot Type
openboolean

Current open state

Data Attributes

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.

Props

Prop Default Type
as'h3'APrimitiveAsTag | Component

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

asChildboolean

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 Attributes

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

Props

Prop Default Type
as'div'APrimitiveAsTag | Component

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

asChildboolean

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 Attributes

Attribute Value
[data-state]'open' | 'closed'
[data-disabled]Present when disabled
[data-orientation]'vertical' | 'horizontal'

Content

Contains the collapsible content for an item.

Props

Prop Default Type
as'div'APrimitiveAsTag | Component

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

asChildboolean

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read our Composition guide for more details.

forceMountboolean

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

Data Attributes

Attribute Value
[data-state]'open' | 'closed'
[data-disabled]Present when disabled
[data-orientation]'vertical' | 'horizontal'

CSS Variables

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

Examples

Expanded by default

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>

Allow collapsing all items

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>

Multiple items open at the same time

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>

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

Horizontal orientation

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>

Animating content size

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;
  }
}

UnoCSS Preset

By installing the Vinicunca Preset, you gain immediate access to pre-defined animation keyframes. This means the utility classes animate-accordion-up and animate-accordion-down are available right out of the box, saving you the step of manually creating them.

Render content even when closed

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>

Accessibility

Adheres to the Accordion WAI-ARIA design pattern.

Keyboard Interactions

Key Description
Space

When focus is on an AAccordionTrigger of a collapsed section, expands the section.

Enter

When focus is on an AAccordionTrigger 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 AAccordionTrigger when orientation is vertical.

ArrowUp

Moves focus to the previous AAccordionTrigger when orientation is vertical.

ArrowRight

Moves focus to the next AAccordionTrigger when orientation is horizontal.

ArrowLeft

Moves focus to the previous AAccordionTrigger when orientation is horizontal.

Home

When focus is on an AAccordionTrigger, moves focus to the start AAccordionTrigger.

End

When focus is on an AAccordionTrigger, moves focus to the last AAccordionTrigger.