# Accordion

A column of sections where opening one is a decision about the others — one at a time, or as many as the reader likes.

```slint
import { Accordion, AccordionSection } from "@glint/components/accordion.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 440px;

                acc := Accordion {
                    AccordionSection {
                        index: 0;
                        title: "Is it accessible?";
                        state <=> acc.state;
                        open: true;

                        Text {
                            text: "Yes. It adheres to the WAI-ARIA APG accordion design pattern.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                            wrap: word-wrap;
                        }
                    }

                    AccordionSection {
                        index: 1;
                        title: "Is it styled?";
                        state <=> acc.state;

                        Text {
                            text: "Yes. It comes with default styles matching your theme palette and design tokens.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                            wrap: word-wrap;
                        }
                    }

                    AccordionSection {
                        index: 2;
                        title: "Is it animated?";
                        state <=> acc.state;

                        Text {
                            text: "Yes. Opening and closing transitions animate smoothly with easing tokens.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                            wrap: word-wrap;
                        }
                    }
                }
            }
        }
    }
}
```

## Usage

```slint
import { Accordion, AccordionSection } from "@glint/components/accordion.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component AppWindow inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        acc := Accordion {
            AccordionSection {
                index: 0;
                title: "Shipping & Delivery";
                state <=> acc.state;
                open: true;

                Text {
                    text: "Orders process within 1-2 business days with standard shipping.";
                    color: Tokens.color-foreground;
                    wrap: word-wrap;
                }
            }

            AccordionSection {
                index: 1;
                title: "Returns & Exchanges";
                state <=> acc.state;

                Text {
                    text: "30-day return policy for unused items in original packaging.";
                    color: Tokens.color-foreground;
                    wrap: word-wrap;
                }
            }
        }
    }
}
```

Each section binds to the parent accordion’s shared state with `state <=> acc.state`. `open` provides a two-way binding on each section to control or inspect whether it is expanded.

## Examples

### Multi-open

Set `multiple: true` on the `Accordion` to allow several sections to remain open simultaneously.

```slint
import { Accordion, AccordionSection } from "@glint/components/accordion.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 320px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 440px;

                acc := Accordion {
                    multiple: true;

                    AccordionSection {
                        index: 0;
                        title: "Account settings";
                        state <=> acc.state;
                        open: true;

                        Text {
                            text: "Manage email preferences and connected social accounts.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                        }
                    }

                    AccordionSection {
                        index: 1;
                        title: "Security keys";
                        state <=> acc.state;
                        open: true;

                        Text {
                            text: "Configure two-factor authentication and hardware security keys.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                        }
                    }
                }
            }
        }
    }
}
```

### Borderless

Set `border: false` to remove the hairline dividers between accordion sections.

```slint
import { Accordion, AccordionSection } from "@glint/components/accordion.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 440px;

                acc := Accordion {
                    border: false;

                    AccordionSection {
                        index: 0;
                        title: "Overview";
                        state <=> acc.state;
                        open: true;

                        Text {
                            text: "Glint provides robust, themeable Slint components.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                        }
                    }

                    AccordionSection {
                        index: 1;
                        title: "Architecture";
                        state <=> acc.state;

                        Text {
                            text: "State broadcasts allow seamless keyboard navigation across sections.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                        }
                    }
                }
            }
        }
    }
}
```

### Disabled section

Set `disabled: true` on an `AccordionSection` to prevent opening while retaining its position and tab stop in accessibility navigation.

```slint
import { Accordion, AccordionSection } from "@glint/components/accordion.slint";
import { Tokens } from "@glint/theme/tokens.slint";

export component Demo inherits Window {
    width: 560px;
    height: 300px;
    background: Tokens.color-background;

    VerticalLayout {
        alignment: center;
        padding: 24px;

        HorizontalLayout {
            alignment: center;

            VerticalLayout {
                width: 440px;

                acc := Accordion {
                    AccordionSection {
                        index: 0;
                        title: "Active plan";
                        state <=> acc.state;
                        open: true;

                        Text {
                            text: "Your workspace is currently on the Pro plan.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                        }
                    }

                    AccordionSection {
                        index: 1;
                        title: "Enterprise options (Unavailable)";
                        state <=> acc.state;
                        disabled: true;

                        Text {
                            text: "Contact sales to enable custom SSO and dedicated support.";
                            color: Tokens.color-muted-foreground;
                            font-size: Tokens.typography-body-sm-size;
                        }
                    }
                }
            }
        }
    }
}
```

## API Reference

### Properties

| Property   | Type                    | Default | Description                                                                                                                                                                                           |
| ---------- | ----------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `state`    | `in-out AccordionState` | `}`     | Everything the sections share. See `AccordionState`.                                                                                                                                                  |
| `border`   | `in bool`               | `true`  | Draws a hairline above every section but the first. False leaves the list unruled; there is never one after the last section either way, because the rule belongs to the section it opens (ADR-0012). |
| `multiple` | `in bool`               | `false` | Lets several sections stay open at once. Off, opening one closes whichever was open.                                                                                                                  |

### Callbacks

| Callback             | Description                                                                                                                                                                                                       |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `changed(int, bool)` | Fired when a section is toggled: which one, and whether it is now open. The sections write the shared state and this is derived from it, so it arrives on the way to the next frame rather than inside the click. |

### Functions

| Function      | Description                                                                                                                                    |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `close-all()` | Closes every section — the one thing a single whole-accordion property was good for, spelled as the broadcast everything else here already is. |

### AccordionSection

One section: a header that toggles it, and `@children` as the panel. It is written as a child of an `Accordion`, which binds its position and the shared state in — the properties below are that conversation, not knobs a call site reaches for.

### Properties

| Property   | Type                    | Default    | Description                                                                                                                                                                                                                                                                                                                                                                                                               |
| ---------- | ----------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `index`    | `in int`                | no default | Position in the accordion, counting from 0.                                                                                                                                                                                                                                                                                                                                                                               |
| `title`    | `in string`             | no default | Header caption. Also the header's accessible name.                                                                                                                                                                                                                                                                                                                                                                        |
| `open`     | `in-out bool`           | `false`    | Two-way; whether this section is open. The section holds its own, rather than the accordion holding an index or a list of flags: Slint arrays do not grow — a write past the end is dropped in silence — so a list in the shared struct would have to be sized by hand at every call site, and one item short is a section that never opens and never says why. Here it is also the handle a consumer binds from outside. |
| `disabled` | `in bool`               | `false`    | When true, the section stays listed and keeps its tab stop, announces itself unavailable, and refuses to open.                                                                                                                                                                                                                                                                                                            |
| `state`    | `in-out AccordionState` | no default | The accordion's shared state — `state <=> acc.state;`.                                                                                                                                                                                                                                                                                                                                                                    |

## Accessibility

- **Accordion header button role.** Each section header is marked with `accessible-role: button`, reporting `accessible-expandable: true` and `accessible-expanded` reflecting the section’s `open` state.
- **Keyboard navigation.** Follows the WAI-ARIA APG Accordion pattern. `Up` and `Down` arrow keys move focus between headers with wrap-around. `Home` moves focus to the first header, and `End` jumps to the last header.
- **Header activation.** Pressing `Space` or `Enter` on a focused header toggles that section.
- **Disabled section behaviour.** A disabled section preserves its tab stop and announcement in the accessibility tree with `accessible-enabled: false`, while ignoring activation.
- **Focus ring.** Displays a prominent focus ring when navigating headers via keyboard.
