Drawer
A panel from an edge of the screen that you can drag to close.
import { … } from '@inlaylab/ivorie/drawer'import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { IvButton } from '@inlaylab/ivorie/button';
import { IV_DRAWER_IMPORTS } from '@inlaylab/ivorie/drawer';
@Component({
selector: 'demo-drawer',
imports: [IV_DRAWER_IMPORTS, IvButton],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<button ivButton variant="outline" [ivDrawerTrigger]="drawer">Open drawer</button>
<ng-template #drawer>
<div class="mx-auto w-full max-w-sm">
<iv-drawer-header>
<iv-drawer-title>Move goal</iv-drawer-title>
<iv-drawer-description>Set your daily activity goal.</iv-drawer-description>
</iv-drawer-header>
<div class="flex items-center justify-center gap-4 p-4">
<button ivButton variant="outline" size="icon" aria-label="Decrease" [disabled]="goal() <= 200" (click)="goal.set(goal() - 10)">−</button>
<div class="text-center">
<div class="text-6xl font-bold tracking-tighter tabular-nums">{{ goal() }}</div>
<div class="text-muted-foreground text-xs uppercase">Calories/day</div>
</div>
<button ivButton variant="outline" size="icon" aria-label="Increase" [disabled]="goal() >= 400" (click)="goal.set(goal() + 10)">+</button>
</div>
<iv-drawer-footer>
<button ivButton ivDrawerClose="saved">Submit</button>
<button ivButton variant="outline" ivDrawerClose>Cancel</button>
</iv-drawer-footer>
</div>
</ng-template>
`,
})
export default class DrawerDemo {
readonly goal = signal(350);
}
Installation
npx ivorie add drawerimport { … } from '@inlaylab/ivorie/drawer'A drawer is a Sheet with a drag gesture. Drag it more than a quarter of its size toward its edge and it closes with reason 'drag'. A shorter drag springs back. It uses the Dialog service, close reasons and focus rules.
Usage
import { IV_DRAWER_IMPORTS } from '@inlaylab/ivorie/drawer';<button ivButton [ivDrawerTrigger]="drawer">Open</button>
<ng-template #drawer>
<iv-drawer-header>
<iv-drawer-title>Title</iv-drawer-title>
</iv-drawer-header>
</ng-template>Or open it from code: inject(IvDrawer).open(MyComponent, { direction: 'right' }). It returns an IvDialogRef.
Examples
Direction
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IvButton } from '@inlaylab/ivorie/button';
import { DrawerDirection, IV_DRAWER_IMPORTS } from '@inlaylab/ivorie/drawer';
@Component({
selector: 'demo-drawer-direction',
imports: [IV_DRAWER_IMPORTS, IvButton],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="flex flex-wrap gap-2">
@for (direction of directions; track direction) {
<button ivButton variant="outline" class="capitalize" [ivDrawerTrigger]="drawer" [ivDrawerConfig]="{ direction }">{{ direction }}</button>
}
</div>
<ng-template #drawer>
<iv-drawer-header>
<iv-drawer-title>Drawer</iv-drawer-title>
<iv-drawer-description>Drag it toward its edge to close.</iv-drawer-description>
</iv-drawer-header>
<iv-drawer-footer>
<button ivButton variant="outline" ivDrawerClose>Close</button>
</iv-drawer-footer>
</ng-template>
`,
})
export default class DrawerDirectionDemo {
readonly directions: DrawerDirection[] = ['top', 'right', 'bottom', 'left'];
}
API
Every part also accepts class.
DrawerConfig
All Dialog config options except size, height and showCloseButton, plus:
| Name | Type | Default | Description |
|---|---|---|---|
direction |
'top' | 'right' | 'bottom' | 'left' |
'bottom' |
Edge the drawer comes from. |
[ivDrawerTrigger]
| Name | Type | Default | Description |
|---|---|---|---|
ivDrawerTrigger |
TemplateRef | Type |
required | Content to show. |
ivDrawerConfig |
DrawerConfig |
{} |
Options. |
Outputs: opened (IvDialogRef), closed (DialogCloseEvent).
[ivDrawerClose]
| Name | Type | Default | Description |
|---|---|---|---|
ivDrawerClose |
unknown |
undefined |
Result passed to afterClosed. |
reason |
DialogCloseReason |
'close-button' |
Close reason. |
Other parts
iv-drawer-header,iv-drawer-title,iv-drawer-description,iv-drawer-footer.
Accessibility
Same as Dialog: role="dialog" with aria-modal, labelled by the title, focus trapped inside, Escape closes, focus returns to the opener. Dragging is optional: a drawer can always close with Escape or a button.