折叠区域 · Collapsible
折叠区域用于内容容器场景。下面的官方示例展示原生用法与状态,属性名保持上游 API。
安装与前置条件
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0
需要 React 19+,按顺序导入基础 CSS 和主题,并设置 Theme Provider。参见开始使用。
示例与使用方式
- 折叠区域 · 综合展示 / 分组 1:首先体验这个示例,再查看代码理解组件的组合方式。
- 折叠区域 · 综合展示 2:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 折叠区域 · 受控交互 3:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 折叠区域 · 交互示例 4:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 折叠区域 · 分组 5:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 折叠区域 · 交互示例 6:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 折叠区域 · 交互示例 7:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 折叠区域 · 交互示例 8:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
- 折叠区域 · 交互示例 9:可交互查看这一用法的行为,复制代码时保留它实际使用的属性与导入。
API 与上游详细参考
优先使用 0.7.1 官方中文说明;上游尚未提供中文的条目保留英文。属性名、类型及默认值保持原生 API,不把示例状态名称当成组件属性。
Collapsible
Collapsible hides and reveals content behind a trigger button. Use it in settings panels, FAQ pages, or detail views to keep the page scannable while letting users drill into sections they care about. Wrap multiple collapsibles in CollapsibleGroup for accordion behavior.
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| trigger * | ReactNode | Content shown in the trigger area (always visible). | |
| children | ReactNode | Content that collapses and expands. | |
| defaultIsOpen | boolean | true | Default open state for standalone uncontrolled usage. Ignored when value binds the item to a surrounding CollapsibleGroup. |
| isOpen | boolean | Controlled open state for standalone usage. Ignored when value binds the item to a surrounding CollapsibleGroup. | |
| isDisabled | boolean | false | Disable the item so its trigger can't be toggled (dimmed, aria-disabled, and out of the tab order). Doesn't collapse an already-open item. |
| onOpenChange | (isOpen: boolean) => void | Callback invoked when standalone open state changes. A surrounding CollapsibleGroup owns grouped state and calls its onChange instead. | |
| chevronPosition | 'start' | 'end' | 'end' | Logical position of Collapsible's disclosure chevron. end (default) follows the label, pointing down when collapsed and up when expanded. start precedes the label, pointing inward toward content when collapsed (mirrored under RTL) and down when expanded. Inside a CollapsibleGroup this defaults to the group's chevronPosition. |
| value | string | Identifier used for group coordination. When set inside a CollapsibleGroup, the group owns open state and its onChange is the notification callback. | |
| ref | React.Ref<HTMLDivElement> | Ref forwarded to the root collapsible element. | |
| xstyle | StyleXStyles | StyleX styles for layout customization. Must be a stylex.create() value. | |
| className | string | CSS class name for the root element. Prefer xstyle for styling. | |
| style | CSSProperties | Inline styles. Prefer xstyle for StyleX-optimized styling. | |
| data-testid | string | Test selector for automated testing frameworks. |
使用建议
- 确保每个触发器都有有意义的无障碍名称。可见文本通常可提供名称;若自定义视觉内容无法提供名称,请加入 VisuallyHidden 文本。
- Use hasDividers on CollapsibleGroup for FAQ-style lists: built-in row hairlines with themed border tokens, no hand-rolled borders.
- Wrap each Collapsible in an Card for visual separation in accordion layouts, or use CollapsibleGroup's hasDividers for flat lists; don't combine both.
- Use CollapsibleGroup with type="single" for settings or FAQ pages where only one section should be open at a time.
- Use type="multiple" when users need to compare content across sections, like feature lists or pricing tiers.
- Start sections open (defaultIsOpen) when the content is likely needed on first view; don't make users click to see essential info.
- 避免:Hide critical or required content behind a collapsible; users may not discover it.
- 避免:Nest collapsibles more than two levels deep; it makes content hard to find and navigate.
- 避免:Use a collapsible for a single short paragraph; just show the text directly instead.
主题 API
{
"targets": [
{
"className": "astryx-collapsible",
"visualProps": [
"density"
],
"states": [
"divided"
]
},
{
"className": "astryx-collapsible-trigger",
"visualProps": [
"density",
"chevronPosition"
],
"states": [
"open",
"disabled"
]
},
{
"className": "astryx-collapsible-content",
"visualProps": [
"density"
],
"states": [
"open"
]
},
{
"className": "astryx-collapsible-group",
"visualProps": [
"density"
]
}
]
}
CollapsibleGroup
无障碍
- Trigger label: The trigger text must have at least 4.5:1 contrast with the surface behind it. For Pointer down, measure against the pressed overlay the trigger row paints while it is pressed. — 4.5:1
组件结构
- Container: The root that contains one trigger and its controlled content and, in a divided group, paints the item divider.
- Trigger: The always-visible button that toggles the content. Shows a label and a chevron indicator.
- Chevron: Animated disclosure arrow. It follows the label by default; chevronPosition="start" moves it ahead of the label, points inward when collapsed (mirrored under RTL), and turns down when expanded.
- Content: The area that hides or reveals when the trigger is clicked.
- Group container: The CollapsibleGroup wrapper rendered when dividers are enabled. It contains the coordinated items and carries their density.
Collapsible Group
协调多个 Collapsible 实例,使同一时间只有一个(single 模式)或任意数量(multiple 模式)可以展开。除非启用 dividers,否则不渲染包裹 DOM 元素。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | 'single' | 'multiple' | 'single' | 是否允许同时展开一个或多个项目。 |
| defaultValue | string | string[] | 非受控模式下默认展开的项目。single 模式使用字符串,multiple 模式使用数组。 | |
| value | string | string[] | 受控展开的项目。 | |
| onChange | (value: string | string[]) => void | 展开项目集合变更时调用的回调。 | |
| hasDividers | boolean | false | 是否在组项目之间绘制细线分隔线。启用后组会渲染一个包裹 div,且项目默认使用 'balanced' 密度。适合搭配裸 Collapsible 子项使用;用 Card 包裹的项目自带视觉分隔。 |
| density | 'compact' | 'balanced' | 'spacious' | 控制组内项目触发器和内容块内边距的行密度。显示分隔线时默认为 'balanced';否则项目保持默认的无内边距外观。 | |
| chevronPosition | 'start' | 'end' | 'end' | 组内直接 Collapsible 项目的逻辑箭头位置。end 是默认的尾随指示器;start 是前置展开箭头,折叠时指向内容(RTL 下镜像),展开时向下。单个 Collapsible 仍可覆盖此设置。 |
| children * | ReactNode | 需要协调的 Collapsible 实例。 | |
| ref | React.Ref<HTMLElement> | Ref forwarded to the group wrapper when hasDividers renders one. | |
| xstyle | StyleXStyles | StyleX styles for the group wrapper when hasDividers renders one. Must be a stylex.create() value. | |
| className | string | CSS class name for the group wrapper when hasDividers renders one. Prefer xstyle for styling. | |
| style | CSSProperties | Inline styles for the group wrapper when hasDividers renders one. Prefer xstyle for StyleX-optimized styling. | |
| data-testid | string | Test selector forwarded to the group wrapper when hasDividers renders one. |
useCollapsible
Reusable hook that encapsulates the collapsible state machine. Supports three modes: group-controlled (inside CollapsibleGroup), controlled (isOpen + onOpenChange), and uncontrolled (self-managed with defaultIsOpen). Used internally by Card and Section.
Parameters
| Parameter | Type | Description |
|---|---|---|
| isCollapsible | boolean | CollapsibleConfig | Enable collapsible behavior. true = self-managed (starts open). Pass config object for controlled mode or custom defaults. |
| value | string | Unique identifier within an CollapsibleGroup. When present and inside a group, state is managed by the group. |
Returns
[
{
"name": "isEnabled",
"type": "boolean",
"description": "Whether collapsible behavior is active."
},
{
"name": "isOpen",
"type": "boolean",
"description": "Whether the content is currently expanded."
},
{
"name": "toggle",
"type": "() => void",
"description": "Toggle open/closed state. Dispatches to group, controlled callback, or internal state."
}
]
使用建议
- Use the hook directly when building custom collapsible components that need Astryx collapsible behavior without Collapsible wrapper.
- For accordion behavior, wrap items in CollapsibleGroup and pass unique value props.
- 避免:Pass local isOpen, defaultIsOpen, or onOpenChange expecting them to run for a value-bound group item; the group owns that state and notification path.
- 避免:Implement your own open/close state when useCollapsible already provides it; the hook handles group coordination automatically.