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>
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>
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>
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>
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>
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>
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. |