Component
Drawer
A full-height panel over the page, from its end edge, to read or edit one record without leaving the list.
Plain-text source, for agents and clipboard use: /components/source/drawer.txt
When to use it
Shows a record, or a short task on it, while the page it came from stays in place behind. It is a native dialog opened with showModal(), so focus moves into it, the page behind is inert, Escape or a click outside closes it and focus returns to the button that opened it. The header names the record, the body scrolls on its own, and the action row stays pinned at the bottom.
Examples
Record
Opens over a list to show one booking. A click outside the drawer, the close button, Close or Escape all close it.
<button class="flux-button flux-button--secondary" type="button" commandfor="booking-drawer" command="show-modal">View KB-104931</button>
<dialog class="flux-drawer" id="booking-drawer" aria-labelledby="booking-drawer-title">
<div class="flux-drawer__header">
<div class="flux-drawer__heading">
<h2 class="flux-drawer__title" id="booking-drawer-title">KB-104931</h2>
<p class="flux-drawer__meta">Golden Circle, 14 Sep · 12 passengers</p>
</div>
<button class="flux-drawer__close" type="button" commandfor="booking-drawer" command="close" aria-label="Close"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7" /></svg></button>
</div>
<div class="flux-drawer__body">
<div class="flux-note flux-note--warning">
<div>
<p class="flux-note__title">Guide not assigned</p>
<p class="flux-note__body">The manifest cannot be sent until a guide is confirmed.</p>
</div>
</div>
<dl class="flux-dl">
<div class="flux-dl__pair"><dt class="flux-dl__term">Lead passenger</dt><dd class="flux-dl__detail">Anna Lindqvist</dd></div>
<div class="flux-dl__pair"><dt class="flux-dl__term">Agent</dt><dd class="flux-dl__detail">Nordic Trails</dd></div>
<div class="flux-dl__pair"><dt class="flux-dl__term">Status</dt><dd class="flux-dl__detail"><span class="flux-badge flux-badge--pending">On request</span></dd></div>
<div class="flux-dl__pair"><dt class="flux-dl__term">Balance due</dt><dd class="flux-dl__detail flux-dl__detail--data">€4,860.00</dd></div>
</dl>
</div>
<div class="flux-drawer__footer">
<button class="flux-button flux-button--ghost" type="button" commandfor="booking-drawer" command="close">Close</button>
<a class="flux-button" href="#">Open booking</a>
</div>
</dialog>Task
A form inside the drawer, with method="dialog" so Save closes it. Closing it any other way leaves the fields as they were, so reopening the drawer returns to what was typed.
<button class="flux-button flux-button--secondary" type="button" commandfor="guide-drawer" command="show-modal">Assign guide</button>
<dialog class="flux-drawer" id="guide-drawer" aria-labelledby="guide-drawer-title">
<form class="flux-drawer__form" method="dialog">
<div class="flux-drawer__header">
<div class="flux-drawer__heading">
<h2 class="flux-drawer__title" id="guide-drawer-title">Assign a guide</h2>
<p class="flux-drawer__meta">DEP-0914 · Golden Circle, 14 Sep</p>
</div>
<button class="flux-drawer__close" type="button" commandfor="guide-drawer" command="close" aria-label="Close"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4.5 4.5l7 7M11.5 4.5l-7 7" /></svg></button>
</div>
<div class="flux-drawer__body">
<div class="flux-field">
<label class="flux-field__label" for="guide-name">Guide</label>
<input class="flux-input" id="guide-name" name="guide" type="text" autocomplete="off" required />
</div>
<div class="flux-field">
<label class="flux-field__label" for="guide-meeting">Meeting point</label>
<input class="flux-input" id="guide-meeting" name="meeting" type="text" value="Hotel Kea, main entrance" />
</div>
<div class="flux-field">
<label class="flux-field__label" for="guide-note">Note to the guide</label>
<textarea class="flux-textarea" id="guide-note" name="note" rows="4"></textarea>
</div>
</div>
<div class="flux-drawer__footer">
<button class="flux-button flux-button--ghost" type="button" commandfor="guide-drawer" command="close">Cancel</button>
<button class="flux-button" type="submit">Assign guide</button>
</div>
</form>
</dialog>Anatomy
| Part | Description |
|---|---|
| Opener | A button with commandfor naming the drawer and command="show-modal". |
| Drawer | A dialog on surface-overlay with shadow-xl, full height at the end edge, 32rem wide or 48rem with flux-drawer--lg. |
| Header | The title, an optional line of context, and a close button. |
| Body | Scrolls on its own between the header and the action row. |
| Action row | Pinned at the bottom, right-aligned. Cancel or Close first, the primary action last. |
API
| Name | Kind | Description |
|---|---|---|
dialog | element | The native element. Open it with showModal(), never by toggling a class or the open attribute. |
flux-drawer | class | On the dialog. Give it an id and aria-labelledby pointing at the title. |
flux-drawer--lg | class | The wide drawer, for a record with a table in it. |
flux-drawer__header | __heading | __title | __meta | __close | class | The header row: the heading block, its title and context line, and the close button. |
flux-drawer__body | class | The scrolling content. |
flux-drawer__footer | class | The pinned action row. |
flux-drawer__form | class | A form wrapping header, body and footer, so a submit button in the footer submits the fields in the body. |
commandfor | command | attribute | On a button: the drawer’s id, and show-modal or close. flux-components.js supplies them where the browser does not. |
States
| State | Treatment |
|---|---|
| Closed | Not rendered and not focusable. |
| Open | Slides in from the end edge over surface-backdrop. The page behind is inert. |
| Narrow viewport | Never wider than the viewport; on a phone it covers the screen. |
Keyboard
| Keys | Action |
|---|---|
Escape | Closes the drawer. Native behaviour — do not prevent it. |
Tab | Cycles within the drawer only. |
Click outside | Closes the drawer. Requires flux-components.js. |
Accessibility
- showModal() traps focus, makes the page inert and handles Escape; a div-based drawer reimplements all three.
- Name the drawer with aria-labelledby pointing at its title, and give the close button an accessible name.
- Focus returns to the opener when the drawer closes. If the opener is removed, for instance because the record was deleted, move focus to the list it was in.
- Reduced motion removes the slide; the base layer handles it.
Tokens
The tier-3 and tier-2 tokens this component binds to. Change the token, not the component.
- --flux-drawer-width | -width-lg | -padding | -duration
- --flux-drawer-bg | -shadow | -backdrop | -divider
Do and don’t
Do
- Title the drawer with the record’s reference or the task it performs.
- Keep the page behind as it was, so closing the drawer returns to the same place in the list.
Don’t
- Do not open a drawer from a drawer, or a modal from a drawer for anything but a confirmation.
- Do not use a drawer for content people need beside the page while they work. Use the List and detail split view.
- Do not round the drawer’s corners or give it a border; it is an edge of the window, not a card.