<bmx-drawer>
A panel that slides in from an edge: filters beside a table, a record's
detail beside the list it came from, a navigation menu on a narrow screen.
Everything bmx-dialog is, arriving from the side rather than from the
middle - and the difference is not only decoration. A drawer keeps the page
it came from visible along one edge, which is what makes it the right shape
for something you consult about what is behind it rather than instead of
it.
12 properties · 2 events · 2 methods · 7 parts
Example
A navigation drawer sits on the leading edge, where the page's own navigation would be.
A sheet from the bottom edge is the shape a phone expects for a share or an action list.
Show markup
<div class="row">
<bmx-button id="ex-drawer-end" variant="outline" tone="neutral">Filters</bmx-button>
<bmx-button id="ex-drawer-start" variant="outline" tone="neutral">Navigation</bmx-button>
<bmx-button id="ex-drawer-bottom" variant="outline" tone="neutral">From the bottom</bmx-button>
</div>
<!--
`edge` is logical. `end` opens from the right in English and from the left in
Arabic, with nothing to change in between; `top` and `bottom` do not mirror,
because the block direction runs the same way in every locale.
-->
<bmx-drawer id="ex-drawer-1" heading="Filters" edge="end">
<div style="display: grid; gap: var(--bmx-space-3); justify-items: start">
<bmx-checkbox label="In stock only" checked></bmx-checkbox>
<bmx-checkbox label="Free delivery"></bmx-checkbox>
<bmx-checkbox label="Discounted"></bmx-checkbox>
</div>
<bmx-button slot="footer" variant="ghost" tone="neutral" id="ex-drawer-clear">Clear</bmx-button>
<bmx-button slot="footer" id="ex-drawer-apply">Apply</bmx-button>
</bmx-drawer>
<bmx-drawer id="ex-drawer-2" heading="Sections" edge="start" size="sm">
<p style="margin: 0">A navigation drawer sits on the leading edge, where the page's own navigation would be.</p>
</bmx-drawer>
<bmx-drawer id="ex-drawer-3" heading="Share this report" edge="bottom" size="sm">
<p style="margin: 0">A sheet from the bottom edge is the shape a phone expects for a share or an action list.</p>
</bmx-drawer>
<script type="module">
await customElements.whenDefined('bmx-drawer');
const open = (button, drawer) => {
document.getElementById(button).addEventListener('bmxActivate', () => document.getElementById(drawer).openDrawer());
};
open('ex-drawer-end', 'ex-drawer-1');
open('ex-drawer-start', 'ex-drawer-2');
open('ex-drawer-bottom', 'ex-drawer-3');
const filters = document.getElementById('ex-drawer-1');
document.getElementById('ex-drawer-clear').addEventListener('bmxActivate', () => filters.closeDrawer());
document.getElementById('ex-drawer-apply').addEventListener('bmxActivate', () => filters.closeDrawer());
</script>
WHY IT IS A SECOND ELEMENT AND NOT A position ON THE FIRST
The same reasoning that made bmx-combobox its own element rather than a
flag on bmx-select. The two have different defaults, different sizing (a
drawer's size is its width, a dialog's is a maximum), a different edge
vocabulary, and different documentation pages - and a consumer scanning the
library for "drawer" should find one rather than a paragraph inside
something else. The behaviour they share is shared as code: one
BmxDialogSurface, one dialog.css, one set of chrome helpers, and one
src/core/dialog.ts between them.
Stencil does not support component inheritance, so the properties below are declared rather than derived. That duplication is deliberate and bounded: it is the declarations only, and every line of behaviour behind them is shared.
THE EDGES ARE LOGICAL
start and end mirror under RTL, so a drawer that opens from the right in
English opens from the left in Arabic without the consumer doing anything.
top and bottom do not mirror, because the block direction of every locale
this library supports runs the same way. An edge named left would be the
one thing here that does not mirror, and it would be wrong in half the
world's scripts while looking perfect in English.
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
closeLabel |
close-label |
string |
'Close' |
The close button's accessible name. |
closeOnBackdrop |
close-on-backdrop |
boolean |
true |
Whether a press on the scrim dismisses it. |
closeOnEscape |
close-on-escape |
boolean |
true |
Whether Escape dismisses it. |
dismissible |
dismissible |
boolean |
true |
Whether the user may dismiss it. Never restrains closeDrawer(). |
edge |
edge |
BmxDrawerEdge |
'end' |
Which edge it slides in from. start and end mirror under RTL. |
heading |
heading |
string |
— | The visible title. Also the drawer's accessible name. |
hideClose |
hide-close |
boolean |
false |
Hide the close button while still allowing Escape and the backdrop. |
initialFocus |
initial-focus |
string | HTMLElement |
— | What is focused when it opens, as a CSS selector or an element. |
label |
label |
string |
— | The accessible name, for a design with no visible title. |
open |
open |
boolean |
false |
Whether the drawer is showing. Mutable, so it can close itself. |
returnFocus |
return-focus |
boolean |
true |
Whether closing returns focus to whatever opened it. |
size |
size |
BmxDialogSize |
'md' |
How much of the screen it takes. The panel's width on start and end, its height on top and bottom. full covers the viewport, which is what a navigation drawer on a phone usually wants. |
Events
| Event | Detail | Description |
|---|---|---|
bmxClose |
BmxDialogCloseDetail |
Fired once it has finished closing, with why it closed. |
bmxOpenChange |
boolean |
Fired when the drawer opens or closes. |
Methods
| Method | Signature | Description |
|---|---|---|
closeDrawer |
closeDrawer() => Promise<void> |
Close the drawer. Always permitted, whatever dismissible says. |
openDrawer |
openDrawer() => Promise<void> |
Open the drawer. |
Slots
| Slot | Description |
|---|---|
(default) |
The drawer's content. |
footer |
The row of actions along the bottom. |
heading |
Replaces the plain-text heading. |
CSS shadow parts
| Part | Description |
|---|---|
body |
The scrolling content area. |
close |
The close button. |
dialog |
The native element, which is also the scrim. |
footer |
The row of actions. |
header |
The bar across the top. |
heading |
The title within it. |
panel |
The box the content sits in. |
CSS custom properties
| Property | Description |
|---|---|
--bmx-dialog-padding |
Space inside the panel's header, body and footer. |
--bmx-dialog-scrim |
The colour laid over the page behind it. |
--bmx-drawer-size |
The panel's width on a side edge, its height on a top or bottom one. |