Sheet
A panel that slides in from the edge of the screen. Useful for navigation, filters, forms, or any supplementary content.
Example
A right-side sheet used for navigation.
<div buiSheet side="end">
<button matButton buiSheetTrigger>Open Navigation</button>
<ng-template buiSheetPortal>
<div buiSheetBackdrop></div>
<div buiSheetContent>
<div buiSheetHeader class="items-center justify-between">
<h2 buiSheetTitle>Navigation</h2>
<button matIconButton buiSheetClose>
<mat-icon svgIcon="x" />
</button>
</div>
<div buiSheetBody class="flex flex-col gap-y-2">
<button matButton buiSheetClose class="tertiary justify-start">
<mat-icon svgIcon="house" />
<span>Home</span>
</button>
<button matButton buiSheetClose class="tertiary justify-start">
<mat-icon svgIcon="user" />
<span>Profile</span>
</button>
<button matButton buiSheetClose class="tertiary justify-start">
<mat-icon svgIcon="settings" />
<span>Settings</span>
</button>
</div>
</div>
</ng-template>
</div>Structure
The sheet is fully directive-based. You compose it by applying attribute directives to standard HTML elements.
<div buiSheet side="end">
<button matButton buiSheetTrigger>Open</button>
<ng-template buiSheetPortal>
<div buiSheetBackdrop></div>
<div buiSheetContent>
<div buiSheetHeader>
<h2 buiSheetTitle>Title</h2>
</div>
<div buiSheetBody>
Content goes here
</div>
<div buiSheetFooter>
<button matButton buiSheetClose>Close</button>
</div>
</div>
</ng-template>
</div>The building blocks are:
| Directive | Description |
|---|---|
buiSheet | Root container. Manages open state, position, and the CDK dialog. |
buiSheetTrigger | Opens the sheet when clicked. |
buiSheetPortal | Wraps the content that is rendered inside a CDK dialog overlay. |
buiSheetBackdrop | Semi-transparent backdrop behind the panel. Optional. |
buiSheetContent | The sliding panel itself. |
buiSheetHeader | Sticky header area. |
buiSheetTitle | Title text inside the header. |
buiSheetBody | Scrollable main content area. |
buiSheetFooter | Sticky footer area. |
buiSheetClose | Closes the sheet when clicked. |
buiSheet
The root directive. Apply it to any element to create a sheet instance. It manages the open state, handles keyboard and backdrop dismissal, and renders the content inside a CDK dialog.
<!-- Default (end) -->
<div buiSheet>...</div>
<!-- Left side -->
<div buiSheet side="start">...</div>
<!-- Prevent backdrop/Escape dismissal -->
<div buiSheet disableClose>...</div>| Prop | Type | Default | Description |
|---|---|---|---|
open | model<boolean> | false | Two-way binding for the open state. |
side | 'start' | 'end' | 'top' | 'bottom' | 'end' | Edge of the screen the sheet slides in from. |
disableClose | boolean | false | Prevents closing via backdrop click or Escape key. |
autoFocus | 'dialog' | 'first-tabbable' | 'first-heading' | string | undefined | 'first-tabbable' | Configures where focus goes when the dialog opens. |
restoreFocus | boolean | string | HTMLElement | true | Configures where focus returns when the dialog closes. |
(opened) | void | — | Emits when the sheet opens. |
(closed) | void | — | Emits after the sheet closes and its exit animation completes. |
Trigger
Apply buiSheetTrigger to a button or any clickable element. It automatically sets aria-expanded, aria-controls, and keyboard support (Enter / Space).
<button matButton buiSheetTrigger>Open Sheet</button>Portal
The buiSheetPortal directive goes on an ng-template. Its content is projected into a CDK dialog overlay when the sheet opens.
<ng-template buiSheetPortal>
<div buiSheetBackdrop></div>
<div buiSheetContent>
<!-- header, body, footer -->
</div>
</ng-template>Backdrop
Add buiSheetBackdrop inside the portal to render a semi-transparent overlay behind the panel. It is optional, omitting it gives you a sheet without a dimmed background.
Content
The buiSheetContent directive marks the sliding panel. It handles positioning, entry/exit animations, and nested sheet scaling. Place header, body, and footer directives inside it.
Header, Title & Description
The header is a sticky area at the top of the sheet. buiSheetTitle automatically connects to aria-labelledby on the dialog, and buiSheetDescription (optional) connects to aria-describedby.
<div buiSheetHeader class="items-center justify-between">
<h2 buiSheetTitle>Title</h2>
<button matIconButton buiSheetClose>
<mat-icon svgIcon="x" />
</button>
</div>Body
The scrollable main content area. It fills the available space between the header and footer.
Footer
A sticky area at the bottom. Typically holds action buttons like Apply or Cancel.
<div buiSheet side="start">
<button matButton buiSheetTrigger>Open Sheet</button>
<ng-template buiSheetPortal>
<div buiSheetBackdrop></div>
<div buiSheetContent>
<div buiSheetHeader class="items-center justify-between">
<h2 buiSheetTitle>Sheet Title</h2>
<button matIconButton buiSheetClose>
<mat-icon svgIcon="x" />
</button>
</div>
<div buiSheetBody>
Scrollable content here...
</div>
<div buiSheetFooter>
<button matButton buiSheetClose>Close</button>
</div>
</div>
</ng-template>
</div>Close
Apply buiSheetClose to any element inside the portal. It closes the sheet when clicked. Attach your own (click) handler separately for additional logic.
<button matButton buiSheetClose (click)="onSave()">
Save & Close
</button>Side
Use the side input to control which edge the sheet enters from. Sides start and end are direction-aware and flip automatically in RTL layouts.
<!-- Right (default) -->
<div buiSheet side="end">...</div>
<!-- Left -->
<div buiSheet side="start">...</div>
<!-- Top -->
<div buiSheet side="top">...</div>
<!-- Bottom -->
<div buiSheet side="bottom">...</div>Programmatic control
You can control the sheet without a trigger. Use the open model for two-way binding, or grab a template reference via #ref="buiSheet" and call open(), close(), or toggle().
<!-- Two-way binding -->
<div buiSheet [(open)]="isSheetOpen">
<ng-template buiSheetPortal>
<div buiSheetBackdrop></div>
<div buiSheetContent>...</div>
</ng-template>
</div>
<button matButton (click)="isSheetOpen = true">Open</button>
<!-- Template reference -->
<div buiSheet #mySheet="buiSheet">
<ng-template buiSheetPortal>
<div buiSheetBackdrop></div>
<div buiSheetContent>...</div>
</ng-template>
</div>
<button matButton (click)="mySheet.open()">Open</button>
<button matButton (click)="mySheet.close()">Close</button>
<button matButton (click)="mySheet.toggle()">Toggle</button>Disable close
Add disableClose to prevent closing via backdrop click or the Escape key. The user must use an explicit close button.
<div buiSheet side="end" disableClose>
<button matButton buiSheetTrigger>Open Sheet</button>
<ng-template buiSheetPortal>
<div buiSheetBackdrop></div>
<div buiSheetContent>
<div buiSheetHeader class="items-center justify-between">
<h2 buiSheetTitle>Disable Close</h2>
<button matIconButton buiSheetClose>
<mat-icon svgIcon="x" />
</button>
</div>
<div buiSheetBody>
<p>Only the close button can dismiss this sheet.</p>
</div>
</div>
</ng-template>
</div>