Skip to content

feat(Accordion): ngAccordionGroup should discover ngAccordionTrigger across component view boundaries #32995

@denisyilmaz

Description

@denisyilmaz

Which @angular package(s) are relevant/related to the feature request?

@angular/aria

Description

ngAccordionGroup cannot coordinate ngAccordionTrigger directives that live inside child component templates (views). This makes it impossible to build reusable accordion-item components that participate in a shared group defined by a parent.

Current behavior

AccordionGroup discovers triggers via contentChildren(AccordionTrigger, { descendants: true }). Angular's contentChildren only traverses the content DOM; it does not cross into child component view boundaries. Triggers defined inside a child component's own template are invisible to a parent-level ngAccordionGroup.

Interestingly, the reverse direction does work: AccordionTrigger successfully finds its parent group via inject(ACCORDION_GROUP) because DI naturally crosses view boundaries. This creates an asymmetry: triggers know about the group, but the group doesn't know about the triggers.

Reproduction

// panel.component.ts — reusable accordion item
@Component({
  selector: 'app-panel',
  imports: [AccordionTrigger, AccordionPanel],
  template: `
    <button ngAccordionTrigger [panel]="panel" #trigger="ngAccordionTrigger">
      <ng-content select="[title]" />
    </button>
    <div ngAccordionPanel #panel="ngAccordionPanel">
      <ng-content />
    </div>
  `,
})
export class PanelComponent {}
<!-- parent.component.html -->
<div ngAccordionGroup [multiExpandable]="false">
  <app-panel>
    <span title>Section 1</span>
    <p>Content 1</p>
  </app-panel>
  <app-panel>
    <span title>Section 2</span>
    <p>Content 2</p>
  </app-panel>
</div>

Result: Each trigger injects the group (no DI error), but the group's contentChildren query returns an empty list. The group cannot coordinate expansion (e.g. single-expand mode), and keyboard navigation between triggers does not work.

Workaround: Place a separate ngAccordionGroup inside each child component. This gives each panel its own independent accordion group, but loses all cross-panel coordination (multiExpandable, keyboard navigation between items, expandAll()/collapseAll(), etc.).

Expected behavior

ngAccordionGroup should discover and coordinate ngAccordionTrigger directives regardless of whether they are in the same template or inside child component views.

Use case

Accordion items are commonly wrapped in reusable components: a panel component with a header, icon, animations, and projected content. This is a standard composition pattern:

  • A <app-faq-item> component that encapsulates the trigger + panel + styling
  • A <app-collapsible-section> used across different pages
  • A <app-settings-panel> with consistent expand/collapse behavior

In all these cases, multiple instances should participate in a shared ngAccordionGroup to get single-expand mode, keyboard navigation, and expandAll()/collapseAll() for free.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: cdk/accordionfeatureLabel used to distinguish feature request from other issuesgemini-triagedLabel noting that an issue has been triaged by geminineeds triageThis issue needs to be triaged by the team

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions