Collapsible
A component that allows users to expand or collapse content sections.
Docsimport { Collapsible, CollapsibleTrigger, CollapsibleContent } from "~/components/collapsible";
export default function CollapsibleBasicDemo() {
return (
<Collapsible>
<CollapsibleTrigger>Click to expand</CollapsibleTrigger>
<CollapsibleContent>
<div class="pt-4 text-sm">Hidden content goes here.</div>
</CollapsibleContent>
</Collapsible>
);
}Installation
CLI
Run the following command to add the component to your project:
npx @ark-preset/cli@latest add collapsibleManual
Create the recipe file at src/components/recipes/collapsible.ts:
import { tv, type VariantProps } from "tailwind-variants";
export const collapsibleVariants = tv({
slots: {
root: "w-full",
trigger:
"flex items-center justify-between gap-3 w-full p-2.5 text-sm font-medium border border-neutral-200 rounded-lg bg-transparent cursor-pointer hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring data-[disabled]:opacity-50 data-[disabled]:cursor-not-allowed",
content:
"overflow-hidden data-[state=open]:animate-accordion-expand data-[state=closed]:animate-accordion-collapse duration-500",
indicator: "size-4 shrink-0 transition-transform duration-200 data-[state=open]:rotate-90",
},
});
export type CollapsibleVariants = VariantProps<typeof collapsibleVariants>;Create the component directory and files.
src/components/collapsible/collapsible.base.tsx:
import { Collapsible as ArkCollapsible } from "@ark-ui/solid/collapsible";
import { splitProps, type Component } from "solid-js";
import { collapsibleVariants } from "../recipes/collapsible";
const styles = collapsibleVariants();
const Root: Component<ArkCollapsible.RootProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCollapsible.Root class={styles.root({ class: local.class })} {...others} />;
};
const RootProvider: Component<ArkCollapsible.RootProviderProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCollapsible.RootProvider class={styles.root({ class: local.class })} {...others} />;
};
const Trigger: Component<ArkCollapsible.TriggerProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCollapsible.Trigger class={styles.trigger({ class: local.class })} {...others} />;
};
const Content: Component<ArkCollapsible.ContentProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCollapsible.Content class={styles.content({ class: local.class })} {...others} />;
};
const Indicator: Component<ArkCollapsible.IndicatorProps> = (props) => {
const [local, others] = splitProps(props, ["class"]);
return <ArkCollapsible.Indicator class={styles.indicator({ class: local.class })} {...others} />;
};
export const Collapsible = { Root, RootProvider, Trigger, Content, Indicator };src/components/collapsible/index.tsx:
import { type Component } from "solid-js";
import { Collapsible as CollapsibleBase } from "./collapsible.base";
import { Collapsible as ArkCollapsible } from "@ark-ui/solid/collapsible";
const Collapsible = CollapsibleBase.Root;
const CollapsibleIndicator: Component<ArkCollapsible.IndicatorProps> = (props) => {
return (
<CollapsibleBase.Indicator {...props}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="m6 9 6 6 6-6" />
</svg>
</CollapsibleBase.Indicator>
);
};
const CollapsibleTrigger = CollapsibleBase.Trigger;
const CollapsibleContent = CollapsibleBase.Content;
export {
Collapsible,
CollapsibleTrigger,
CollapsibleIndicator,
CollapsibleContent,
CollapsibleBase,
};
export { collapsibleVariants, type CollapsibleVariants } from "../recipes/collapsible";Note: Make sure your project has the Tailwind CSS theme variables set up (
--background,--foreground,--ring,--border, etc.) or override the utility classes to match your design system.
Usage
Basic Usage
import { Collapsible, CollapsibleTrigger, CollapsibleContent } from "~/components/collapsible";
export default function CollapsibleBasicDemo() {
return (
<Collapsible>
<CollapsibleTrigger>Click to expand</CollapsibleTrigger>
<CollapsibleContent>
<div class="pt-4 text-sm">Hidden content goes here.</div>
</CollapsibleContent>
</Collapsible>
);
}With Indicator
The indicator rotates when the content is expanded. Use CollapsibleIndicator inside the trigger to show the chevron icon. The rotation is styled via the indicator slot in the recipe.
import {
Collapsible,
CollapsibleIndicator,
CollapsibleTrigger,
CollapsibleContent,
} from "~/components/collapsible";
export default function CollapsibleIndicatorDemo() {
return (
<Collapsible>
<CollapsibleTrigger>
Toggle Content
<CollapsibleIndicator />
</CollapsibleTrigger>
<CollapsibleContent>
<div class="pt-4 text-sm">The indicator automatically rotates when expanded.</div>
</CollapsibleContent>
</Collapsible>
);
}Advanced Usage
Root Provider
Use CollapsibleRootProvider when you need to access the collapsible state outside of the component tree. This pattern uses the useCollapsible hook from Ark UI to create a shared context that both the component and external elements can reference.
import { useCollapsible } from "@ark-ui/solid/collapsible";
import {
CollapsibleBase,
CollapsibleIndicator,
CollapsibleTrigger,
CollapsibleContent,
} from "~/components/collapsible";
export default function CollapsibleRootProviderDemo() {
const collapsible = useCollapsible({ defaultOpen: true });
return (
<div class="space-y-4">
<output class="block text-sm text-muted-foreground">
Open: {JSON.stringify(collapsible().open)}
</output>
<CollapsibleBase.RootProvider value={collapsible}>
<CollapsibleTrigger>
Click to expand
<CollapsibleIndicator />
</CollapsibleTrigger>
<CollapsibleContent>
<div class="pt-4 text-sm text-foreground">
The collapsible state is managed externally via <code>useCollapsible</code>. The{" "}
<code>output</code> element above reads <code>collapsible().open</code> outside the
collapsible tree.
</div>
</CollapsibleContent>
</CollapsibleBase.RootProvider>
</div>
);
}The key difference:
Collapsible(Root) — manages its own state internally. Use for simple, self-contained usage.CollapsibleRootProvider— accepts a pre-created context viauseCollapsible. Use when you need to read or control the collapsible state from outside the component tree.
API Reference
See the Ark UI Collapsible documentation.