Collapsible
@cloudflare/kumo

Kumo is Cloudflare's new design system.

import { Collapsible, Text } from "@cloudflare/kumo";
import { useState } from "react";

/**
 * Hero demo using DefaultTrigger and DefaultPanel for classic Kumo styling.
 */
export function CollapsibleHeroDemo() {
  const [isOpen, setIsOpen] = useState(true);
  return (
    <div className="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>
  );
}

安装

批量导入

import { Collapsible } from "@cloudflare/kumo";

按需导入

import { Collapsible } from "@cloudflare/kumo/components/collapsible";

用法

Collapsible 采用复合组件模式,提供完整的组合控制能力。

默认样式

使用 DefaultTriggerDefaultPanel 获得经典的 Kumo 样式:

import { Collapsible } from "@cloudflare/kumo";

export default function Example() {
  const [open, setOpen] = useState(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>
  );
}

自定义触发器

Trigger 上使用 render 属性,即可完全掌控触发器元素:

<Collapsible.Root open={open} onOpenChange={setOpen}>
  <Collapsible.Trigger render={<Button variant="ghost" />}>
    {open ? "Hide" : "Show"} details
  </Collapsible.Trigger>
  <Collapsible.Panel className="mt-2 p-4 bg-kumo-tint rounded-lg">
    Custom styled panel content.
  </Collapsible.Panel>
</Collapsible.Root>

示例

基本

import { Collapsible, Text } from "@cloudflare/kumo";
import { useState } from "react";

/**
 * Basic usage with default styling components.
 */
export function CollapsibleBasicDemo() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <div className="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>
  );
}

多个可折叠项

import { Collapsible, Text } from "@cloudflare/kumo";
import { useState } from "react";

/**
 * Multiple independent collapsibles.
 */
export function CollapsibleMultipleDemo() {
  const [open1, setOpen1] = useState(false);
  const [open2, setOpen2] = useState(false);
  const [open3, setOpen3] = useState(false);

  return (
    <div className="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>
  );
}

自定义触发器

Collapsible.Triggerrender 属性结合使用即可完全掌控:

import { Button, Collapsible, Text } from "@cloudflare/kumo";
import { useState } from "react";

/**
 * Custom trigger using the render prop for full control.
 */
export function CollapsibleCustomTriggerDemo() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <div className="w-full">
      <Collapsible.Root open={isOpen} onOpenChange={setIsOpen}>
        <Collapsible.Trigger render={<Button 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>
  );
}

保持挂载

DefaultPanel(或 Panel)上使用 keepMounted,可在面板折叠时保留内部状态(如表单输入):

Type something below, then collapse and re-open — your input is preserved because the panel stays mounted.

import { Collapsible, Input, Text } from "@cloudflare/kumo";
import { useState } from "react";

/**
 * Keep the panel mounted in the DOM when closed to preserve internal state like form inputs.
 */
export function CollapsibleKeepMountedDemo() {
  const [isOpen, setIsOpen] = useState(true);
  return (
    <div className="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>
  );
}

表单内容

DefaultPanel 与表单控件搭配使用,以验证焦点环在动画面板内有足够的空间:

import { Button, Collapsible, Input } from "@cloudflare/kumo";
import { useState } from "react";

/**
 * Form controls inside DefaultPanel for testing focus ring clipping.
 */
export function CollapsibleFormDemo() {
  const [isOpen, setIsOpen] = useState(true);
  return (
    <div className="w-full">
      <Collapsible.Root open={isOpen} onOpenChange={setIsOpen}>
        <Collapsible.DefaultTrigger>
          Contact settings
        </Collapsible.DefaultTrigger>
        <Collapsible.DefaultPanel>
          <form
            className="flex max-w-sm flex-col gap-4"
            onSubmit={(event) => event.preventDefault()}
          >
            <Input label="Email" placeholder="[email protected]" type="email" />
            <Input label="Team name" placeholder="Design engineering" />
            <Button type="submit">Save settings</Button>
          </form>
        </Collapsible.DefaultPanel>
      </Collapsible.Root>
    </div>
  );
}

手风琴模式

通过控制展开的条目来实现手风琴效果,即每次只展开一个条目:

Kumo is Cloudflare's new design system built on Base UI and Tailwind CSS v4.

import { Collapsible, Text } from "@cloudflare/kumo";
import { useState } from "react";

/**
 * Accordion pattern where only one item can be open at a time.
 */
export function CollapsibleAccordionDemo() {
  const [activeIndex, setActiveIndex] = useState<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 @cloudflare/kumo` 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 className="w-full space-y-2">
      {items.map((item, i) => (
        <Collapsible.Root
          key={i}
          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>
  );
}

子组件

组件说明
Collapsible.Root管理展开状态。传入 openonOpenChange 可使用受控模式。
Collapsible.Trigger切换可见性的按钮。使用 render 属性可自定义元素。
Collapsible.Panel折叠内容的容器。
Collapsible.DefaultTrigger预置样式的触发器,含文本标签和动画插入标记图标。
Collapsible.DefaultPanel预置样式的面板,带左侧边框强调和标准间距。

API 参考

Collapsible.Root

属性类型默认值说明
openboolean面板是否可见(受控)。
defaultOpenbooleanfalse初始展开状态(非受控)。
onOpenChange(open: boolean) => void展开状态变化时的回调。
disabledbooleanfalse是否禁用该折叠组件。

Collapsible.Trigger

属性类型默认值说明
renderReactElement作为触发器渲染的自定义元素。
classNamestring额外的 CSS 类。

Collapsible.Panel

属性类型默认值说明
classNamestring额外的 CSS 类。
keepMountedbooleanfalse关闭时是否将面板保留在 DOM 中。

Collapsible.DefaultTrigger

属性类型默认值说明
childrenReactNode显示在触发器中的标签文本。
classNamestring额外的 CSS 类。

Collapsible.DefaultPanel

除下面列出的属性外,还接受 Collapsible.Panel 的所有属性。

属性类型默认值说明
childrenReactNode面板内容。
classNamestring额外的 CSS 类。
keepMountedbooleanfalse关闭时是否将面板保留在 DOM 中。