Skip to content

Drawer

Drawer is a dialog docked to an edge of the viewport (Side), portaled out of ancestor clipping and stacking contexts, that additionally supports drag-to-dismiss: the engine drags the sheet along Side, publishing data-swiping and --drawer-swipe-movement-x / --drawer-swipe-movement-y while the pointer is down, and closes the drawer once the drag passes the threshold. It can be controlled (@bind-Open) or uncontrolled (DefaultOpen). When Modal (the default), opening it traps focus inside the popup and locks page scroll; closing it returns focus to the trigger.

Snap points, a restricted swipe-area edge, background scaling, nested drawers and the virtual-keyboard provider are not implemented.

@using Navius.Primitives.Components.Drawer
<NaviusDrawer>
<NaviusDrawerTrigger />
<NaviusDrawerPortal>
<NaviusDrawerBackdrop />
<NaviusDrawerPopup>
<NaviusDrawerTitle />
<NaviusDrawerDescription />
<NaviusDrawerClose />
</NaviusDrawerPopup>
</NaviusDrawerPortal>
</NaviusDrawer>

Owns the open state and the docked side, and cascades a DrawerContext to the parts. Renders no DOM of its own.

Prop Type Default Description
Open bool false Controlled open state. Pair with OpenChanged (@bind-Open).
OpenChanged EventCallback<bool> - Fires when the controlled Open value should change. Also fires as an observer when uncontrolled.
DefaultOpen bool false Initial open state when used uncontrolled.
Modal bool true When false, does not trap focus, does not lock scroll, and leaves outside content interactive.
Side string "bottom" The edge the sheet docks to and is dragged toward: "bottom", "top", "left" or "right".
ChildContent RenderFragment? - The drawer’s parts.

The button that opens the drawer. Renders a button.

Prop Type Default Description
ChildContent RenderFragment? - Trigger label content.
Attributes IDictionary<string, object>? - Forwarded to the rendered button.

Optional wrapper that records the mount target for the Backdrop and Popup. Renders no DOM of its own.

Prop Type Default Description
Container string? - CSS selector for the mount target. null uses document.body.
KeepMounted bool false Keeps the Backdrop and Popup mounted while closed, driving exit transitions off data-closed instead of unmounting.
ChildContent RenderFragment? - The Backdrop and Popup.

The scrim behind the sheet, portaled as a sibling of the Popup. Presentational only: outside dismissal is owned by the Popup’s dismissable layer. Renders a div.

Prop Type Default Description
KeepMounted bool false Keeps the backdrop mounted while closed, for exit animations.
Attributes IDictionary<string, object>? - Forwarded to the rendered div.

The draggable sheet that contains the drawer content, and the swipe target itself. Portaled; renders a div with role="dialog" and tabindex="-1".

Prop Type Default Description
KeepMounted bool false Keeps the popup mounted while closed, for exit animations.
OnOpenAutoFocus EventCallback<NaviusOpenAutoFocusEventArgs> - Fires when focus moves into the popup on open; cancelable.
OnCloseAutoFocus EventCallback<NaviusCloseAutoFocusEventArgs> - Fires when focus returns to the trigger on close; cancelable.
OnEscapeKeyDown EventCallback<NaviusEscapeKeyDownEventArgs> - Fires on Escape; cancelable.
OnPointerDownOutside EventCallback<NaviusPointerDownOutsideEventArgs> - Fires on pointer-down outside the popup; cancelable.
OnFocusOutside EventCallback<NaviusFocusOutsideEventArgs> - Fires when focus moves outside the popup; cancelable.
OnInteractOutside EventCallback<NaviusInteractOutsideEventArgs> - Fires on any outside interaction; cancelable.
ChildContent RenderFragment? - The drawer’s content.
Attributes IDictionary<string, object>? - Forwarded to the rendered div.

An accessible title for the sheet. aria-labelledby on the Popup points here. Renders an h2.

Prop Type Default Description
ChildContent RenderFragment? - Title content.
Attributes IDictionary<string, object>? - Forwarded to the rendered h2.

An optional accessible description. aria-describedby on the Popup points here. Renders a p.

Prop Type Default Description
ChildContent RenderFragment? - Description content.
Attributes IDictionary<string, object>? - Forwarded to the rendered p.

A button that closes the drawer. Lives inside the Popup. Renders a button.

Prop Type Default Description
ChildContent RenderFragment? - Close button content.
Attributes IDictionary<string, object>? - Forwarded to the rendered button.
Part Attribute Description
Trigger data-popup-open Present while the drawer is open.
Backdrop data-open Present while open.
Backdrop data-closed Present while closing (through the exit transition).
Backdrop data-starting-style Present at the start of the open transition.
Backdrop data-ending-style Present at the start of the close transition.
Popup data-open Present while open.
Popup data-closed Present while closing (through the exit transition).
Popup data-starting-style Present at the start of the open transition.
Popup data-ending-style Present at the start of the close transition.
Popup data-drawer-direction The docked edge (bottom, top, left, right), mirroring Side.
Popup data-swiping Set by the engine while a drag is in progress, and removed on drop or cancel.

While dragging, the engine also writes --drawer-swipe-movement-x and --drawer-swipe-movement-y as inline custom properties on the Popup, and removes them when the drag ends.

Key Behavior
Space Opens or closes the drawer when focus is on the trigger.
Enter Opens or closes the drawer when focus is on the trigger.
Tab Moves focus to the next focusable element inside the popup. Focus is trapped when modal.
Shift + Tab Moves focus to the previous focusable element inside the popup.
Escape Closes the drawer and returns focus to the trigger.

The Trigger wires aria-haspopup="dialog", aria-expanded, and aria-controls pointing at the Popup’s id. The Popup renders role="dialog" and sets aria-modal="true" when Modal. aria-labelledby and aria-describedby on the Popup are wired only when a Title or Description part is mounted, so no dangling IDREF is emitted when they are absent. On open, focus moves into the Popup; on close, it is restored to the Trigger. Drag-to-dismiss is a pointer affordance layered on top: Escape and the Close button remain the keyboard paths out. This mechanism is covered by the Playwright browser test suite and gated by axe-core in CI.