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

Collapsible

A single-item disclosure toggle for showing and hiding content.

Usage

The Collapsible component provides a simple open/closed toggle for a single content region. It supports v-model for controlled state and exposes data-state attributes for CSS-driven styling.

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

<template>
  <Collapsible.Root
    class="border border-divider rounded-lg border-solid overflow-hidden"
  >
    <Collapsible.Activator
      class="w-full px-3 py-2 border-none flex items-center gap-3 text-left cursor-pointer bg-surface hover:bg-surface-tint"
    >
      <Collapsible.Cue class="inline-flex items-center justify-center w-5 text-sm text-on-surface opacity-60 data-[state=open]:text-primary">
        <span class="data-[state=open]:hidden">+</span>
        <span class="hidden data-[state=open]:inline">&minus;</span>
      </Collapsible.Cue>

      <span class="flex-1 font-medium text-on-surface text-base">
        Toggle content
      </span>
    </Collapsible.Activator>

    <Collapsible.Content class="px-3 py-2 border-t border-divider border-solid">
      <div class="text-on-surface text-sm">
        This content can be toggled open and closed. The Collapsible component manages a single boolean state with full keyboard and accessibility support.
      </div>
    </Collapsible.Content>
  </Collapsible.Root>
</template>

Anatomy

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

<template>
  <Collapsible.Root>
    <Collapsible.Activator>
      <Collapsible.Cue />
    </Collapsible.Activator>
    <Collapsible.Content />
  </Collapsible.Root>
</template>

Examples

Filters sidebar

A product-filters sidebar built from several independent Collapsible sections — Price, Brand, and Rating — whose open state lives in a single reactive map instead of each section tracking its own boolean. Every section binds v-model to open[section.id], so the Expand all and Collapse all buttons flip every section at once by mutating that one object, while a user clicking an individual activator still toggles only that section. This externally-owned open state is the main reason to reach for Collapsible over a self-contained accordion: each instance is independent, and you decide where the state lives and who is allowed to change it.

The Collapsible.Cue inside each activator mirrors its Root’s data-state, so the chevron rotation is pure CSS — data-[state=open]:rotate-180 — with no slot prop or watcher. The filter controls themselves compose other v0 primitives rather than native inputs: Price and Brand use a Checkbox group with an array v-model, and Rating uses a single-select Radio group. All three read and write one shared filters object that drives the active-filter count and the summary chips below the panel.

Reach for this pattern whenever sections must be controllable from outside — a clear-filters action, deep-linking a specific section open, or restoring panel state from storage. The trade-off is that you own the coordination logic: nothing stops two sections from being open at once. If you instead want strict “only one section open at a time” accordion behavior, use ExpansionPanel, which coordinates selection across panels through a shared parent context.

FileRole
useFilterPanel.tsOwns the section open-state map, filter selections, and the derived count, chips, and expand/collapse/clear actions
FilterPanel.vueRenders the Collapsible sections with Checkbox and Radio controls plus the expand/collapse header
filter-panel.vueWires the composable to the panel and renders the active-filter summary
Filters
0 active filters

No filters applied — showing all products.

FAQ

Each FAQ item is an independent Collapsible.Root — they share no state, so opening one never collapses another. The example extracts FaqItem.vue as a reusable wrapper that accepts a question prop and a default slot for the answer, keeping the entry-point file (faq.vue) a clean data-driven list.

Collapsible.Cue inside the activator automatically mirrors the data-state of its parent Root, so the chevron rotation is wired up with a single CSS transition class — no slot prop or manual binding needed.

When you need “only one open at a time” behavior, reach for ExpansionPanel instead. It coordinates selection across all panels through a shared parent context, making accordion mode a one-prop change.

FileRole
FaqItem.vueReusable wrapper around Collapsible with chevron rotation
faq.vueEntry point rendering items from data

Recipes

Collapsible vs ExpansionPanel

Both components handle expanding and collapsing content, but they solve different problems:

CollapsibleExpansionPanel
ItemsSingleMultiple
StateBoolean (open / closed)Selection set (IDs)
CoordinationNone — each instance is independentShared — accordion mode, mandatory, enroll
v-modelv-model (boolean)v-model (ID or ID[])
Built oncreateSinglecreateSelection

Use Collapsible when you have a single region to show/hide — a details section, a settings panel, a mobile navigation drawer. Each Collapsible is independent.

Use ExpansionPanel when you have a list of items where expanding one may collapse another — an FAQ, a settings page with sections, an accordion sidebar.

Tip

You can build an FAQ from multiple independent Collapsible instances (see the FAQ example above), but if you need “only one open at a time” behavior, use ExpansionPanel instead — it handles that coordination for you.

Accessibility

Collapsible follows the WAI-ARIA Disclosure pattern↗︎.

Keyboard

KeyAction
EnterToggles the content
SpaceToggles the content

ARIA

AttributeElementValue
aria-expandedActivatortrue when open, false when closed
aria-controlsActivatorPoints to the content element’s id
role="region"ContentLandmarks the content area
aria-labelledbyContentPoints back to the activator’s id

Data attributes

All three sub-components expose data-state="open" or data-state="closed" for CSS-driven styling without JavaScript. The Root and Activator also expose data-disabled when the disabled prop is set.

FAQ

Discord
Need help? Join our community for support and discussions ↗
Was this page helpful?

Ctrl+/