Accordion

Vertically stacked sections that expand and collapse.

import { … } from '@inlaylab/ivorie/accordion'

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_ACCORDION_IMPORTS } from '@inlaylab/ivorie/accordion';

@Component({
  selector: 'demo-accordion',
  imports: [IV_ACCORDION_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-accordion type="single" class="w-96">
      <iv-accordion-item value="profile">
        <iv-accordion-trigger>Profile</iv-accordion-trigger>
        <iv-accordion-content>Manage your name, email and avatar.</iv-accordion-content>
      </iv-accordion-item>
      <iv-accordion-item value="security">
        <iv-accordion-trigger>Security</iv-accordion-trigger>
        <iv-accordion-content>Configure 2FA, sessions and trusted devices.</iv-accordion-content>
      </iv-accordion-item>
    </iv-accordion>
  `,
})
export default class AccordionDemo {}

Installation

CLInpm
npx ivorie add accordion

Sections with a heading trigger and a collapsible body. Open one at a time or many. Ports the shadcn/ui Accordion.

Usage

import { IV_ACCORDION_IMPORTS } from '@inlaylab/ivorie/accordion';
<iv-accordion type="single">
  <iv-accordion-item value="profile">
    <iv-accordion-trigger>Profile</iv-accordion-trigger>
    <iv-accordion-content>Manage your name, email and avatar.</iv-accordion-content>
  </iv-accordion-item>
</iv-accordion>

Examples

Multiple

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_ACCORDION_IMPORTS } from '@inlaylab/ivorie/accordion';

@Component({
  selector: 'demo-accordion-multiple',
  imports: [IV_ACCORDION_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-accordion type="multiple" class="w-96">
      <iv-accordion-item value="profile">
        <iv-accordion-trigger>Profile</iv-accordion-trigger>
        <iv-accordion-content>Manage your name, email and avatar.</iv-accordion-content>
      </iv-accordion-item>
      <iv-accordion-item value="security">
        <iv-accordion-trigger>Security</iv-accordion-trigger>
        <iv-accordion-content>Configure 2FA, sessions and trusted devices.</iv-accordion-content>
      </iv-accordion-item>
    </iv-accordion>
  `,
})
export default class AccordionMultipleDemo {}

Controlled

Manage your name, email and avatar.

Open: profile

import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { IV_ACCORDION_IMPORTS } from '@inlaylab/ivorie/accordion';

@Component({
  selector: 'demo-accordion-controlled',
  imports: [IV_ACCORDION_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-accordion type="single" [(value)]="open" class="w-96">
      <iv-accordion-item value="profile">
        <iv-accordion-trigger>Profile</iv-accordion-trigger>
        <iv-accordion-content>Manage your name, email and avatar.</iv-accordion-content>
      </iv-accordion-item>
      <iv-accordion-item value="security">
        <iv-accordion-trigger>Security</iv-accordion-trigger>
        <iv-accordion-content>Configure 2FA, sessions and trusted devices.</iv-accordion-content>
      </iv-accordion-item>
    </iv-accordion>
    <p class="mt-3 text-sm text-muted-foreground">Open: {{ open() ?? 'none' }}</p>
  `,
})
export default class AccordionControlledDemo {
  protected readonly open = signal<string | string[] | null>('profile');
}

Disabled

import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IV_ACCORDION_IMPORTS } from '@inlaylab/ivorie/accordion';

@Component({
  selector: 'demo-accordion-disabled',
  imports: [IV_ACCORDION_IMPORTS],
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `
    <iv-accordion type="single" class="w-96">
      <iv-accordion-item value="profile">
        <iv-accordion-trigger>Profile</iv-accordion-trigger>
        <iv-accordion-content>Manage your name, email and avatar.</iv-accordion-content>
      </iv-accordion-item>
      <iv-accordion-item value="security" [disabled]="true">
        <iv-accordion-trigger>Security</iv-accordion-trigger>
        <iv-accordion-content>Configure 2FA, sessions and trusted devices.</iv-accordion-content>
      </iv-accordion-item>
    </iv-accordion>
  `,
})
export default class AccordionDisabledDemo {}

API

Every part also accepts class.

iv-accordion

Name Type Default Description
type 'single' | 'multiple' 'single' One open item at a time, or any number.
collapsible boolean true In single mode, allow closing the open item.
value string | string[] | null - Open item values. A string for single, a string[] for multiple. Bind with [(value)].

Outputs:

Name Payload Description
valueChange string | string[] | null The open set changed. single emits one value or null. multiple emits an array.

iv-accordion-item

Name Type Default Description
value string required Unique key within the accordion.
disabled boolean false Disables the trigger.

iv-accordion-trigger

Renders a <button> inside an <h3> with a chevron icon. No own inputs.

iv-accordion-content

Body shown when the item is open. No own inputs.

Accessibility

  • The trigger is a <button> in an <h3> with aria-expanded and aria-controls.
  • The content has role="region" and aria-labelledby pointing at its trigger.
  • Enter and Space toggle the item.
  • Down and Up move between triggers and wrap. Home and End go to the first and last trigger. Disabled triggers are skipped.
  • Only keys pressed on a trigger count. Arrows inside a field in a panel, or in a nested accordion, stay there.
  • A disabled item disables its <button>.

Notes

  • Trigger and content must sit inside iv-accordion-item. The item must sit inside iv-accordion.
  • Closed content is hidden. data-state="open" | "closed" is set on the item, trigger and content.