Collapsible
Disclosure & LayoutLocal guide ↗
import { Collapsible } from "bits-ui" Animated content
Height and opacity animate without measuring in application code
Bundle184 kB
Health checks12 / 12
Release2026.08.30
<script lang="ts">
import { Collapsible } from 'bits-ui';
import { ChevronDown } from '@lucide/svelte';
</script>
<Collapsible.Root class="card mx-auto w-full max-w-lg overflow-hidden">
<Collapsible.Trigger
class="flex w-full items-center justify-between gap-4 px-5 py-4 text-left text-sm font-semibold hover:bg-ink-850 [&[data-state=open]_svg]:rotate-180"
>
<span>
Deployment summary
<span class="muted mt-0.5 block text-xs font-normal">3 production checks completed</span>
</span>
<ChevronDown class="size-4 shrink-0 transition-transform duration-200" />
</Collapsible.Trigger>
<Collapsible.Content class="collapsible-content border-t border-ink-800">
<div class="grid gap-3 p-5 text-sm">
<div class="flex items-center justify-between"><span class="text-ink-200">Bundle</span><span class="chip">184 kB</span></div>
<div class="flex items-center justify-between"><span class="text-ink-200">Health checks</span><span class="text-brand-400">12 / 12</span></div>
<div class="flex items-center justify-between"><span class="text-ink-200">Release</span><span class="font-mono text-xs text-ink-400">2026.08.30</span></div>
</div>
</Collapsible.Content>
</Collapsible.Root>
<style>
:global(.collapsible-content) {
overflow: hidden;
}
:global(.collapsible-content[data-state='open']) {
animation: expand 220ms ease-out;
}
:global(.collapsible-content[data-state='closed']) {
animation: collapse 180ms ease-in;
}
@keyframes expand {
from { height: 0; opacity: 0; }
to { height: var(--bits-collapsible-content-height); opacity: 1; }
}
@keyframes collapse {
from { height: var(--bits-collapsible-content-height); opacity: 1; }
to { height: 0; opacity: 0; }
}
</style>
Controlled and searchable
Bound open state plus hidden-until-found browser search integration
State: closed
Version 2.19 adds browser-find integration: searching for “connection pinning” can reveal this region even while it is collapsed.
<script lang="ts">
import { Collapsible } from 'bits-ui';
import { ChevronDown } from '@lucide/svelte';
let open = $state(false);
</script>
<div class="mx-auto grid w-full max-w-lg gap-3">
<div class="flex items-center justify-between">
<span class="muted text-xs">State: <strong class="text-ink-200">{open ? 'open' : 'closed'}</strong></span>
<button class="btn btn-sm" onclick={() => (open = !open)}>{open ? 'Close externally' : 'Open externally'}</button>
</div>
<Collapsible.Root bind:open class="rounded-xl border border-ink-800 bg-ink-900">
<Collapsible.Trigger class="flex w-full items-center justify-between px-4 py-3 text-left text-sm font-medium [&[data-state=open]_svg]:rotate-180">
Searchable release notes
<ChevronDown class="size-4 transition-transform" />
</Collapsible.Trigger>
<Collapsible.Content hiddenUntilFound class="border-t border-ink-800 px-4 py-3 text-sm leading-relaxed text-ink-400">
Version 2.19 adds browser-find integration: searching for “connection pinning” can reveal this region even while it is collapsed.
</Collapsible.Content>
</Collapsible.Root>
</div>
Content exposes --bits-collapsible-content-height and --bits-collapsible-content-width, so CSS can animate to the measured size. For Svelte transitions instead, set forceMount and render conditionally from the child snippet's open value.
hiddenUntilFound maps collapsed content to hidden="until-found", allowing supported browsers to reveal it for find-in-page matches.