Collapsible
A trigger that shows or hides a region, with a height animation.
import { … } from '@inlaylab/ivorie/collapsible'Hidden content.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { LucideChevronRight } from '@lucide/angular';
import { IV_COLLAPSIBLE_IMPORTS } from '@inlaylab/ivorie/collapsible';
@Component({
selector: 'demo-collapsible',
imports: [IV_COLLAPSIBLE_IMPORTS, LucideChevronRight],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<iv-collapsible [(open)]="open" class="w-80">
<button ivCollapsibleTrigger class="group flex items-center gap-2 text-sm font-medium">
Advanced settings
<svg lucideChevronRight class="size-4 transition-transform group-data-[state=open]:rotate-90"></svg>
</button>
<iv-collapsible-content>
<p class="pt-2 text-sm text-muted-foreground">Hidden content.</p>
</iv-collapsible-content>
</iv-collapsible>
`,
})
export default class CollapsibleDemo {
protected readonly open = signal(false);
}
Installation
npx ivorie add collapsibleimport { … } from '@inlaylab/ivorie/collapsible'Ports the shadcn/ui Collapsible. The height animates with a CSS grid transition. No @angular/animations needed.
Usage
import { IV_COLLAPSIBLE_IMPORTS } from '@inlaylab/ivorie/collapsible';<iv-collapsible [(open)]="isOpen">
<button ivCollapsibleTrigger>Advanced settings</button>
<iv-collapsible-content>Hidden content.</iv-collapsible-content>
</iv-collapsible>Examples
Open by default
Hidden content.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { LucideChevronRight } from '@lucide/angular';
import { IV_COLLAPSIBLE_IMPORTS } from '@inlaylab/ivorie/collapsible';
@Component({
selector: 'demo-collapsible-open-by-default',
imports: [IV_COLLAPSIBLE_IMPORTS, LucideChevronRight],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<iv-collapsible [(open)]="open" class="w-80">
<button ivCollapsibleTrigger class="group flex items-center gap-2 text-sm font-medium">
Details
<svg lucideChevronRight class="size-4 transition-transform group-data-[state=open]:rotate-90"></svg>
</button>
<iv-collapsible-content>
<p class="pt-2 text-sm text-muted-foreground">Hidden content.</p>
</iv-collapsible-content>
</iv-collapsible>
`,
})
export default class CollapsibleOpenByDefaultDemo {
protected readonly open = signal(true);
}
Disabled
Hidden content.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { LucideChevronRight } from '@lucide/angular';
import { IV_COLLAPSIBLE_IMPORTS } from '@inlaylab/ivorie/collapsible';
@Component({
selector: 'demo-collapsible-disabled',
imports: [IV_COLLAPSIBLE_IMPORTS, LucideChevronRight],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<iv-collapsible [(open)]="open" [disabled]="true" class="w-80">
<button ivCollapsibleTrigger class="group flex items-center gap-2 text-sm font-medium">
Can't open
<svg lucideChevronRight class="size-4 transition-transform group-data-[state=open]:rotate-90"></svg>
</button>
<iv-collapsible-content>
<p class="pt-2 text-sm text-muted-foreground">Hidden content.</p>
</iv-collapsible-content>
</iv-collapsible>
`,
})
export default class CollapsibleDisabledDemo {
protected readonly open = signal(false);
}
Animated chevron
Hidden content.
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { LucideChevronRight } from '@lucide/angular';
import { IV_COLLAPSIBLE_IMPORTS } from '@inlaylab/ivorie/collapsible';
@Component({
selector: 'demo-collapsible-animated-chevron',
imports: [IV_COLLAPSIBLE_IMPORTS, LucideChevronRight],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<iv-collapsible [(open)]="open" class="w-80">
<button ivCollapsibleTrigger class="group flex items-center gap-2 text-sm font-medium">
Details
<svg lucideChevronRight class="size-4 transition-transform group-data-[state=open]:rotate-90"></svg>
</button>
<iv-collapsible-content>
<p class="pt-2 text-sm text-muted-foreground">Hidden content.</p>
</iv-collapsible-content>
</iv-collapsible>
`,
})
export default class CollapsibleAnimatedChevronDemo {
protected readonly open = signal(false);
}
API
Every part also accepts class.
iv-collapsible
| Name | Type | Default | Description |
|---|---|---|---|
open |
boolean |
false |
Open state. Two-way bindable with [(open)]. |
disabled |
boolean |
false |
Blocks toggling. |
Outputs:
| Name | Payload | Description |
|---|---|---|
openChange |
boolean |
The open state changed. Use with [(open)]. |
ivCollapsibleTrigger
Attribute directive for the element that toggles. Put it on a <button> or any element. No inputs.
iv-collapsible-content
The expandable region. No own inputs.
Accessibility
- The trigger has
aria-expandedandaria-controlspointing at the content id. - A
<button>trigger keeps native behavior. Any other element getsrole="button",tabindex="0", and toggles on Enter and Space. - A disabled non-button trigger sets
aria-disabledandtabindex="-1". A disabled<button>gets thedisabledattribute. - Closed content is
inert. Its links and fields are not focusable and are hidden from assistive tech.
Notes
data-state="open" | "closed"is set on the root, trigger and content. Use it for styling, for examplegroup-data-[state=open]:rotate-90on a chevron.- Closed content stays in the DOM so the height can animate.