# Accordion

- Entry point: `@koobiq/components/accordion`
- NgModule: `KbqAccordionModule`
- Page: https://koobiq.io/en/components/accordion/overview

## Overview

An accordion is an interactive UI element that allows users to expand and collapse individual blocks of information on demand, organizing them into compact sections.

**Example: Accordion** (`accordion-overview`)

```ts accordion-overview-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';

@Component({
    selector: 'accordion-overview-example',
    imports: [KbqAccordionModule],
    templateUrl: 'accordion-overview-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionOverviewExample {}
```

```html accordion-overview-example.html
<div class="layout-column layout-fill layout-align-center-center docs-example-vertical-margin">
    <kbq-accordion style="width: 300px">
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>
</div>
```

### States

#### Trigger Placement

By default, the trigger is positioned on the left side. If needed, it can be placed in the left part of the section header after the title or on the right side of the section header.

**Example: Accordion states** (`accordion-states`)

```ts accordion-states-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule, KbqAccordionVariant } from '@koobiq/components/accordion';
import { KbqButtonToggleModule } from '@koobiq/components/button-toggle';

@Component({
    selector: 'accordion-states-example',
    imports: [KbqAccordionModule, KbqButtonToggleModule],
    templateUrl: 'accordion-states-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionStatesExample {
    readonly accordionVariant: Record<'fill' | 'hug' | 'hugSpaceBetween', KbqAccordionVariant> = {
        fill: 'fill',
        hug: 'hug',
        hugSpaceBetween: 'hugSpaceBetween'
    };
}
```

```html accordion-states-example.html
<div class="layout-column layout-fill layout-align-center-center docs-example-vertical-margin">
    <kbq-accordion style="width: 300px" [variant]="group1.value">
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>

    <div>
        <div
            style="color: var(--kbq-foreground-contrast-secondary)"
            class="kbq-text-normal layout-margin-top-l layout-margin-bottom-s layout-row layout-align-center"
        >
            Trigger Position
        </div>
        <kbq-button-toggle-group #group1="kbqButtonToggleGroup" class="layout-margin-s" [value]="accordionVariant.fill">
            <kbq-button-toggle [value]="accordionVariant.fill">Before Title</kbq-button-toggle>
            <kbq-button-toggle [value]="accordionVariant.hug">After Title</kbq-button-toggle>
            <kbq-button-toggle [value]="accordionVariant.hugSpaceBetween">Separately</kbq-button-toggle>
        </kbq-button-toggle-group>
    </div>
</div>
```

#### Section Expansion

By default, the accordion allows only one section to be expanded at a time. However, it is possible to enable the expansion of all sections simultaneously.

**Example: Accordion sections** (`accordion-sections`)

```ts accordion-sections-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';
import { KbqButtonToggleModule } from '@koobiq/components/button-toggle';

@Component({
    selector: 'accordion-sections-example',
    imports: [KbqAccordionModule, KbqButtonToggleModule],
    templateUrl: 'accordion-sections-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionSectionsExample {}
```

```html accordion-sections-example.html
<div class="layout-column layout-fill layout-align-center-center docs-example-vertical-margin">
    <kbq-accordion style="width: 300px" [type]="toggle.value">
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>

    <div>
        <div
            style="color: var(--kbq-foreground-contrast-secondary)"
            class="kbq-text-normal layout-margin-top-l layout-margin-bottom-s layout-row layout-align-center"
        >
            Openning
        </div>
        <kbq-button-toggle-group #toggle="kbqButtonToggleGroup" class="layout-margin-s" [value]="'single'">
            <kbq-button-toggle [value]="'single'">Single</kbq-button-toggle>
            <kbq-button-toggle [value]="'multiple'">Multiple</kbq-button-toggle>
        </kbq-button-toggle-group>
    </div>
</div>
```

#### Inactive Section

If necessary, a section can be disabled, preventing it from being expanded.

**Example: Accordion inactive section** (`accordion-inactive-section`)

