Skip to content

Collapsible

A lightweight single-toggle component for showing and hiding content. Unlike Collapse (multi-panel accordion), Collapsible manages a single open/close state — perfect for toggleable sections, expandable details, or progressive disclosure patterns.

NameCategoryDescriptionTypeDefault
ghost? StyleGhost mode with no border or shadowbooleanfalse
color? ColorColor theme. Supports preset names (primary / success / warning / danger / info) or custom hex colorsstring
disabled? StateWhether disabledbooleanfalse
default-open? BehaviorDefault expanded state (uncontrolled mode)booleanfalse
CollapsibleTriggeras-child? BehaviorWhether to use child element as trigger (reserved)booleanfalse
model-value / v-model? ContentWhether expanded (controlled mode)boolean
change? EventTriggered when open state changes(open: boolean) => void
default? SlotContent area, should contain CollapsibleTrigger and CollapsibleContent
CollapsibleTriggerdefault? SlotTrigger content
CollapsibleContentdefault? SlotCollapsible content
open? ExposeCurrent open stateRef<boolean>
toggle? ExposeToggle open/close state() => void

Basic Usage

Click the trigger to toggle the content area.

<template>
  <div class="demo-collapsible">
    <px-collapsible>
      <px-collapsible-trigger>
        <span class="trigger-label">Click to toggle</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>This is the collapsible content. It can contain any elements.</p>
      </px-collapsible-content>
    </px-collapsible>
  </div>
</template>

<style scoped>
.demo-collapsible {
  max-width: 400px;
}
.trigger-label {
  font-weight: 500;
}
</style>

Default Open

Use the default-open prop to start with the content expanded.

<template>
  <div class="demo-collapsible">
    <px-collapsible default-open>
      <px-collapsible-trigger>
        <span class="trigger-label">Starts expanded</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>This content is visible by default when the component mounts.</p>
      </px-collapsible-content>
    </px-collapsible>
  </div>
</template>

<style scoped>
.demo-collapsible {
  max-width: 400px;
}
.trigger-label {
  font-weight: 500;
}
</style>

Disabled

Set disabled to prevent the collapsible from being toggled.

<template>
  <div class="demo-collapsible">
    <px-collapsible disabled>
      <px-collapsible-trigger>
        <span class="trigger-label">Disabled (cannot toggle)</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>This content is hidden and cannot be toggled.</p>
      </px-collapsible-content>
    </px-collapsible>
  </div>
</template>

<style scoped>
.demo-collapsible {
  max-width: 400px;
}
.trigger-label {
  font-weight: 500;
}
</style>

Color Variants

Use the color prop with preset names or custom hex values.

<template>
  <div class="demo-collapsible">
    <px-collapsible v-for="c in colors" :key="c" :color="c" default-open>
      <px-collapsible-trigger>
        <span class="trigger-label">{{ c }}</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>Content styled with {{ c }} color theme.</p>
      </px-collapsible-content>
    </px-collapsible>

    <px-collapsible color="#e64553" default-open>
      <px-collapsible-trigger>
        <span class="trigger-label">Custom hex #e64553</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>Content styled with a custom hex color.</p>
      </px-collapsible-content>
    </px-collapsible>
  </div>
</template>

<script setup lang="ts">
const colors = ['primary', 'success', 'warning', 'danger', 'info'];
</script>

<style scoped>
.demo-collapsible {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 400px;
}
.trigger-label {
  font-weight: 500;
  text-transform: capitalize;
}
</style>

Ghost

Enable ghost mode for a borderless, shadowless appearance.

<template>
  <div class="demo-collapsible">
    <px-collapsible ghost>
      <px-collapsible-trigger>
        <span class="trigger-label">Ghost mode (no border)</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>Content area without pixel border or shadow — useful when embedding inside other containers.</p>
      </px-collapsible-content>
    </px-collapsible>

    <px-collapsible ghost color="primary">
      <px-collapsible-trigger>
        <span class="trigger-label">Ghost + color</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>Ghost mode combined with a preset color.</p>
      </px-collapsible-content>
    </px-collapsible>
  </div>
</template>

<style scoped>
.demo-collapsible {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 400px;
}
.trigger-label {
  font-weight: 500;
}
</style>

Controlled State

Use v-model to control the open state from outside the component.

<template>
  <div class="demo-collapsible">
    <px-button @click="isOpen = !isOpen">
      {{ isOpen ? 'Close' : 'Open' }} from outside
    </px-button>

    <px-collapsible v-model="isOpen" color="primary">
      <px-collapsible-trigger>
        <span class="trigger-label">Controlled state: {{ isOpen ? 'Open' : 'Closed' }}</span>
      </px-collapsible-trigger>
      <px-collapsible-content>
        <p>This collapsible is controlled via <code>v-model</code>. You can toggle it from the button above or by clicking the trigger.</p>
      </px-collapsible-content>
    </px-collapsible>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';

const isOpen = ref(false);
</script>

<style scoped>
.demo-collapsible {
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: 400px;
}
.trigger-label {
  font-weight: 500;
}
</style>