一个 React 手风琴,采用可折叠的 Liquid Glass 面板,支持键盘操作。
Accordion 在同一块玻璃表面上渲染一组折叠面板。每个条目都是真实的标题与按钮,展开时面板高度会带过渡动画。
每个 items 条目都会渲染真实的标题与按钮。默认的加号指示器会旋转成关闭图标,面板高度平滑过渡。
默认只保留一个展开的面板。添加 multiple 可以让多个面板同时展开:
支持 xs / sm / md / lg / xl,默认 md。触发器高度、内边距、文字与指示器会一起缩放。
value 与 onValueChange 让展开状态完全由外部控制。下面的示例可以通过一个按钮展开或收起全部面板:
在根上设置 disabled 会禁用所有触发器;在单个 item 上设置 disabled 只会禁用该面板。
默认情况下,关闭的面板会从 DOM 中移除。设置 keepMounted 可以保留面板,让表单状态在关闭后依然存在;设置 hiddenUntilFound 则使用 hidden="until-found" 保留面板,让浏览器页内查找可以展开匹配内容。
每个条目都在真实标题(默认是 <h3>)内渲染原生按钮。触发器始终暴露 aria-expanded;面板打开时还会暴露 aria-controls。面板由对应触发器命名。Enter 或 Space 切换当前面板。禁用的触发器仍保留在文档中,但会被 Tab 跳过。
标题文字应保持有意义;视觉样式不能替代真实的文档大纲。共享交互模式见可访问性指南。
Accordion
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value | Value[] | — | 受控的展开值。 |
defaultValue | Value[] | [] | 初始展开值。 |
onValueChange | (value: Value[], details) => void | — | 展开值变化时调用。 |
multiple | boolean | false | 是否允许多个面板同时展开。 |
disabled | boolean | false | 禁用所有触发器。 |
hiddenUntilFound | boolean | false | 使用 hidden="until-found" 保留关闭的面板,让浏览器页内查找可以展开匹配内容。 |
keepMounted | boolean | false | 关闭时仍保留面板 DOM。 |
loopFocus | boolean | — | 已废弃,不再影响键盘焦点。 |
orientation | "horizontal" | "vertical" | "vertical" | 已废弃,不再影响键盘焦点。 |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | 控制触发器高度、内边距、文字与指示器尺寸。 |
items | readonly AccordionItemProps[] | — | 渲染在 accordion 内部的面板。 |
render | ReactElement | ((props, state) => ReactElement) | — | 替换根元素。 |
ref | Ref<HTMLDivElement> | — | 转发到根元素的 ref。 |
className | string | — | 合并到根元素的 Tailwind 类名。 |
style | CSSProperties | — | 内联样式,合并到与 className 相同的元素。 |
ui | { root?: ClassValue; glass?: ClassValue; overlay?: ClassValue; content?: ClassValue; item?: ClassValue; header?: ClassValue; trigger?: ClassValue; title?: ClassValue; indicator?: ClassValue; indicatorIcon?: ClassValue; panel?: ClassValue; panelContent?: ClassValue } | — | 按 data-slot 组织的内部槽位类名。 |
AccordionItemProps
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
value | any | — | 必填,accordion value 使用的标识。 |
title | ReactNode | — | 必填,触发器内的可见标题。 |
content | ReactNode | — | 面板内容。 |
indicator | ReactNode | false | 内置加号图标 | 替换默认指示器;设为 false 时隐藏。 |
disabled | boolean | false | 禁用该 item。 |
onOpenChange | (open: boolean, details) => void | — | 该面板展开或收起时调用。 |
render | ReactElement | ((props, state) => ReactElement) | — | 替换 item 根元素。 |
ref | Ref<HTMLDivElement> | — | 转发到 item 根元素的 ref。 |
className | string | — | 合并到 item root 的 Tailwind 类名。 |
style | CSSProperties | — | 内联样式,合并到与 className 相同的元素。 |
ui | { item?: ClassValue; header?: ClassValue; trigger?: ClassValue; title?: ClassValue; indicator?: ClassValue; indicatorIcon?: ClassValue; panel?: ClassValue; panelContent?: ClassValue } | — | 按 data-slot 组织的该 item 内部槽位类名。 |
根 ui 会先合并到每个 item,再合并该 item 的 ui,最后合并 item 的 className。
| 属性 | 说明 |
|---|---|
data-disabled | accordion 或 item 被禁用时存在。 |
data-orientation | 表示方向(horizontal 或 vertical)。 |
data-index | 在 item 与 trigger 上表示 item 索引。 |
data-open | item 展开时存在。 |
data-panel-open | 触发器的面板展开时存在。 |
data-starting-style | 面板开始进入动画时存在。 |
data-ending-style | 面板正在退出动画时存在。 |
data-slot | 标记内部部件(root、glass、overlay、content、item、header、trigger、title、indicator、indicator-icon、panel、panel-content)。 |
组件使用共享玻璃材质。可以在父级调整 --ui-glass-* token,用 className 控制布局,并通过 ui 按 data-slot 调整内部槽位。组件级数值位于 src/theme/accordion.ts。Token 分层与预设见主题指南。