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 采用组合式组件模式,可完全自行编排结构。

使用默认样式

用 DefaultTrigger 和 DefaultPanel 获得经典的 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>
  );
}

自定义触发器

用带 render 属性的 Collapsible.Trigger 完全掌控触发器:

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="user@example.com" 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管理打开状态。传入 open 和 onOpenChange 即为受控模式。
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 中。