Collapsible
An interactive component that can be expanded or collapsed.
Animation
You can use CSS animations to create smooth transitions for opening and closing the Collapsible content. Utilize the
data-state
attribute in combination with the --height
CSS variable to animate the open and closed states.
@keyframes slideDown {
from {
height: 0;
}
to {
height: var(--height);
}
}
@keyframes slideUp {
from {
height: var(--height);
}
to {
height: 0;
}
}
[data-scope='collapsible'][data-part='content'][data-state='open'] {
animation: slideDown 250ms;
}
[data-scope='collapsible'][data-part='content'][data-state='closed'] {
animation: slideUp 200ms;
}
Examples
Learn how to use the Collapsible
component in your project. Let's examine the most basic example
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronDownIcon } from 'lucide-react'
export const Basic = () => (
<Collapsible.Root>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronDownIcon } from 'lucide-solid'
export const Basic = () => (
<Collapsible.Root>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { useForwardPropsEmits } from '@ark-ui/vue'
import { Collapsible, type CollapsibleRootEmits, type CollapsibleRootProps } from '@ark-ui/vue/collapsible'
import { ChevronDownIcon } from 'lucide-vue-next'
const props = defineProps<CollapsibleRootProps>()
const emits = defineEmits<CollapsibleRootEmits>()
const localProps = useForwardPropsEmits(props, emits)
</script>
<template>
<Collapsible.Root v-bind="localProps">
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronDownIcon } from 'lucide-svelte'
</script>
<Collapsible.Root>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
Events
Use onExitComplete
callback to listen for when the Collapsible.Content
is no longer visible
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronDownIcon } from 'lucide-react'
export const OnExitComplete = () => (
<Collapsible.Root onExitComplete={() => alert('on exit')}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronDownIcon } from 'lucide-solid'
export const OnExitComplete = () => (
<Collapsible.Root onExitComplete={() => alert('on exit')}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronDownIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root @exit-complete="() => console.log('on exit')">
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronDownIcon } from 'lucide-svelte'
let logs = $state<string[]>([])
</script>
<div>
<Collapsible.Root onExitComplete={() => (logs = [...logs, `Exit complete at ${new Date().toLocaleTimeString()}`])}>
<Collapsible.Trigger>
Toggle (with exit callback)
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>This content has an exit callback</Collapsible.Content>
</Collapsible.Root>
{#if logs.length > 0}
<div style="margin-top: 1rem;">
<h4>Exit logs:</h4>
<ul>
{#each logs as log}
<li>{log}</li>
{/each}
</ul>
</div>
{/if}
</div>
Lazy Mount
To delay the mounting of the Collapsible.Content
, use the lazyMount
prop
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronDownIcon } from 'lucide-react'
export const LazyMount = () => (
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronDownIcon } from 'lucide-solid'
export const LazyMount = () => (
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronDownIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronDownIcon } from 'lucide-svelte'
</script>
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle (lazy mount)
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>This content is only mounted when opened</Collapsible.Content>
</Collapsible.Root>
Unmount on Exit
To remove the Collapsible.Content
from the DOM when it is not visible, use the unmountOnExit
prop
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronDownIcon } from 'lucide-react'
export const UnmountOnExit = () => (
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronDownIcon } from 'lucide-solid'
export const UnmountOnExit = () => (
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronDownIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronDownIcon } from 'lucide-svelte'
</script>
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle (unmount on exit)
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>This content is unmounted when closed</Collapsible.Content>
</Collapsible.Root>
Lazy Mount + Unmount on Exit
Both lazyMount
and unmountOnExit
can be combined to ensure that the component is mounted only when the Collapsible
is expanded and unmounted when it is collapsed:
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronDownIcon } from 'lucide-react'
export const LazyMountAndUnmountOnExit = () => (
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronDownIcon } from 'lucide-solid'
export const LazyMountAndUnmountOnExit = () => (
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronDownIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronDownIcon } from 'lucide-svelte'
</script>
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle (lazy + unmount)
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>This content is lazy mounted and unmounted on exit</Collapsible.Content>
</Collapsible.Root>
Root Provider
Use the useCollapsible
hook to create the collapsible store and pass it to the Collapsible.RootProvider
component.
This allows you to have maximum control over the collapsible programmatically.
import { Collapsible, useCollapsible } from '@ark-ui/react/collapsible'
import { ChevronDownIcon } from 'lucide-react'
export const RootProvider = () => {
const collapsible = useCollapsible()
return (
<>
<span>{collapsible.visible ? 'Visible' : 'Hidden'}</span>
<Collapsible.RootProvider value={collapsible}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</>
)
}
import { Collapsible, useCollapsible } from '@ark-ui/solid/collapsible'
import { ChevronDownIcon } from 'lucide-solid'
export const RootProvider = () => {
const collapsible = useCollapsible()
return (
<>
<span>{collapsible().visible ? 'Visible' : 'Hidden'}</span>
<Collapsible.RootProvider value={collapsible}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</>
)
}
<script setup lang="ts">
import { Collapsible, useCollapsible } from '@ark-ui/vue/collapsible'
import { ChevronDownIcon } from 'lucide-vue-next'
const collapsible = useCollapsible()
</script>
<template>
<span>{{ collapsible.visible ? 'Visible' : 'Hidden' }}</span>
<Collapsible.RootProvider :value="collapsible">
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</template>
<script lang="ts">
import { Collapsible, useCollapsible } from '@ark-ui/svelte/collapsible'
import { ChevronDownIcon } from 'lucide-svelte'
const id = $props.id()
const collapsible = useCollapsible({ id })
</script>
<div>
<button onclick={() => collapsible().setOpen(true)}>Open</button>
<button onclick={() => collapsible().setOpen(false)}>Close</button>
<Collapsible.RootProvider value={collapsible}>
<Collapsible.Trigger>
Toggle (with external control)
<Collapsible.Indicator>
<ChevronDownIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>This collapsible is controlled externally</Collapsible.Content>
</Collapsible.RootProvider>
</div>
If you're using the
Collapsible.RootProvider
component, you don't need to use theCollapsible.Root
component.
API Reference
Root
Prop | Default | Type |
---|---|---|
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
defaultOpen | boolean The initial open state of the collapsible when rendered. Use when you don't need to control the open state of the collapsible. | |
disabled | boolean Whether the collapsible is disabled. | |
ids | Partial<{ root: string; content: string; trigger: string }> The ids of the elements in the collapsible. Useful for composition. | |
lazyMount | false | boolean Whether to enable lazy mounting |
onExitComplete | VoidFunction The callback invoked when the exit animation completes. | |
onOpenChange | (details: OpenChangeDetails) => void The callback invoked when the open state changes. | |
open | boolean The controlled open state of the collapsible. | |
unmountOnExit | false | boolean Whether to unmount on exit. |
Data Attribute | Value |
---|---|
[data-scope] | collapsible |
[data-part] | root |
[data-state] | "open" | "closed" |
Content
Prop | Default | Type |
---|---|---|
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | collapsible |
[data-part] | content |
[data-collapsible] | |
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
Indicator
Prop | Default | Type |
---|---|---|
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | collapsible |
[data-part] | indicator |
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
RootProvider
Prop | Default | Type |
---|---|---|
value | UseCollapsibleReturn | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Trigger
Prop | Default | Type |
---|---|---|
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | collapsible |
[data-part] | trigger |
[data-state] | "open" | "closed" |
[data-disabled] | Present when disabled |
Accessibility
Keyboard Support
Key | Description |
---|---|
Space | Opens/closes the collapsible. |
Enter | Opens/closes the collapsible. |