Skip to main content
Vuetify0 is now in beta!
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

ExpansionPanel

A component for creating accordion-style expansion panels with proper ARIA support.

Usage

The ExpansionPanel component provides a wrapper and item pattern for managing expansion state in accordion-style interfaces. It uses the createSelection composable internally and provides full v-model support with automatic state synchronization.

Accordion Panels

Multiple expandable panels with accordion behavior and a multi-expand mode that allows several panels open at once.

Expanded:

Anatomy

Anatomy
<script setup lang="ts">
  import { ExpansionPanel } from '@vuetify/v0'
</script>

<template>
  <ExpansionPanel.Group>
    <ExpansionPanel.Root>
      <ExpansionPanel.Activator>
        <ExpansionPanel.Cue />
      </ExpansionPanel.Activator>

      <ExpansionPanel.Content />
    </ExpansionPanel.Root>
  </ExpansionPanel.Group>
</template>

For instances where you need to wrap the activator in a heading element (h3) for semantic purposes and WAI-ARIA, use the ExpansionPanel.Header component:

AnatomyWithHeader
<script setup lang="ts">
  import { ExpansionPanel } from '@vuetify/v0'
</script>

<template>
  <ExpansionPanel.Group>
    <ExpansionPanel.Root>
      <ExpansionPanel.Header>
        <ExpansionPanel.Activator>
          <ExpansionPanel.Cue />
        </ExpansionPanel.Activator>
      </ExpansionPanel.Header>

      <ExpansionPanel.Content />
    </ExpansionPanel.Root>
  </ExpansionPanel.Group>
</template>

Examples

Animated Transitions

By default, ExpansionPanel.Content toggles visibility with the hidden attribute — instant, but not animatable. To animate the open and close, add renderless to ExpansionPanel.Content and render your own element: the slot exposes isSelected to drive a v-if inside Vue’s <Transition>, and an attrs object you must bind to your replacement element so it keeps the component’s accessibility contract (role="region", the id targeted by the activator’s aria-controls, and aria-labelledby).

The height animation itself needs no JavaScript measurements. CSS interpolate-size: allow-keywords lets max-height transition to and from the intrinsic max-content keyword, so panels of any content size animate smoothly. Padding lives on an inner wrapper rather than the transitioned element — animating max-height on the padded element would make the content jump at the ends of the transition.

Reach for this pattern whenever panel content deserves a smooth reveal — tables, long text, nested forms. If you only need the default show and hide behavior, skip renderless entirely; the non-renderless Content keeps its element mounted and is the simpler, more accessible default for static content.

Note

interpolate-size↗︎ is currently a Chromium-only CSS feature (Chrome and Edge 129+). Other browsers skip the animation and open the panel instantly — the content itself works everywhere.

Was this page helpful?

Ctrl+/