# Collapsible

- Page: https://jiguang132.com/resources/astryx/docs/collapsible
- Resource: Astryx (https://jiguang132.com/resources/astryx.md)
- All guides: https://jiguang132.com/resources/astryx/docs.md

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. For custom collapsible components, use the `useCollapsible` hook directly (`astryx hook useCollapsible`).

## Installation

```bash
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0
```

Requires React 19+, base CSS and a Theme provider. See [Setup](/resources/astryx/docs/getting-started).

## 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. For custom collapsible components, use the `useCollapsible` hook directly (`astryx hook useCollapsible`).

| Prop | Type | Default | Description |
|---|---|---|---|
| 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. |

### Usage guidance

- Give every trigger a meaningful accessible name. Visible text usually supplies it; custom trigger content should include VisuallyHidden text when its visuals do not.
- 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.
- Avoid: Hide critical or required content behind a collapsible; users may not discover it.
- Avoid: Nest collapsibles more than two levels deep; it makes content hard to find and navigate.
- Avoid: Use a collapsible for a single short paragraph; just show the text directly instead.

### Theming API

```json
{
  "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



### Accessibility

- **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

### Anatomy

- **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

Coordinates multiple Collapsible instances so only one (single mode) or any number (multiple mode) can be open at a time. Renders no wrapper DOM element unless dividers are enabled.

| Prop | Type | Default | Description |
|---|---|---|---|
| type | 'single' \| 'multiple' | 'single' | Whether one or many items can be open simultaneously. |
| defaultValue | string \| string[] |  | Default open item(s) for uncontrolled usage. Use a string for single mode and an array for multiple mode. |
| value | string \| string[] |  | Controlled open item(s). |
| onChange | (value: string \| string[]) => void |  | Callback invoked when the set of open items changes. |
| hasDividers | boolean | false | Whether to draw hairline dividers between the group's items. When set, the group renders a wrapper div and items default to 'balanced' density. Pair with bare Collapsible children; Card-wrapped items provide their own separation. |
| density | 'compact' \| 'balanced' \| 'spacious' |  | Row density controlling trigger and content block padding on the group's items. Defaults to 'balanced' when dividers are shown; otherwise items keep their default unpadded look. |
| chevronPosition | 'start' \| 'end' | 'end' | Logical position shared by the group's direct Collapsible items. `end` is the default trailing indicator; `start` is a leading disclosure arrow that points inward when collapsed (mirrored under RTL) and down when expanded. An individual Collapsible can still override it. |
| children * | ReactNode |  | Collapsible instances to coordinate. |
| 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

```json
[
  {
    "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."
  }
]
```

### Usage guidance

- 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.
- Avoid: Pass local isOpen, defaultIsOpen, or onOpenChange expecting them to run for a value-bound group item; the group owns that state and notification path.
- Avoid: Implement your own open/close state when useCollapsible already provides it; the hook handles group coordination automatically.


## Examples

- Collapsible Group: CollapsibleGroup coordinates its Collapsible children: with type="single", opening one closes the others. No state or handlers in the example — the group owns which value is open and each child only declares its own. One Collapsible per Card, so each trigger keeps its default large type as the heading of its own surface.
- Collapsible: An accordion group with three collapsible sections in single mode: opening one closes the others.
- Collapsible — Controlled: Manage the open section from parent state, so something other than a click can move it: a URL parameter, a form jumping to the step that failed validation, or the Previous/Next controls shown here. onChange hands back the whole open value.
- Collapsible — FAQ: FAQ built with hasDividers: row hairlines and density padding with no custom CSS. Questions set their own type — body at semibold, not the trigger's default 17px large — so a list of questions reads as rows rather than a stack of headings, and question and answer separate on weight and color instead of size.
- CollapsibleGroup — Density: density sets the block padding on every row in the group, so a list of sections can be tuned to the surface it sits on without touching the rows. compact for dense surfaces like sidebars and inspectors, balanced (the default) for page content, spacious for a short list that is the main thing on the page. It follows Table's scale and pairs with hasDividers, which turns it on at balanced.
- useCollapsible — Custom Disclosure: Custom disclosure UI built directly with useCollapsible for headless open/close state.
- Collapsible — Multiple Mode: Several sections open at once, for comparing across them — feature lists, pricing tiers. One Collapsible per Card, so each trigger keeps its own large type: it is the heading of its surface, not a row in a list.
- Collapsible — Single Mode: Only one section open at a time, so a single body of content competes for attention. Use defaultValue to pre-expand whichever section a first-time reader needs. Each Collapsible owns a Section, so its trigger is that section heading.
- Collapsible — With Dividers: A flat list on the page background with hand-placed Dividers, for detail panels and sidebars where cards would add too much weight. Rows, so the triggers step down to body-semibold and a supporting metadata line sits under each answer.

---

Index of all JGuang resources: https://jiguang132.com/llms.txt
