Kumo is Cloudflare's new design system.
import { createSignal } from "solid-js";
import { Collapsible, Text } from "@photon-ai/kumo-solid";
/**
* Hero demo using DefaultTrigger and DefaultPanel for classic Kumo styling.
*/
export function CollapsibleHeroDemo() {
const [isOpen, setIsOpen] = createSignal(true);
return (
<div class="w-full">
<Collapsible.Root open={isOpen()} onOpenChange={setIsOpen}>
<Collapsible.DefaultTrigger>What is Kumo?</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel>
<Text>Kumo is Cloudflare's new design system.</Text>
</Collapsible.DefaultPanel>
</Collapsible.Root>
</div>
);
}Installation
Barrel
import { Collapsible } from "@photon-ai/kumo-solid";Granular
import { Collapsible } from "@photon-ai/kumo-solid/components/collapsible";Usage
Collapsible uses a compound component pattern for full composition control.
With Default Styling
Use DefaultTrigger and DefaultPanel for the classic Kumo style:
import { createSignal } from "solid-js";
import { Collapsible } from "@photon-ai/kumo-solid";
export default function Example() {
const [open, setOpen] = createSignal(false);
return (
<Collapsible.Root open={open()} onOpenChange={setOpen}>
<Collapsible.DefaultTrigger>Show details</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel>
Content with border-left accent styling.
</Collapsible.DefaultPanel>
</Collapsible.Root>
);
}Custom Trigger
Use the render prop on Trigger for full control over the trigger element:
<Collapsible.Root open={open()} onOpenChange={setOpen}>
<Collapsible.Trigger
render={(triggerProps) => <Button {...triggerProps} variant="ghost" />}
>
{open() ? "Hide" : "Show"} details
</Collapsible.Trigger>
<Collapsible.Panel class="mt-2 p-4 bg-kumo-tint rounded-lg">
Custom styled panel content.
</Collapsible.Panel>
</Collapsible.Root>Examples
Basic
import { createSignal } from "solid-js";
import { Collapsible, Text } from "@photon-ai/kumo-solid";
/**
* Basic usage with default styling components.
*/
export function CollapsibleBasicDemo() {
const [isOpen, setIsOpen] = createSignal(false);
return (
<div class="w-full">
<Collapsible.Root open={isOpen()} onOpenChange={setIsOpen}>
<Collapsible.DefaultTrigger>What is Kumo?</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel>
<Text>Kumo is Cloudflare's new design system.</Text>
</Collapsible.DefaultPanel>
</Collapsible.Root>
</div>
);
}Multiple Items
import { createSignal } from "solid-js";
import { Collapsible, Text } from "@photon-ai/kumo-solid";
/**
* Multiple independent collapsibles.
*/
export function CollapsibleMultipleDemo() {
const [open1, setOpen1] = createSignal(false);
const [open2, setOpen2] = createSignal(false);
const [open3, setOpen3] = createSignal(false);
return (
<div class="w-full space-y-2">
<Collapsible.Root open={open1()} onOpenChange={setOpen1}>
<Collapsible.DefaultTrigger>What is Kumo?</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel>
<Text>Kumo is Cloudflare's new design system.</Text>
</Collapsible.DefaultPanel>
</Collapsible.Root>
<Collapsible.Root open={open2()} onOpenChange={setOpen2}>
<Collapsible.DefaultTrigger>
How do I use it?
</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel>
<Text>Install the components and import them into your project.</Text>
</Collapsible.DefaultPanel>
</Collapsible.Root>
<Collapsible.Root open={open3()} onOpenChange={setOpen3}>
<Collapsible.DefaultTrigger>
Is it open source?
</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel>
<Text>Check the repository for license information.</Text>
</Collapsible.DefaultPanel>
</Collapsible.Root>
</div>
);
}Custom Trigger
Use Collapsible.Trigger with the render prop for full control:
import { createSignal } from "solid-js";
import { Button, Collapsible, Text } from "@photon-ai/kumo-solid";
/**
* Custom trigger using the render prop for full control.
*/
export function CollapsibleCustomTriggerDemo() {
const [isOpen, setIsOpen] = createSignal(false);
return (
<div class="w-full">
<Collapsible.Root open={isOpen()} onOpenChange={setIsOpen}>
<Collapsible.Trigger
render={(renderProps) => (
<Button {...renderProps} variant="secondary" size="sm" />
)}
>
{isOpen() ? "Hide details" : "Show details"}
</Collapsible.Trigger>
<Collapsible.Panel className="mt-3 rounded-lg bg-kumo-tint p-4">
<Text>
This panel uses custom styling instead of the default border-left
accent.
</Text>
</Collapsible.Panel>
</Collapsible.Root>
</div>
);
}Keep Mounted
Use keepMounted on DefaultPanel (or Panel) to preserve internal state — such as form inputs — when the panel is collapsed:
Type something below, then collapse and re-open — your input is preserved because the panel stays mounted.
import { createSignal } from "solid-js";
import { Collapsible, Input, Text } from "@photon-ai/kumo-solid";
/**
* Keep the panel mounted in the DOM when closed to preserve internal state like form inputs.
*/
export function CollapsibleKeepMountedDemo() {
const [isOpen, setIsOpen] = createSignal(true);
return (
<div class="w-full space-y-4">
<Collapsible.Root open={isOpen()} onOpenChange={setIsOpen}>
<Collapsible.DefaultTrigger>Edit details</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel keepMounted>
<Text>
Type something below, then collapse and re-open — your input is
preserved because the panel stays mounted.
</Text>
<Input label="Name" placeholder="Type here…" />
</Collapsible.DefaultPanel>
</Collapsible.Root>
</div>
);
}Accordion Pattern
Control which item is open to create an accordion where only one item can be expanded at a time:
Kumo is Cloudflare's new design system built on Base UI and Tailwind CSS v4.
import { createSignal } from "solid-js";
import { Collapsible, Text } from "@photon-ai/kumo-solid";
/**
* Accordion pattern where only one item can be open at a time.
*/
export function CollapsibleAccordionDemo() {
const [activeIndex, setActiveIndex] = createSignal<number | null>(0);
const items = [
{
title: "What is Kumo?",
content:
"Kumo is Cloudflare's new design system built on Base UI and Tailwind CSS v4.",
},
{
title: "How do I install it?",
content:
"Run `npm install @photon-ai/kumo-solid solid-js` and import the components you need.",
},
{
title: "Is it accessible?",
content:
"Yes! Kumo is built on Base UI which provides excellent accessibility out of the box.",
},
];
return (
<div class="w-full space-y-2">
{items.map((item, i) => (
<Collapsible.Root
open={activeIndex() === i}
onOpenChange={(open) => setActiveIndex(open ? i : null)}
>
<Collapsible.DefaultTrigger>{item.title}</Collapsible.DefaultTrigger>
<Collapsible.DefaultPanel>
<Text>{item.content}</Text>
</Collapsible.DefaultPanel>
</Collapsible.Root>
))}
</div>
);
}Sub-components
| Component | Description |
|---|---|
Collapsible.Root | Manages open state. Pass open and onOpenChange for controlled mode. |
Collapsible.Trigger | Button that toggles visibility. Use render prop for custom elements. |
Collapsible.Panel | Container for collapsible content. |
Collapsible.DefaultTrigger | Pre-styled trigger with text label and animated caret icon. |
Collapsible.DefaultPanel | Pre-styled panel with border-left accent and standard spacing. |
API Reference
Collapsible.Root
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Whether the panel is visible (controlled). |
defaultOpen | boolean | false | Initial open state (uncontrolled). |
onOpenChange | (open: boolean) => void | — | Callback when open state changes. |
disabled | boolean | false | Whether the collapsible is disabled. |
Collapsible.Trigger
| Prop | Type | Default | Description |
|---|---|---|---|
render | RenderProp | — | Solid render callback for a custom trigger element. |
className | string | — | Additional CSS classes. |
Collapsible.Panel
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Additional CSS classes. |
keepMounted | boolean | false | Whether to keep the panel in the DOM when closed. |
Collapsible.DefaultTrigger
| Prop | Type | Default | Description |
|---|---|---|---|
children | JSX.Element | — | Label text displayed in the trigger. |
className | string | — | Additional CSS classes. |
Collapsible.DefaultPanel
Accepts all Collapsible.Panel props in addition to the ones listed below.
| Prop | Type | Default | Description |
|---|---|---|---|
children | JSX.Element | — | Panel content. |
className | string | — | Additional CSS classes. |
keepMounted | boolean | false | Whether to keep the panel in the DOM when closed. |