```ts accordion-inactive-section-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';

@Component({
    selector: 'accordion-inactive-section-example',
    imports: [KbqAccordionModule],
    templateUrl: 'accordion-inactive-section-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionInactiveSectionExample {}
```

```html accordion-inactive-section-example.html
<div class="layout-column layout-fill layout-align-center-center docs-example-vertical-margin">
    <kbq-accordion style="width: 300px">
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item [disabled]="true">
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>
</div>
```

#### Content Placement

The content inside a section can be placed within the section header or inside the content area.

##### Inside the Section Header

The section header can additionally include an icon, description, left and right badges, as well as extra actions (using an Icon Button).

**Example: Accordion header** (`accordion-header`)

```ts accordion-header-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';
import { KbqBadgeModule } from '@koobiq/components/badge';
import { KbqCheckboxModule } from '@koobiq/components/checkbox';
import { KbqIcon, KbqIconButton } from '@koobiq/components/icon';

@Component({
    selector: 'accordion-header-example',
    imports: [KbqAccordionModule, KbqBadgeModule, KbqCheckboxModule, KbqIcon, KbqIconButton],
    templateUrl: 'accordion-header-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionHeaderExample {
    icon: boolean = false;
    caption: boolean = false;
    leftBadge: boolean = false;
    rightBadge: boolean = false;
    actions: boolean = false;
}
```

