Advanced Components

Collapsible

A container that expands and collapses to show or hide content. Useful for sidebars, menus, filters, nested lists, or any place where content needs to toggle from a trigger.

Example

A basic collapsible with a trigger and expandable content.

Basic collapsible
Multiple collapsibles
<div buiCollapsible>
<button
buiCollapsibleTrigger
class="flex items-center justify-between ..."
>
<span>Click to expand</span>
<mat-icon svgIcon="chevron-down" class="size-4 transition-transform group-data-[state=open]/bui-collapsible:rotate-180" />
</button>
<ng-template buiCollapsiblePanel>
<div buiCollapsibleContent>
<div class="p-4">
This is the collapsible content.
</div>
</div>
</ng-template>
</div>

Structure

The collapsible is fully directive-based. You compose it by applying attribute directives to standard HTML elements.

<div buiCollapsible>
<button buiCollapsibleTrigger>Toggle</button>

<ng-template buiCollapsiblePanel>
<div buiCollapsibleContent>
Content goes here
</div>
</ng-template>
</div>

The building blocks are:

DirectiveDescription
buiCollapsibleRoot directive that manages state and accessibility.
buiCollapsibleTriggerApplied to a clickable element to toggle the collapsible.
buiCollapsiblePanel Wraps content in an ng-template, rendered only when expanded.
buiCollapsibleContentMarks the animated content container inside the panel.

buiCollapsible

The root directive. Apply it to any element to create a collapsible instance. It manages the expanded state, generates accessibility IDs, and exposes a data-state attribute for CSS hooks.

<!-- Default (collapsed) -->
<div buiCollapsible>...</div>

<!-- Expanded by default -->
<div buiCollapsible [(expanded)]="isExpanded">...</div>

<!-- Template reference -->
<div buiCollapsible #ref="buiCollapsible">...</div>
PropTypeDefaultDescription
expandedmodel<boolean>falseTwo-way binding for the expanded state.

Trigger

Apply buiCollapsibleTrigger to a button or any clickable element. It automatically sets aria-expanded, aria-controls, and keyboard support (Enter / Space). It also exposes data-state for CSS styling.

<button buiCollapsibleTrigger>Toggle</button>

Panel

The buiCollapsiblePanel directive goes on an ng-template. Its content is only rendered in the DOM when the collapsible is expanded and destroyed when collapsed.

<ng-template buiCollapsiblePanel>
<div buiCollapsibleContent>
Content rendered only when expanded
</div>
</ng-template>

Content

The buiCollapsibleContent directive marks the animated container inside the panel. It applies expand/collapse animations and connects to aria-labelledby for accessibility. It uses role="region" by default.

<div buiCollapsibleContent>
Animated content container
</div>
PropTypeDefaultDescription
enterAnimationstring'animate-collapsible-down'CSS animation class applied when expanding.
leaveAnimationstring'animate-collapsible-up'CSS animation class applied when collapsing.

Programmatic control

You can control the collapsible without a trigger. Use the expanded model for two-way binding, or grab a template reference via #ref="buiCollapsible" and call toggle().

<!-- Two-way binding -->
<div buiCollapsible [(expanded)]="isExpanded">
<ng-template buiCollapsiblePanel>
<div buiCollapsibleContent>...</div>
</ng-template>
</div>

<button (click)="isExpanded = !isExpanded">Toggle</button>

<!-- Template reference -->
<div buiCollapsible #myCollapsible="buiCollapsible">
<ng-template buiCollapsiblePanel>
<div buiCollapsibleContent>...</div>
</ng-template>
</div>

<button (click)="myCollapsible.toggle()">Toggle</button>

Expanded by default

Set [(expanded)] to a signal initialized to true to render the collapsible in its expanded state on mount. The enter animation is automatically skipped on the initial render so the content appears immediately without an animation flash.

Open on mount

This content was visible from the start without an animation. Toggle it to see the collapse and expand animations.

<!-- In the component class -->
readonly isExpanded = signal(true);

<!-- In the template -->
<div buiCollapsible [(expanded)]="isExpanded">
<button buiCollapsibleTrigger class="...">
Already expanded
</button>
<ng-template buiCollapsiblePanel>
<div buiCollapsibleContent>
This content is visible from the start.
</div>
</ng-template>
</div>

CSS hooks

The collapsible exposes data-state on the root, trigger, and content elements. Use Tailwind's group-data-[state=open] selector (scoped via the group/bui-collapsible group) to style child elements based on the expanded state. For example, rotating a chevron icon:

<div buiCollapsible>
<button buiCollapsibleTrigger class="flex items-center gap-2">
<span>Toggle</span>
<mat-icon svgIcon="chevron-down" class="size-4 transition-transform group-data-[state=open]/bui-collapsible:rotate-180" />
</button>
...
</div>