DEV Community

Rens Jaspers
Rens Jaspers

Posted on

How To Easily Expand or Collapse All Accordion Items in IonAccordionGroup at Once Without Adding Complexity

The Ionic Accordion Group and the ion-accordion are awesome. Accordions provide collapsible sections in your content to reduce vertical space while organizing and grouping information.

However, I feel there's an important feature that's missing: the ability to easily expand or collapse all accordion items at once.

While it's technically possible to expand or collapse all items at once, the current method is quite cumbersome. You have to use <ion-accordion-group [value]="valuesOfTheAccordionsThatShouldBeExpanded"> and pass an array of all the values of the accordions (or an empty array if you want to collapse all). This approach is problematic for several reasons:

  1. Typically, you don't want to assign a value to each accordion manually. Ionic already handles this automatically, but as a developer, you can't easily see these values.

  2. Your component suddenly has an extra responsibility: managing the state of each accordion group. This adds unnecessary complexity to your app.

Generally, I appreciate that the Ionic team keeps things lean and leaves extra functionalities to the developer. However, in this case, I would have liked to see an accordionGroup.toggleAll / expandAll / collapseAll method.

Fortunately, with Angular directives, it's relatively simple to add this functionality cleanly.

Here's an example:

import { ContentChildren, Directive, QueryList } from "@angular/core";
import { IonAccordion, IonAccordionGroup } from "@ionic/angular/standalone";

@Directive({
  selector: "[appAccordionGroupToggle]",
  exportAs: "appAccordionGroupToggle",
  standalone: true,
})
export class AccordionGroupToggleDirective {
  @ContentChildren(IonAccordion) accordions!: QueryList<IonAccordion>;

  get isCompletelyExpanded() {
    const groupValue = this.host.value;
    return (
      Array.isArray(groupValue) && groupValue?.length === this.accordions.length
    );
  }

  constructor(private host: IonAccordionGroup) {}

  toggle() {
    if (this.isCompletelyExpanded) {
      this.collapse();
    } else {
      this.expand();
    }
  }

  expand() {
    this.host.value = this.accordions.map((accordion) => accordion.value);
  }

  collapse() {
    this.host.value = [];
  }
}
Enter fullscreen mode Exit fullscreen mode

The directive works by using @ContentChildren to get a reference to all ion-accordion items within the accordion group. This allows the directive to access the state (and thus the values) of all the accordions collectively. The constructor injects the host IonAccordionGroup, providing access to the group’s properties and methods.

In the expand method, the directive sets the value of the host accordion group to an array containing the values of all the individual accordions, effectively expanding all of them. In the collapse method, it sets the value to an empty array, collapsing all the accordions.

The toggle method first checks if all accordions are already open by checking the value of isCompletelyExpanded. If it equals true, it collapses them; if not, it expands them.

You can use the directive as follows (don't forget to import the directive in your component):

<ion-content>
  <ion-button (click)="toggler.toggle()">Toggle all</ion-button>
  <ion-button (click)="toggler.expand()">Expand all</ion-button>
  <ion-button (click)="toggler.collapse()">Collapse all</ion-button>
  <ion-accordion-group
    appAccordionGroupToggle
    #toggler="appAccordionGroupToggle"
  >
    <ion-accordion>
      <ion-item slot="header">
        <ion-label>First Accordion</ion-label>
      </ion-item>
      <div slot="content">😎</div>
    </ion-accordion>
    <ion-accordion>
      <ion-item slot="header">
        <ion-label>Second Accordion</ion-label>
      </ion-item>
      <div slot="content">🀩</div>
    </ion-accordion>
    <ion-accordion>
      <ion-item slot="header">
        <ion-label>Third Accordion</ion-label>
      </ion-item>
      <div slot="content">πŸ’ͺ</div>
    </ion-accordion>
  </ion-accordion-group>
</ion-content>
Enter fullscreen mode Exit fullscreen mode

In the above example, we use #toggler to create a reference to the instance of the Group toggle. This is possible because we set exportAs: 'appAccordionGroupToggle' in our directive. Now, we can call any of the public methods (toggle, expand, and collapse) directly from our template.

That's it! Now you can use this directive to easily toggle all accordions at once anywhere you like. While I hope the Ionic team will add expand, collapse, and toggle methods to ion-accordion-group in the near future, it's great that Angular components make it so easy to add the desired functionality yourself.

Top comments (0)