```html accordion-header-example.html
<div class="layout-row layout-fill layout-align-space-around docs-example-vertical-margin">
    <kbq-accordion style="width: 360px">
        <kbq-accordion-item>
            <kbq-accordion-header>
                <button kbq-accordion-trigger type="button">
                    @if (icon) {
                        <i kbq-icon="kbq-database_16" class="layout-margin-right-xxs"></i>
                    }
                    <span class="layout-margin-right-s">Text</span>
                    @if (caption) {
                        <span
                            style="color: var(--kbq-foreground-contrast-secondary)"
                            class="kbq-accordion-trigger__caption"
                        >
                            Caption
                        </span>
                    }
                    @if (leftBadge) {
                        <kbq-badge class="kbq-accordion-trigger__badge" [compact]="true">Badge</kbq-badge>
                    }
                    @if (rightBadge) {
                        <kbq-badge style="margin-left: auto" class="kbq-accordion-trigger__badge" [compact]="true">
                            Badge
                        </kbq-badge>
                    }
                </button>

                <!-- Actions go next to the trigger, not inside it: the trigger is a role="button",
                     and nesting focusable elements in it breaks accessibility. Each label names its
                     own section, since every section here shares the same "Text" title. -->
                @if (actions) {
                    <div class="kbq-accordion-header__actions">
                        <button kbq-icon-button="kbq-bolt_16" type="button" aria-label="Bolt, section 1"></button>
                        <button kbq-icon-button="kbq-bug_16" type="button" aria-label="Bug, section 1"></button>
                        <button
                            kbq-icon-button="kbq-ellipsis-vertical_16"
                            type="button"
                            aria-label="More, section 1"
                        ></button>
                    </div>
                }
            </kbq-accordion-header>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <kbq-accordion-header>
                <button kbq-accordion-trigger type="button">
                    @if (icon) {
                        <i kbq-icon="kbq-database_16" class="layout-margin-right-xxs"></i>
                    }
                    <span class="layout-margin-right-s">Text</span>
                    @if (caption) {
                        <span
                            style="color: var(--kbq-foreground-contrast-secondary)"
                            class="kbq-accordion-trigger__caption"
                        >
                            Caption
                        </span>
                    }
                    @if (leftBadge) {
                        <kbq-badge class="kbq-accordion-trigger__badge" [compact]="true">Badge</kbq-badge>
                    }
                    @if (rightBadge) {
                        <kbq-badge style="margin-left: auto" class="kbq-accordion-trigger__badge" [compact]="true">
                            Badge
                        </kbq-badge>
                    }
                </button>

                @if (actions) {
                    <div class="kbq-accordion-header__actions">
                        <button kbq-icon-button="kbq-bolt_16" type="button" aria-label="Bolt, section 2"></button>
                        <button kbq-icon-button="kbq-bug_16" type="button" aria-label="Bug, section 2"></button>
                        <button
                            kbq-icon-button="kbq-ellipsis-vertical_16"
                            type="button"
                            aria-label="More, section 2"
                        ></button>
                    </div>
                }
            </kbq-accordion-header>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <kbq-accordion-header>
                <button kbq-accordion-trigger type="button">
                    @if (icon) {
                        <i kbq-icon="kbq-database_16" class="layout-margin-right-xxs"></i>
                    }
                    <span class="layout-margin-right-s">Text</span>
                    @if (caption) {
                        <span
                            style="color: var(--kbq-foreground-contrast-secondary)"
                            class="kbq-accordion-trigger__caption"
                        >
                            Caption
                        </span>
                    }
                    @if (leftBadge) {
                        <kbq-badge class="kbq-accordion-trigger__badge" [compact]="true">Badge</kbq-badge>
                    }
                    @if (rightBadge) {
                        <kbq-badge style="margin-left: auto" class="kbq-accordion-trigger__badge" [compact]="true">
                            Badge
                        </kbq-badge>
                    }
                </button>

                @if (actions) {
                    <div class="kbq-accordion-header__actions">
                        <button kbq-icon-button="kbq-bolt_16" type="button" aria-label="Bolt, section 3"></button>
                        <button kbq-icon-button="kbq-bug_16" type="button" aria-label="Bug, section 3"></button>
                        <button
                            kbq-icon-button="kbq-ellipsis-vertical_16"
                            type="button"
                            aria-label="More, section 3"
                        ></button>
                    </div>
                }
            </kbq-accordion-header>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <kbq-accordion-header>
                <button kbq-accordion-trigger type="button">
                    @if (icon) {
                        <i kbq-icon="kbq-database_16" class="layout-margin-right-xxs"></i>
                    }
                    <span class="layout-margin-right-s">Text</span>
                    @if (caption) {
                        <span
                            style="color: var(--kbq-foreground-contrast-secondary)"
                            class="kbq-accordion-trigger__caption"
                        >
                            Caption
                        </span>
                    }
                    @if (leftBadge) {
                        <kbq-badge class="kbq-accordion-trigger__badge" [compact]="true">Badge</kbq-badge>
                    }
                    @if (rightBadge) {
                        <kbq-badge style="margin-left: auto" class="kbq-accordion-trigger__badge" [compact]="true">
                            Badge
                        </kbq-badge>
                    }
                </button>

                @if (actions) {
                    <div class="kbq-accordion-header__actions">
                        <button kbq-icon-button="kbq-bolt_16" type="button" aria-label="Bolt, section 4"></button>
                        <button kbq-icon-button="kbq-bug_16" type="button" aria-label="Bug, section 4"></button>
                        <button
                            kbq-icon-button="kbq-ellipsis-vertical_16"
                            type="button"
                            aria-label="More, section 4"
                        ></button>
                    </div>
                }
            </kbq-accordion-header>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <kbq-accordion-header>
                <button kbq-accordion-trigger type="button">
                    @if (icon) {
                        <i kbq-icon="kbq-database_16" class="layout-margin-right-xxs"></i>
                    }
                    <span class="layout-margin-right-s">Text</span>
                    @if (caption) {
                        <span
                            style="color: var(--kbq-foreground-contrast-secondary)"
                            class="kbq-accordion-trigger__caption"
                        >
                            Caption
                        </span>
                    }
                    @if (leftBadge) {
                        <kbq-badge class="kbq-accordion-trigger__badge" [compact]="true">Badge</kbq-badge>
                    }
                    @if (rightBadge) {
                        <kbq-badge style="margin-left: auto" class="kbq-accordion-trigger__badge" [compact]="true">
                            Badge
                        </kbq-badge>
                    }
                </button>

                @if (actions) {
                    <div class="kbq-accordion-header__actions">
                        <button kbq-icon-button="kbq-bolt_16" type="button" aria-label="Bolt, section 5"></button>
                        <button kbq-icon-button="kbq-bug_16" type="button" aria-label="Bug, section 5"></button>
                        <button
                            kbq-icon-button="kbq-ellipsis-vertical_16"
                            type="button"
                            aria-label="More, section 5"
                        ></button>
                    </div>
                }
            </kbq-accordion-header>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>

    <div class="layout-column layout-margin-top-4xl">
        <kbq-checkbox class="layout-margin-bottom-s" (change)="icon = !icon">Icon</kbq-checkbox>
        <kbq-checkbox class="layout-margin-bottom-s" (change)="caption = !caption">Caption</kbq-checkbox>
        <kbq-checkbox class="layout-margin-bottom-s" (change)="leftBadge = !leftBadge">Left Badge</kbq-checkbox>
        <kbq-checkbox class="layout-margin-bottom-s" (change)="rightBadge = !rightBadge">Right Badge</kbq-checkbox>
        <kbq-checkbox class="layout-margin-bottom-s" (change)="actions = !actions">Actions</kbq-checkbox>
    </div>
</div>

<div
    style="color: var(--kbq-foreground-contrast-secondary)"
    class="kbq-text-normal layout-margin-top-l layout-margin-bottom-s layout-row layout-align-center"
>
    Скрытие и раскрытие секций производится по нажатию на всю секцию
</div>
```

