import { Component } from '@angular/core';
import { WR_DRAWER_DATA, WrDrawer, WrDrawerClose, WrDrawerContent, WrDrawerFooter, WrDrawerManager, WrDrawerRef, WrDrawerTitle } from 'ngwr/drawer';
@Component({ imports: [WrDrawer, WrDrawerClose, WrDrawerContent, WrDrawerFooter, WrDrawerTitle] })
export class MyComponent {}Drawer
A side panel that slides in from any edge of the screen.
Installation
Import the class, and @use the entry point in your global styles: without it the component renders unstyled.
Basic usage
Bind [(open)]; position picks the edge.
<wr-btn (click)="open.set(true)">Open</wr-btn>
<wr-drawer [(open)]="open" position="right" width="22rem">
<h2 wrDrawerTitle>Settings</h2>
<div wrDrawerContent>…</div>
<div wrDrawerFooter>
<wr-btn wrDrawerClose>Close</wr-btn>
<wr-btn color="primary" wrDrawerClose>Save</wr-btn>
</div>
</wr-drawer>Without a backdrop
Since v15 a drawer with hasBackdrop off is non-modal: the page stays clickable, scrollable and reachable with Tab.
<wr-drawer [(open)]="open" [hasBackdrop]="false" width="18rem">
<h2 wrDrawerTitle>Details</h2>
<div wrDrawerContent>…</div>
</wr-drawer>Focus still moves into the panel on open. Escape closes it unless you have moved on to the page, and closing returns focus to the opener unless you have moved on likewise.
Opening a drawer from code
WrDrawerManager.open() opens any component as a drawer and returns its close result. The content injects WR_DRAWER_DATA and WrDrawerRef.
import { WrDrawerManager } from 'ngwr/drawer';
export class Inbox {
private readonly drawers = inject(WrDrawerManager);
async openChat(threadId: string): Promise<void> {
const ref = this.drawers.open<ChatComponent, string, ChatData>(ChatComponent, {
data: { thread: threadId },
position: 'right',
width: '24rem',
});
const sent = await ref.awaitClose(); // string | undefined
}
}import { WR_DRAWER_DATA, WrDrawerRef } from 'ngwr/drawer';
@Component({...})
export class ChatComponent {
protected readonly data = inject<ChatData>(WR_DRAWER_DATA);
private readonly ref = inject<WrDrawerRef<ChatComponent, string>>(WrDrawerRef);
send(): void {
this.store.send(this.draft());
this.ref.close('sent');
}
}drawers.open(ChatComponent, { data, position: 'right', width: '24rem' })Drawer API
| Name | Description | Type | Default |
|---|---|---|---|
open | Open state. Two-way bindable. | boolean | false |
position | Side the drawer slides in from. | 'left' | 'right' | 'top' | 'bottom' | 'right' |
width | Width when position is left/right. | string | '20rem' |
height | Height when position is top/bottom. | string | '16rem' |
hasBackdrop | Show the dimming backdrop and make the drawer modal. false gives a non-modal panel. | boolean | true |
closeOnBackdropClick | Close when backdrop is clicked. | boolean | true |
closeOnEscape | Close on Escape. | boolean | true |
closable | Show the built-in dismiss (×) in the top-right corner. | boolean | true |
closeLabel | Accessible name for the dismiss button. Falls back to the drawer.close catalog key. | string | null | null |
Focus and lifetime
Mark the field to focus with cdkFocusInitial. Without it, <wr-drawer> focuses its ✕ and WrDrawerManager the first control.
<wr-drawer [(open)]="open" position="right">
<h2 wrDrawerTitle>Filters</h2>
<div wrDrawerContent>
<wr-form-field label="Search">
<input wrInput cdkFocusInitial [value]="query()" (input)="onQuery($event)" />
</wr-form-field>
</div>
</wr-drawer> A drawer from WrDrawerManager outlives its opener: close the ref in DestroyRef.onDestroy. <wr-drawer> closes with its view.
Service API
| Name | Description | Type | Default |
|---|---|---|---|
open(component, options?) | Opens a component as a drawer. Returns a WrDrawerRef. | (component, WrDrawerOptions) => WrDrawerRef | — |
WrDrawerOptions
The component inputs, plus data and closeOnNavigation.
| Name | Description | Type | Default |
|---|---|---|---|
data | Payload exposed to the content via WR_DRAWER_DATA. | D | — |
closeOnNavigation | Close the drawer when the router navigates. | boolean | true |
position | Side the drawer slides in from. | 'left' | 'right' | 'top' | 'bottom' | 'right' |
width | Width when position is left/right. | string | '20rem' |
height | Height when position is top/bottom. | string | '16rem' |
maxHeight | Height cap for top/bottom positions. | string | null | null |
rounded | Round the leading corners. | boolean | false |
safeArea | Pad the trailing edge with the safe-area inset. | boolean | false |
hasBackdrop | Show the dimming backdrop and make the drawer modal. false gives a non-modal panel. | boolean | true |
closeOnBackdropClick | Close when backdrop is clicked. | boolean | true |
closeOnEscape | Close on Escape. | boolean | true |
closable | Show the built-in dismiss (×) in the top-right corner. | boolean | true |
panelClass | Extra class(es) on the panel. | WrClassInput | null |
closeLabel | Accessible name for the dismiss button. Falls back to the drawer.close catalog key. | string | — |
panelClass | Extra class(es) on the box that slides in, not the CDK pane. | WrClassInput | — |
Layout directives
| Name | Description | Type | Default |
|---|---|---|---|
[wrDrawerTitle] | Styles the title row. | directive | — |
[wrDrawerContent] | Styles the scrollable body. | directive | — |
[wrDrawerFooter] | Styles the footer row. | directive | — |
align | Horizontal alignment of the footer content. | 'start' | 'center' | 'end' | 'end' |
[wrDrawerClose]="value?" | Closes the drawer on click. The value is the close result of a service-opened drawer. | directive | — |
Available inside a service-opened drawer
| Name | Description | Type | Default |
|---|---|---|---|
WR_DRAWER_DATA | The data payload passed to open(). undefined when you didn't pass any. | InjectionToken<D> | — |
WrDrawerRef | The open drawer’s own ref — call close(result) to dismiss it from the content. | WrDrawerRef<unknown, unknown> | — |
WR_DRAWER_REF | The same ref, used by [wrDrawerClose]. Prefer inject(WrDrawerRef). | InjectionToken<WrDrawerRef<C, R>> | — |
CSS variables
Set these on the component's selector or a wrapper, not on :root: the defaults are declared on ngwr/drawer's own element.
| Variable | Default | Declared on |
|---|---|---|
--wr-drawer-bg | var(--wr-color-surface) | .wr-drawer__panel |
--wr-drawer-close-font-size | var(--wr-text-base) | .wr-drawer__close |
--wr-drawer-close-padding | var(--wr-space-xs) | .wr-drawer__close |
--wr-drawer-close-radius | var(--wr-border-radius-sm) | .wr-drawer__close |
--wr-drawer-content-font-size | var(--wr-text-base) | .wr-drawer__content |
--wr-drawer-content-line-height | var(--wr-text-base-leading) | .wr-drawer__content |
--wr-drawer-content-padding-x | var(--wr-space-xl) | .wr-drawer__content |
--wr-drawer-content-padding-y | var(--wr-space-lg) | .wr-drawer__content |
--wr-drawer-font-family | var(--wr-font-family-base) | .wr-drawer__panel |
--wr-drawer-footer-border | var(--wr-border-base) | .wr-drawer__footer |
--wr-drawer-footer-gap | var(--wr-space-sm) | .wr-drawer__footer |
--wr-drawer-footer-padding-x | var(--wr-space-xl) | .wr-drawer__footer |
--wr-drawer-footer-padding-y | var(--wr-space-md) | .wr-drawer__footer |
--wr-drawer-radius | var(--wr-border-radius-lg) | .wr-drawer__panel |
--wr-drawer-shadow | var(--wr-shadow-modal) | .wr-drawer__panel |
--wr-drawer-title-border | var(--wr-border-base) | .wr-drawer__title |
--wr-drawer-title-font-size | var(--wr-text-lg) | .wr-drawer__title |
--wr-drawer-title-font-weight | var(--wr-font-weight-semibold) | .wr-drawer__title |
--wr-drawer-title-line-height | var(--wr-text-base-leading) | .wr-drawer__title |
--wr-drawer-title-padding-x | var(--wr-space-xl) | .wr-drawer__title |
--wr-drawer-title-padding-y | var(--wr-space-lg) | .wr-drawer__title |
Dependencies
| Angular CDK | a11y, overlay, portal |
|---|---|
| Built on | Overlay |
See also
Component DialogOpen any component as a modal dialog and await its result.Component WindowDraggable, resizable windows that you open from code with WrWindowManager.Component BurgerA menu button that morphs between a hamburger and a close mark.Component SidebarNavigation drawn from data: pages and groups, three levels deep.Guide Mobile & responsiveMake ngwr layouts work on touch screens and narrow containers.Guide OverlayStyle ngwr's floating panels and control where focus goes.Component InputA directive that styles a native <input> or <textarea>.