Advanced Components

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.

Right sheet with 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:

DirectiveDescription
buiSheet Root container. Manages open state, position, and the CDK dialog.
buiSheetTriggerOpens the sheet when clicked.
buiSheetPortal Wraps the content that is rendered inside a CDK dialog overlay.
buiSheetBackdropSemi-transparent backdrop behind the panel. Optional.
buiSheetContentThe sliding panel itself.
buiSheetHeaderSticky header area.
buiSheetTitleTitle text inside the header.
buiSheetBodyScrollable main content area.
buiSheetFooterSticky footer area.
buiSheetCloseCloses 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>
PropTypeDefaultDescription
openmodel<boolean>falseTwo-way binding for the open state.
side'start' | 'end' | 'top' | 'bottom''end'Edge of the screen the sheet slides in from.
disableClosebooleanfalse 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.
restoreFocusboolean | string | HTMLElementtrue Configures where focus returns when the dialog closes.
(opened)voidEmits 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.

Sheet with header, scrollable body, and footer
<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.

Open from different sides
<!-- 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.

Backdrop click and Escape key disabled
<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>