##### Inside the Content Area

This area can contain any type of content.

**Example: Accordion content** (`accordion-content`)

```ts accordion-content-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';
import { KbqCheckboxModule } from '@koobiq/components/checkbox';

@Component({
    selector: 'accordion-content-example',
    imports: [KbqAccordionModule, KbqCheckboxModule],
    templateUrl: 'accordion-content-example.html',
    styleUrls: ['accordion-content-example.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionContentExample {
    image: boolean = false;
}
```

```html accordion-content-example.html
<div class="layout-row layout-fill layout-align-space-around docs-example-vertical-margin">
    <kbq-accordion style="width: 360px">
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content class="layout-column">
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                @if (image) {
                    <div class="layout-margin-top-s example-accordion-image"></div>
                }
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content class="layout-column">
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                @if (image) {
                    <div class="layout-margin-top-s example-accordion-image"></div>
                }
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content class="layout-column">
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                @if (image) {
                    <div class="layout-margin-top-s example-accordion-image"></div>
                }
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content class="layout-column">
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                @if (image) {
                    <div class="layout-margin-top-s example-accordion-image"></div>
                }
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Text</button>
            <kbq-accordion-content class="layout-column">
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                @if (image) {
                    <div class="layout-margin-top-s example-accordion-image"></div>
                }
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>

    <div class="layout-column layout-margin-top-4xl">
        <kbq-checkbox class="layout-margin-bottom-s" [checked]="true" [disabled]="true">Paragraph</kbq-checkbox>
        <kbq-checkbox class="layout-margin-bottom-s" (change)="image = !image">Image</kbq-checkbox>
    </div>
</div>
```

```css accordion-content-example.css
.example-accordion-image {
    width: 336px;
    height: 110px;

    border-radius: var(--kbq-size-s);

    background: var(--kbq-background-bg-secondary);
}
```

##### Interactive Elements

Buttons, dropdown menus and form controls can be placed in the section header next to the trigger, as well as inside the content area. Place them **next to** the trigger, never inside it: the trigger is a `role="button"`, and nesting focusable elements in it breaks accessibility. Enter and Space toggle the section only while the trigger itself is focused.

**Example: Accordion interactive elements** (`accordion-interactive-elements`)

