<script setup lang="ts">
import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from 'akar';
import { ref } from 'vue';
import './styles.css';
const open = ref(false);
</script>
<template>
<div class="akar-demo akar-demo-Collapsible">
<CollapsibleRoot
v-model:open="open"
class="CollapsibleRoot"
>
<div style="display: flex; align-items: center; justify-content: space-between">
<span class="Text"> @peduarte starred 3 repos </span>
<CollapsibleTrigger
class="IconButton"
>
<PIcon
v-if="open"
name="i-lucide-x"
/>
<PIcon
v-else
name="i-lucide-unfold-vertical"
/>
</CollapsibleTrigger>
</div>
<div class="Repository">
<span class="Text">@unovue/reka-ui</span>
</div>
<CollapsibleContent>
<div class="Repository">
<span class="Text">@vuejs/core</span>
</div>
<div class="Repository">
<span class="Text">@radix-ui/primitives</span>
</div>
</CollapsibleContent>
</CollapsibleRoot>
</div>
</template>@import '../_colors/black-alpha.css';
@import '../_colors/grass.css';
@scope (.akar-demo-Collapsible) {
/* reset */
button {
all: unset;
}
.CollapsibleRoot {
width: 300px;
}
.IconButton {
font-family: inherit;
border-radius: 100%;
height: 25px;
width: 25px;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--grass-11);
box-shadow: 0 2px 10px var(--black-a7);
}
.IconButton[data-state='closed'] {
background-color: white;
}
.IconButton[data-state='open'] {
background-color: var(--grass-3);
}
.IconButton:hover {
background-color: var(--grass-3);
}
.IconButton:focus {
box-shadow: 0 0 0 2px black;
}
.Text {
color: var(--grass-11);
font-size: 15px;
line-height: 25px;
}
.Repository {
background-color: white;
border-radius: 4px;
margin: 10px 0;
padding: 10px;
box-shadow: 0 2px 10px var(--black-a7);
}
}Features
- Full keyboard navigation.
- Can be controlled or uncontrolled.
Installation
Install the component from your command line.
pnpm add akar
yarn add akar
npm install akar
bun add akar
Anatomy
Import the components and piece the parts together.
<script setup>
import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from 'akar';
</script>
<template>
<CollapsibleRoot>
<CollapsibleTrigger />
<CollapsibleContent />
</CollapsibleRoot>
</template>
API Reference
Root
Contains all the parts of a collapsible
| Prop | Default | Type |
|---|---|---|
as | "div" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
defaultOpen | false | booleanThe open state of the collapsible when it is initially rendered. Use when you do not need to control its open state. |
disabled | booleanWhen | |
open | booleanThe controlled open state of the collapsible. Can be binded with | |
unmountOnHide | true | booleanWhen |
| Event | Payload |
|---|---|
update:open | value: booleanEvent handler called when the open state of the collapsible changes. |
| Slot (default) | Payload |
|---|---|
open | booleanCurrent open state |
| Data attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
Trigger
The button that toggles the collapsible
| Prop | Default | Type |
|---|---|---|
as | "button" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Data attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
Content
The component that contains the collapsible content.
| Prop | Default | Type |
|---|---|---|
as | "div" | AsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |
| Event | Payload |
|---|---|
contentFound | (void)? |
| Data attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
| CSS variable | Description |
|---|---|
--akar-collapsible-content-width | The width of the content when it opens/closes |
--akar-collapsible-content-height | The height of the content when it opens/closes |
Examples
Animating content size
Use the --akar-collapsible-content-width and/or --akar-collapsible-content-height CSS variables to animate the size of the content when it opens/closes. Here's a demo:
// index.vue
<script setup>
import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from 'akar'
import './styles.css'
</script>
<template>
<CollapsibleRoot>
<CollapsibleTrigger>…</CollapsibleTrigger>
<CollapsibleContent class="CollapsibleContent">
…
</CollapsibleContent>
</CollapsibleRoot>
</template>
/* styles.css */
.CollapsibleContent {
overflow: hidden;
}
.CollapsibleContent[data-state="open"] {
animation: slideDown 300ms ease-out;
}
.CollapsibleContent[data-state="closed"] {
animation: slideUp 300ms ease-out;
}
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--akar-collapsible-content-height);
}
}
@keyframes slideUp {
from {
height: var(--akar-collapsible-content-height);
}
to {
height: 0;
}
}
Render content even when collapsed
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 collapsible.
<script setup>
import { CollapsibleContent, CollapsibleRoot, CollapsibleTrigger } from 'akar'
</script>
<template>
<CollapsibleRoot :unmount-on-hide="false">
…
</CollapsibleRoot>
</template>
Accessibility
Adheres to the Disclosure WAI-ARIA design pattern.
Keyboard Interactions
| Key | Description |
|---|---|
| Space | Opens/closes the collapsible |
| Enter | Opens/closes the collapsible |