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 { ChevronRightIcon } from 'lucide-react'
export const Basic = () => (
<Collapsible.Root>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const Basic = () => (
<Collapsible.Root>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</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 { ChevronRightIcon } 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>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRightIcon } from 'lucide-svelte'
</script>
<Collapsible.Root>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
Disabled
Use the disabled
prop to disable the collapsible and prevent it from being toggled.
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronRightIcon } from 'lucide-react'
export const Disabled = () => (
<Collapsible.Root disabled>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const Disabled = () => (
<Collapsible.Root disabled>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root disabled>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRight } from 'lucide-svelte'
</script>
<Collapsible.Root disabled>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRight />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
Partial Collapse
Use the collapsedHeight
or collapsedWidth
props to create a "show more/less" pattern. When set, the content
maintains the specified dimensions when collapsed instead of collapsing to 0px.
We expose the --collapsed-height
or --collapsed-width
variables to use in your CSS animations.
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronRightIcon } from 'lucide-react'
export const PartialCollapse = () => (
<Collapsible.Root collapsedHeight="100px">
<Collapsible.Trigger>
Show More
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
<p>
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem
aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</p>
</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const PartialCollapse = () => (
<Collapsible.Root collapsedHeight="100px">
<Collapsible.Trigger>
Show More
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
<p>
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem
aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</p>
</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root collapsed-height="100px">
<Collapsible.Trigger>
Show More
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
<p>
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem
aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
</p>
</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRight } from 'lucide-svelte'
</script>
<Collapsible.Root collapsedHeight="100px">
<Collapsible.Trigger>
Show More
<Collapsible.Indicator>
<ChevronRight />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco
laboris nisi ut aliquip ex ea commodo consequat.
</p>
<p>
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla
pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt
mollit anim id est laborum.
</p>
<p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque
laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi
architecto beatae vitae dicta sunt explicabo.
</p>
</Collapsible.Content>
</Collapsible.Root>
Interactive elements (links, buttons, inputs) within the collapsed area automatically become
inert
to prevent keyboard navigation to hidden content.
Nested Collapsibles
You can nest collapsibles within collapsibles to create hierarchical content structures.
import { Collapsible } from '@ark-ui/react/collapsible'
import { ChevronRightIcon } from 'lucide-react'
export const NestedCollapsible = () => (
<Collapsible.Root>
<Collapsible.Trigger>
Getting Started
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Welcome to the documentation. Here are some topics to explore:</p>
<Collapsible.Root>
<Collapsible.Trigger>
Installation
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>To install the package, run one of the following commands:</p>
<p>npm install @ark-ui/react</p>
</Collapsible.Content>
</Collapsible.Root>
<Collapsible.Root>
<Collapsible.Trigger>
Configuration
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Configure your project settings to use Ark UI components.</p>
</Collapsible.Content>
</Collapsible.Root>
</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const NestedCollapsible = () => (
<Collapsible.Root>
<Collapsible.Trigger>
Getting Started
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Welcome to the documentation. Here are some topics to explore:</p>
<Collapsible.Root>
<Collapsible.Trigger>
Installation
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>To install the package, run one of the following commands:</p>
<p>npm install @ark-ui/solid</p>
</Collapsible.Content>
</Collapsible.Root>
<Collapsible.Root>
<Collapsible.Trigger>
Configuration
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Configure your project settings to use Ark UI components.</p>
</Collapsible.Content>
</Collapsible.Root>
</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root>
<Collapsible.Trigger>
Getting Started
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Welcome to the documentation. Here are some topics to explore:</p>
<Collapsible.Root>
<Collapsible.Trigger>
Installation
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>To install the package, run one of the following commands:</p>
<p>npm install @ark-ui/vue</p>
</Collapsible.Content>
</Collapsible.Root>
<Collapsible.Root>
<Collapsible.Trigger>
Configuration
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Configure your project settings to use Ark UI components.</p>
</Collapsible.Content>
</Collapsible.Root>
</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRightIcon } from 'lucide-svelte'
</script>
<Collapsible.Root>
<Collapsible.Trigger>
Getting Started
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Welcome to the documentation. Here are some topics to explore:</p>
<Collapsible.Root>
<Collapsible.Trigger>
Installation
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>To install the package, run one of the following commands:</p>
<p>npm install @ark-ui/svelte</p>
</Collapsible.Content>
</Collapsible.Root>
<Collapsible.Root>
<Collapsible.Trigger>
Configuration
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>
<p>Configure your project settings to use Ark UI components.</p>
</Collapsible.Content>
</Collapsible.Root>
</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 { ChevronRightIcon } from 'lucide-react'
export const OnExitComplete = () => (
<Collapsible.Root onExitComplete={() => alert('on exit')}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const OnExitComplete = () => (
<Collapsible.Root onExitComplete={() => alert('on exit')}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root @exit-complete="() => console.log('on exit')">
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRightIcon } 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>
<ChevronRightIcon />
</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 { ChevronRightIcon } from 'lucide-react'
export const LazyMount = () => (
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const LazyMount = () => (
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRightIcon } from 'lucide-svelte'
</script>
<Collapsible.Root lazyMount>
<Collapsible.Trigger>
Toggle (lazy mount)
<Collapsible.Indicator>
<ChevronRightIcon />
</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 { ChevronRightIcon } from 'lucide-react'
export const UnmountOnExit = () => (
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const UnmountOnExit = () => (
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRightIcon } from 'lucide-svelte'
</script>
<Collapsible.Root unmountOnExit>
<Collapsible.Trigger>
Toggle (unmount on exit)
<Collapsible.Indicator>
<ChevronRightIcon />
</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 { ChevronRightIcon } from 'lucide-react'
export const LazyMountAndUnmountOnExit = () => (
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
import { Collapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const LazyMountAndUnmountOnExit = () => (
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
)
<script setup lang="ts">
import { Collapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
</script>
<template>
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.Root>
</template>
<script lang="ts">
import { Collapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRightIcon } from 'lucide-svelte'
</script>
<Collapsible.Root lazyMount unmountOnExit>
<Collapsible.Trigger>
Toggle (lazy + unmount)
<Collapsible.Indicator>
<ChevronRightIcon />
</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 { ChevronRightIcon } 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>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</>
)
}
import { Collapsible, useCollapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } 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>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</>
)
}
<script setup lang="ts">
import { Collapsible, useCollapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
const collapsible = useCollapsible()
</script>
<template>
<span>{{ collapsible.visible ? 'Visible' : 'Hidden' }}</span>
<Collapsible.RootProvider :value="collapsible">
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</template>
<script lang="ts">
import { Collapsible, useCollapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRightIcon } 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>
<ChevronRightIcon />
</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.
Programmatic Control
Use the useCollapsible
hook with Collapsible.RootProvider
to programmatically control the collapsible using the
setOpen()
method and read state properties like open
and visible
.
import { Collapsible, useCollapsible } from '@ark-ui/react/collapsible'
import { ChevronRightIcon } from 'lucide-react'
export const ProgrammaticOpen = () => {
const collapsible = useCollapsible()
return (
<>
<div>
<p>
Open: <strong>{String(collapsible.open)}</strong>
</p>
<p>
Visible: <strong>{String(collapsible.visible)}</strong>
</p>
</div>
<div style={{ display: 'flex', gap: '8px', marginTop: '8px' }}>
<button type="button" onClick={() => collapsible.setOpen(true)}>
Open
</button>
<button type="button" onClick={() => collapsible.setOpen(false)}>
Close
</button>
</div>
<Collapsible.RootProvider value={collapsible}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</>
)
}
import { Collapsible, useCollapsible } from '@ark-ui/solid/collapsible'
import { ChevronRightIcon } from 'lucide-solid'
export const ProgrammaticOpen = () => {
const collapsible = useCollapsible()
return (
<>
<div>
<p>
Open: <strong>{String(collapsible().open)}</strong>
</p>
<p>
Visible: <strong>{String(collapsible().visible)}</strong>
</p>
</div>
<div style={{ display: 'flex', gap: '8px', 'margin-top': '8px' }}>
<button type="button" onClick={() => collapsible().setOpen(true)}>
Open
</button>
<button type="button" onClick={() => collapsible().setOpen(false)}>
Close
</button>
</div>
<Collapsible.RootProvider value={collapsible}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</>
)
}
<script setup lang="ts">
import { Collapsible, useCollapsible } from '@ark-ui/vue/collapsible'
import { ChevronRightIcon } from 'lucide-vue-next'
const collapsible = useCollapsible()
</script>
<template>
<div>
<p>
Open:
<strong>{{ String(collapsible.open) }}</strong>
</p>
<p>
Visible:
<strong>{{ String(collapsible.visible) }}</strong>
</p>
</div>
<div style="display: flex; gap: 8px; margin-top: 8px">
<button type="button" @click="collapsible.setOpen(true)">Open</button>
<button type="button" @click="collapsible.setOpen(false)">Close</button>
</div>
<Collapsible.RootProvider :value="collapsible">
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRightIcon />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
</template>
<script lang="ts">
import { Collapsible, useCollapsible } from '@ark-ui/svelte/collapsible'
import { ChevronRight } from 'lucide-svelte'
const collapsible = useCollapsible()
</script>
<div>
<p>
Open: <strong>{String(collapsible().open)}</strong>
</p>
<p>
Visible: <strong>{String(collapsible().visible)}</strong>
</p>
</div>
<div style="display: flex; gap: 8px; margin-top: 8px">
<button type="button" onclick={() => collapsible().setOpen(true)}>Open</button>
<button type="button" onclick={() => collapsible().setOpen(false)}>Close</button>
</div>
<Collapsible.RootProvider value={collapsible}>
<Collapsible.Trigger>
Toggle
<Collapsible.Indicator>
<ChevronRight />
</Collapsible.Indicator>
</Collapsible.Trigger>
<Collapsible.Content>Content</Collapsible.Content>
</Collapsible.RootProvider>
Guides
Animating the Indicator
To rotate the indicator icon (such as a chevron) when the collapsible opens and closes, use CSS transforms with the
data-state
attribute:
[data-scope='collapsible'][data-part='indicator'] {
transition: transform 200ms;
&[data-state='open'] {
transform: rotate(180deg);
}
}
open
vs visible
When using useCollapsible
or useCollapsibleContext
, you can access the open
and visible
state properties. They
seem similar but serve different purposes:
-
open
: Indicates the intended state of the collapsible. This istrue
when the collapsible should be expanded andfalse
when it should be collapsed. This changes immediately when triggered. -
visible
: Indicates whether the content is currently visible in the DOM. This accounts for exit animations - the content remainsvisible
while the closing animation plays, even thoughopen
is alreadyfalse
. Once the animation completes,visible
becomesfalse
.
Animating the Content
Use the --height
and/or --width
CSS variables to animate the size of the content when it expands or closes.
If you use collapsedHeight
or collapsedWidth
, update your CSS animations to use the --collapsed-height
or
--collapsed-width
variables as the starting/ending point:
@keyframes expand {
from {
height: var(--collapsed-height, 0);
}
to {
height: var(--height);
}
}
@keyframes collapse {
from {
height: var(--height);
}
to {
height: var(--collapsed-height, 0);
}
}
[data-scope='collapsible'][data-part='content'] {
&[data-state='open'] {
animation: expand 250ms;
}
&[data-state='closed'] {
animation: collapse 250ms;
}
}
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. |
CSS Variable | Description |
---|---|
--height | The height of the element |
--width | The width of the element |
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. |