```ts accordion-interactive-elements-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { KbqAccordionModule } from '@koobiq/components/accordion';
import { KbqButtonModule } from '@koobiq/components/button';
import { KbqCheckboxModule } from '@koobiq/components/checkbox';
import { KbqDropdownModule } from '@koobiq/components/dropdown';
import { KbqFormFieldModule } from '@koobiq/components/form-field';
import { KbqIconModule } from '@koobiq/components/icon';
import { KbqInputModule } from '@koobiq/components/input';

type ExampleSection = {
    id: string;
    title: string;
    enabled: boolean;
    name: string;
};

@Component({
    selector: 'accordion-interactive-elements-example',
    imports: [
        KbqAccordionModule,
        KbqButtonModule,
        KbqCheckboxModule,
        KbqDropdownModule,
        KbqFormFieldModule,
        KbqIconModule,
        KbqInputModule,
        FormsModule
    ],
    templateUrl: 'accordion-interactive-elements-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionInteractiveElementsExample {
    protected readonly sections: ExampleSection[] = [
        { id: 'section-1', title: 'Profile', enabled: true, name: '' },
        { id: 'section-2', title: 'Specifications', enabled: false, name: '' },
        { id: 'section-3', title: 'Servers', enabled: false, name: '' }
    ];
}
```

```html accordion-interactive-elements-example.html
<div class="layout-column layout-fill layout-align-center-center docs-example-vertical-margin">
    <kbq-accordion style="width: 360px">
        @for (section of sections; track section.id) {
            <kbq-accordion-item [value]="section.id">
                <kbq-accordion-header>
                    <button kbq-accordion-trigger type="button">{{ section.title }}</button>

                    <!-- Actions go next to the trigger, not inside it: the trigger is a role="button",
                         and nesting focusable elements in it breaks accessibility. Each label names its
                         own section so the actions stay distinguishable in a screen reader element list. -->
                    <div class="kbq-accordion-header__actions">
                        <button
                            aria-label="Run {{ section.title }}"
                            kbq-icon-button="kbq-bolt_16"
                            type="button"
                        ></button>
                        <button
                            aria-label="More actions for {{ section.title }}"
                            kbq-icon-button="kbq-ellipsis-vertical_16"
                            type="button"
                            [kbqDropdownTriggerFor]="dropdown"
                        ></button>
                    </div>
                </kbq-accordion-header>

                <kbq-accordion-content>
                    <div class="layout-column layout-gap-s">
                        <kbq-checkbox [(ngModel)]="section.enabled">Enabled</kbq-checkbox>

                        <kbq-form-field>
                            <input kbqInput placeholder="Name" [(ngModel)]="section.name" />
                        </kbq-form-field>

                        <button kbq-button type="button">Apply</button>
                    </div>
                </kbq-accordion-content>
            </kbq-accordion-item>
        }
    </kbq-accordion>

    <kbq-dropdown #dropdown="kbqDropdown">
        <button kbq-dropdown-item type="button">Rename</button>
        <button kbq-dropdown-item type="button">Duplicate</button>
        <button kbq-dropdown-item type="button">Delete</button>
    </kbq-dropdown>
</div>

<div
    style="color: var(--kbq-foreground-contrast-secondary)"
    class="kbq-text-normal layout-margin-top-l layout-margin-bottom-s layout-row layout-align-center"
>
    Enter and Space toggle the section only while the trigger itself is focused
</div>
```

### State Saving

The accordion remembers which sections were expanded and restores the state after a page reload. On by default — use `[useStateSaving]="false"` to turn it off on a specific component.

**Example: Accordion state saving** (`accordion-state-saving`)

```ts accordion-state-saving-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';
import { KbqButtonModule } from '@koobiq/components/button';

@Component({
    selector: 'accordion-state-saving-example',
    imports: [KbqAccordionModule, KbqButtonModule],
    templateUrl: 'accordion-state-saving-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionStateSavingExample {}
```

```html accordion-state-saving-example.html
<div class="layout-column layout-fill layout-align-center-center docs-example-vertical-margin">
    <kbq-accordion #accordion stateSavingKey="accordion-state-saving-example" style="width: 300px" [type]="'multiple'">
        <kbq-accordion-item [value]="'delivery'">
            <button kbq-accordion-trigger type="button">Доставка</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item [value]="'payment'">
            <button kbq-accordion-trigger type="button">Оплата</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item [value]="'refund'">
            <button kbq-accordion-trigger type="button">Возврат</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>

    <button kbq-button class="layout-margin-top-l" type="button" (click)="accordion.clearSavedState()">
        Reset saved state
    </button>
</div>
```

