Collapsible
A shadcn-style collapsible component built with Ark UI primitives.
Ark UI provides accessible, headless primitives you can style with your own design system.
import { ChevronDownIcon } from "lucide-react";
import {
Collapsible,
CollapsibleContent,
CollapsibleIndicator,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
const CollapsibleDemo = () => {
return (
<Collapsible className="w-full max-w-md">
<CollapsibleTrigger className="flex w-full items-center justify-between rounded-lg border border-border px-3 py-2 text-left font-medium text-sm transition-colors hover:bg-muted">
What is Ark UI?
<CollapsibleIndicator
className="text-muted-foreground transition-transform data-[state=open]:rotate-180"
aria-hidden
>
<ChevronDownIcon className="size-4" />
</CollapsibleIndicator>
</CollapsibleTrigger>
<CollapsibleContent className="rounded-md px-3 py-2">
<p className="text-muted-foreground text-sm leading-relaxed">
Ark UI provides accessible, headless primitives you can style with
your own design system.
</p>
</CollapsibleContent>
</Collapsible>
);
};
export default CollapsibleDemo;
Installation
npx shadcn@latest add @ark-cn/collapsibleInstall the dependency required by this primitive:
npm install @ark-ui/reactCopy the component source into your app:
"use client";
import { Collapsible as CollapsiblePrimitive } from "@ark-ui/react/collapsible";
import { cn } from "@/lib/utils";
export const Collapsible = ({
className,
...props
}: CollapsiblePrimitive.RootProps) => {
return (
<CollapsiblePrimitive.Root
data-slot="collapsible"
className={cn("flex w-full flex-col gap-2", className)}
{...props}
/>
);
};
export const CollapsibleTrigger = CollapsiblePrimitive.Trigger;
export const CollapsibleContent = ({
className,
children,
...props
}: CollapsiblePrimitive.ContentProps) => {
return (
<CollapsiblePrimitive.Content
data-slot="collapsible-content"
className={cn(
"overflow-hidden text-sm [--radix-collapsible-content-height:var(--height)] data-[state=open]:animate-collapsible-down data-[state=closed]:animate-collapsible-up",
className,
)}
{...props}
>
{children}
</CollapsiblePrimitive.Content>
);
};
export const CollapsibleIndicator = CollapsiblePrimitive.Indicator;
export const CollapsibleContext = CollapsiblePrimitive.Context;
Update import aliases to match your project setup.
Usage
import * as Collapsible from "@/components/ui/collapsible"Read exported parts in src/components/ui/collapsible.tsx and compose the primitive according to the Ark UI pattern for this component.
Examples
Ark UI provides accessible, headless primitives you can style with your own design system.
import { ChevronDownIcon } from "lucide-react";
import {
Collapsible,
CollapsibleContent,
CollapsibleIndicator,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
const CollapsibleDemo = () => {
return (
<Collapsible className="w-full max-w-md">
<CollapsibleTrigger className="flex w-full items-center justify-between rounded-lg border border-border px-3 py-2 text-left font-medium text-sm transition-colors hover:bg-muted">
What is Ark UI?
<CollapsibleIndicator
className="text-muted-foreground transition-transform data-[state=open]:rotate-180"
aria-hidden
>
<ChevronDownIcon className="size-4" />
</CollapsibleIndicator>
</CollapsibleTrigger>
<CollapsibleContent className="rounded-md px-3 py-2">
<p className="text-muted-foreground text-sm leading-relaxed">
Ark UI provides accessible, headless primitives you can style with
your own design system.
</p>
</CollapsibleContent>
</Collapsible>
);
};
export default CollapsibleDemo;
Partial Collapse
Ark UI gives you headless primitives, while your app controls layout, typography, spacing, and motion.
With partial collapse, users can preview a snippet without opening the whole section.
This works well for long descriptions, changelogs, or expandable detail blocks in dense interfaces.
import { ChevronDownIcon } from "lucide-react";
import {
Collapsible,
CollapsibleContent,
CollapsibleIndicator,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
const CollapsiblePartialCollapse = () => {
return (
<Collapsible collapsedHeight="84px" className="w-full max-w-md">
<CollapsibleTrigger className="flex w-full items-center justify-between rounded-lg border border-border px-3 py-2 text-left font-medium text-sm transition-colors hover:bg-muted">
Read more
<CollapsibleIndicator
className="text-muted-foreground transition-transform data-[state=open]:rotate-180"
aria-hidden
>
<ChevronDownIcon className="size-4" />
</CollapsibleIndicator>
</CollapsibleTrigger>
<CollapsibleContent
className="
rounded-md px-3 py-2
data-[state=open]:animate-none data-[state=closed]:animate-none
transition-[height] duration-200 ease-out
data-[state=closed]:data-has-collapsed-size:shadow-[inset_0_-12px_12px_-12px_rgba(0,0,0,0.35)]
"
>
<div className="space-y-2 text-muted-foreground text-sm leading-relaxed">
<p>
Ark UI gives you headless primitives, while your app controls
layout, typography, spacing, and motion.
</p>
<p>
With partial collapse, users can preview a snippet without opening
the whole section.
</p>
<p>
This works well for long descriptions, changelogs, or expandable
detail blocks in dense interfaces.
</p>
</div>
</CollapsibleContent>
</Collapsible>
);
};
export default CollapsiblePartialCollapse;
Use collapsedHeight or collapsedWidth to build a "show more/less" pattern.
When set, the content collapses to that dimension instead of 0px.
Ark exposes CSS variables --collapsed-height and --collapsed-width so you can tune open/close animations without layout jerk.
Nested Collapsibles
Expand child sections for focused details.
Install @ark-ui/react and compose with your own styles.
Use Tailwind or CSS modules to style each nested layer differently.
import { ChevronDownIcon } from "lucide-react";
import {
Collapsible,
CollapsibleContent,
CollapsibleIndicator,
CollapsibleTrigger,
} from "@/components/ui/collapsible";
const triggerClassName =
"flex w-full items-center justify-between rounded-lg border border-border px-3 py-2 text-left font-medium text-sm transition-colors hover:bg-muted";
const indicatorClassName =
"text-muted-foreground transition-transform data-[state=open]:rotate-180";
const CollapsibleNested = () => {
return (
<Collapsible className="w-full max-w-md">
<CollapsibleTrigger className={triggerClassName}>
Getting started
<CollapsibleIndicator className={indicatorClassName} aria-hidden>
<ChevronDownIcon className="size-4" />
</CollapsibleIndicator>
</CollapsibleTrigger>
<CollapsibleContent className="space-y-2 rounded-md px-3 py-2">
<p className="text-muted-foreground text-sm">
Expand child sections for focused details.
</p>
<Collapsible className="w-full">
<CollapsibleTrigger className={triggerClassName}>
Installation
<CollapsibleIndicator className={indicatorClassName} aria-hidden>
<ChevronDownIcon className="size-4" />
</CollapsibleIndicator>
</CollapsibleTrigger>
<CollapsibleContent className="rounded-md px-3 py-2">
<p className="text-muted-foreground text-sm">
Install{" "}
<code className="rounded bg-muted px-1 py-0.5 text-xs">
@ark-ui/react
</code>{" "}
and compose with your own styles.
</p>
</CollapsibleContent>
</Collapsible>
<Collapsible className="w-full">
<CollapsibleTrigger className={triggerClassName}>
Styling
<CollapsibleIndicator className={indicatorClassName} aria-hidden>
<ChevronDownIcon className="size-4" />
</CollapsibleIndicator>
</CollapsibleTrigger>
<CollapsibleContent className="rounded-md px-3 py-2">
<p className="text-muted-foreground text-sm">
Use Tailwind or CSS modules to style each nested layer
differently.
</p>
</CollapsibleContent>
</Collapsible>
</CollapsibleContent>
</Collapsible>
);
};
export default CollapsibleNested;
Ark UI also supports additional collapsible patterns such as initial-open, lazy-mount, disabled, and root-provider composition.
API reference
This component mirrors the upstream Ark UI primitive.
See the ARK UI documentation for the full API.
Accessibility
See the Ark UI documentation for clarification.