Give the sections a `[value]`. Without one they are persisted by position, and inserting a section shifts everything after it into the wrong state.

A bound `[value]` wins over the persisted state, which wins over `defaultValue`; a section's own `[expanded]` applies only when none of them is set. `clearSavedState()` removes what is stored.

Keys, storage and expiry work the same for every component that persists — see [Saving component state](https://koobiq.io/en/components/core.md#saving-component-state).

### Usage Examples

#### Inside a Section

**Example: Accordion in section** (`accordion-in-section`)

```ts accordion-in-section-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';

@Component({
    selector: 'accordion-in-section-example',
    imports: [KbqAccordionModule],
    templateUrl: 'accordion-in-section-example.html',
    styleUrls: ['accordion-in-section-example.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionInSectionExample {}
```

```html accordion-in-section-example.html
<div class="layout-column layout-fill layout-align-center-center layout-margin-top-xxl layout-margin-bottom-xxl">
    <kbq-accordion class="example-accordion-in-section layout-padding-s">
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Профиль</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Характеристики</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Сервера</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Данные</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
        <kbq-accordion-item>
            <button kbq-accordion-trigger type="button">Заметка</button>
            <kbq-accordion-content>
                Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
            </kbq-accordion-content>
        </kbq-accordion-item>
    </kbq-accordion>
</div>
```

```css accordion-in-section-example.css
.example-accordion-in-section {
    width: 316px;

    border: 1px solid var(--kbq-line-contrast-fade);

    border-radius: 16px;
}
```

#### Inside a Panel

**Example: Accordion in panel** (`accordion-in-panel`)

```ts accordion-in-panel-example.ts
import { ChangeDetectionStrategy, Component, TemplateRef, inject, viewChild } from '@angular/core';
import { KbqAccordionModule } from '@koobiq/components/accordion';
import { KbqButtonModule } from '@koobiq/components/button';
import {
    KbqSidepanelModule,
    KbqSidepanelPosition,
    KbqSidepanelService,
    KbqSidepanelSize
} from '@koobiq/components/sidepanel';

@Component({
    selector: 'accordion-in-panel-example',
    imports: [KbqAccordionModule, KbqSidepanelModule, KbqButtonModule],
    templateUrl: 'accordion-in-panel-example.html',
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class AccordionInPanelExample {
    private sidepanelService = inject(KbqSidepanelService);

    position: KbqSidepanelPosition = KbqSidepanelPosition.Right;
    size: KbqSidepanelSize = KbqSidepanelSize.Medium;

    readonly template = viewChild.required<TemplateRef<any>>('template');

    openPanel() {
        this.sidepanelService.open(this.template(), {
            position: this.position,
            size: this.size
        });
    }
}
```

```html accordion-in-panel-example.html
<button kbq-button (click)="openPanel()">Open panel with accordion</button>

<ng-template #template>
    <kbq-sidepanel-header [closeable]="true">Панель</kbq-sidepanel-header>

    <kbq-sidepanel-body class="layout-padding-left-l">
        <kbq-accordion>
            <kbq-accordion-item>
                <button kbq-accordion-trigger type="button">Профиль</button>
                <kbq-accordion-content>
                    Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                </kbq-accordion-content>
            </kbq-accordion-item>
            <kbq-accordion-item>
                <button kbq-accordion-trigger type="button">Характеристики</button>
                <kbq-accordion-content>
                    Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                </kbq-accordion-content>
            </kbq-accordion-item>
            <kbq-accordion-item>
                <button kbq-accordion-trigger type="button">Сервера</button>
                <kbq-accordion-content>
                    Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                </kbq-accordion-content>
            </kbq-accordion-item>
            <kbq-accordion-item>
                <button kbq-accordion-trigger type="button">Данные</button>
                <kbq-accordion-content>
                    Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                </kbq-accordion-content>
            </kbq-accordion-item>
            <kbq-accordion-item>
                <button kbq-accordion-trigger type="button">Заметка</button>
                <kbq-accordion-content>
                    Данный текст используется для иллюстрации внутреннего содержимого секции аккордеона
                </kbq-accordion-content>
            </kbq-accordion-item>
        </kbq-accordion>
    </kbq-sidepanel-body>
</ng-template>
```

### Recommendations

- Each accordion section should have a clear and informative title that accurately reflects its content. This helps users quickly find the necessary information.
- Accordion sections should be organized in a logical sequence, such as alphabetical order, hierarchical structure, or thematic grouping.

## API

### Components

#### KbqAccordion (component)

```ts
@Component({ selector: 'kbq-accordion, [kbq-accordion]' })
class KbqAccordion {
    readonly variant = input<KbqAccordionVariant>('fill');
    readonly disabled = input<boolean>();
    readonly orientation = input<KbqAccordionOrientation>('vertical');
    readonly level = input<number>(2);
    readonly defaultValue = input<string[] | string>([]);
    readonly type = input<KbqAccordionType>('single');
    readonly collapsible = input<boolean>(true);
    readonly value = model<string[] | string | undefined>();
    get id(): string;
    get isMultiple(): boolean;
    get hasSavedState(): boolean;
    openAll(): void;
    closeAll(): void;
    clearSavedState(): void;
}
```

- `[variant]`: `KbqAccordionVariant` — The visual variant of the accordion. Defaults to `fill`.
- `[disabled]`: `boolean` — Whether the whole accordion is disabled.
- `[orientation]`: `KbqAccordionOrientation` — The layout orientation of the accordion. Defaults to `vertical`.
- `[level]`: `number` — The `aria-level` applied to the item headings. Defaults to `2`.
  Set it to match the surrounding document outline (e.g. `3` when nested under an `<h2>` section).
- `[defaultValue]`: `string[] | string` — The value of the item(s) to expand when initially rendered.
  Use when you do not need to control the state of the items.
- `[type]`: `KbqAccordionType` — Determines whether one or multiple items can be expanded at the same time.
- `[collapsible]`: `boolean` — Whether an expanded item can be collapsed by the user. Defaults to `true`.
- `[(value)]`: `string[] | string | undefined` — The controlled value of the item(s) to expand, reshaped by mode. Supports `[(value)]`.
  Falls back to `defaultValue` while `value` is unbound.

  Always an array in `multiple` mode and always a string in `single` mode — an empty string
  when nothing is expanded, matching what `valueChange` emits.
- `[useStateSaving]`: `boolean` — Whether the component remembers its state across reloads and restores it on the next render.
  Defaults to `true`, or to whatever `KBQ_STATE_SAVING_ENABLED` is provided as.
- `[stateSavingKey]`: `string` — The key the state is persisted under. While it is empty the key is derived from where the
  component sits in the document, which moves when the surrounding markup is restructured — an `id`
  on the component or any ancestor pins it just as well as this input does.
- `id`: `string` — The unique id of this accordion.
- `isMultiple`: `boolean` — Whether multiple items can be expanded at the same time.
- `hasSavedState`: `boolean` — Whether state is currently persisted for this accordion — restored on init, or written since.
  Always `false` while `useStateSaving` is unset, and `false` again after `clearSavedState()`.
- `openAll()`: `void` — Opens all enabled accordion items in an accordion where `type` is `multiple`.
- `closeAll()`: `void` — Closes all enabled accordion items.
- `clearSavedState()`: `void` — Removes the state persisted for this accordion.

  Persistence itself stays on — the next change is written again. Unset `useStateSaving` to stop it.

#### KbqAccordionContent (component)

```ts
@Component({ selector: 'kbq-accordion-content, [kbq-accordion-content]' })
class KbqAccordionContent {}
```

#### KbqAccordionTrigger (component)

```ts
@Component({ selector: 'kbq-accordion-trigger, [kbq-accordion-trigger]' })
class KbqAccordionTrigger {
    get isFill(): boolean;
    get isHug(): boolean;
    get isHugSpaceBetween(): boolean;
    disableAnimation(): void;
    enableAnimation(): void;
}
```

### Directives

#### KbqAccordionContentDirective (directive)

```ts
@Directive({
    selector: '[kbqAccordionContent]',
    exportAs: 'kbqAccordionContent'
})
class KbqAccordionContentDirective {
    toggle(): void;
    disableAnimation(): void;
    enableAnimation(): void;
}
```

#### KbqAccordionHeader (directive)

```ts
@Directive({ selector: 'kbq-accordion-header, [kbq-accordion-header]' })
class KbqAccordionHeader {}
```

#### KbqAccordionItem (directive)

```ts
@Directive({ selector: 'kbq-accordion-item, [kbq-accordion-item]' })
class KbqAccordionItem {
    expanded = model<boolean | undefined>();
    readonly value = input<string>('');
    disabled = input<boolean | undefined>();
    readonly closed = output<void>();
    readonly opened = output<void>();
    readonly accordion: KbqAccordion;
    get id(): string;
    focus(): void;
    toggle(): void;
    close(): void;
    open(): void;
}
```

- `[(expanded)]`: `boolean | undefined` — Whether the AccordionItem is expanded. When the accordion initializes, its controlled `value`, the saved
  state and `defaultValue` take precedence over it.
- `[value]`: `string` — The item's effective value — its own `value`, or its position inside the accordion when none is
  provided.

  The position, rather than the id: the value is what the accordion persists, and the id carries a
  global instantiation counter that shifts as soon as anything else on the page is created ahead of
  this accordion. The prefix keeps a generated value from colliding with an author-written one.
- `[disabled]`: `boolean | undefined` — Whether the AccordionItem is disabled.
- `(closed)`: `void` — Event emitted every time the AccordionItem is closed.
- `(opened)`: `void` — Event emitted every time the AccordionItem is opened.
- `accordion`: `KbqAccordion` — The accordion this item belongs to — always the nearest one, because it is injected.
  The accordion reads it back to tell its own items apart from a nested accordion's.
- `id`: `string` — The unique AccordionItem id.
- `focus()`: `void` — Moves focus to the item's trigger.
- `toggle()`: `void` — Toggles the expanded state of the accordion item.
- `close()`: `void` — Sets the expanded state of the accordion item to false.
- `open()`: `void` — Sets the expanded state of the accordion item to true.

#### KbqAccordionTriggerDirective (directive)

```ts
@Directive({ selector: '[kbqAccordionTrigger]' })
class KbqAccordionTriggerDirective {
    onClick(): void;
    onKeydown(event: KeyboardEvent): void;
}
```

- `onClick()`: `void` — Fires when trigger clicked
- `onKeydown()`: `void` — Routes keyboard interaction to the accordion, but only while the trigger itself is focused.

  A `keydown` targets the focused element, so header actions placed next to the trigger and
  controls inside the expanded content keep their own keys — the accordion no longer toggles the
  section on Enter/Space nor moves focus to another header on the arrow keys. The `target` check
  additionally covers focusable content mistakenly nested inside the trigger.

### Types

#### KbqAccordionItemState (type)

```ts
type KbqAccordionItemState = 'open' | 'closed';
```

#### KbqAccordionOrientation (type)

The layout orientation of the accordion.

```ts
type KbqAccordionOrientation = 'horizontal' | 'vertical';
```

#### KbqAccordionState (type)

The persisted state of an accordion — the values of the items that were expanded.
Mirrors `KbqAccordion.value` normalized to an array.

```ts
type KbqAccordionState = string[];
```

#### KbqAccordionType (type)

Determines whether one or multiple items can be expanded at the same time.

```ts
type KbqAccordionType = 'single' | 'multiple';
```

#### KbqAccordionVariant (type)

Available visual variants of the accordion.

```ts
type KbqAccordionVariant = 'fill' | 'hug' | 'hugSpaceBetween';
```
