FlexDrawer Documentation
FlexDrawer creates an accessible panel that slides in from a viewport edge. It supports markup and dynamically inserted drawers, internal scrolling, responsive width, focus management, lifecycle events, and a shared multi-drawer stack.
Any element with class flexdrawer is initialized automatically on DOMContentLoaded. Only the class is mandatory; an id is required for static API calls.
<button type="button" id="openCustomerDrawer">Edit customer</button>
<div class="flexdrawer"
id="customerDrawer"
data-target="openCustomerDrawer"
data-position="right"
data-width="72vw"
data-min-width="360px"
data-max-width="1100px"
data-responsive="true"
data-responsive-width="calc(100vw - 16px)"
data-close-modes="outside,button"
data-close-button-position="right"
data-close-on-escape="true"
data-initial-focus="#customerName"
data-accessible-name="Edit customer">
<label>Customer name
<input id="customerName" type="text" />
</label>
</div>
For no-flash initialization, call FlexDrawer.writeStyles() before drawer markup is parsed, as shown on the development page and in the published component structure.
FlexDrawer.configure(options) changes defaults for subsequently initialized drawers. Nested scrim values are merged instead of replacing the whole object.
FlexDrawer.configure({
container: "body",
trigger: "click",
position: "right",
zIndex: 1000,
padding: "10px",
offsetTop: "0",
slidingTime: "0.3s",
width: "80vw",
minWidth: "0",
maxWidth: "none",
height: "100%",
minHeight: "0",
maxHeight: "none",
responsive: true,
responsiveWidth: "calc(100vw - 24px)",
backgroundColor: "#f6f6f6",
boxShadow: "auto",
closeModes: ["outside"],
closeOnScrim: null,
closeButton: null,
closeButtonPosition: "right",
closeOnEscape: true,
focusTrap: true,
restoreFocus: true,
lockBodyScroll: true,
modal: true,
initialFocus: null,
accessibleName: "Drawer",
beforeOpen: null,
onOpen: null,
beforeClose: null,
onClose: null,
scrim: {
opacity: 0.3,
backgroundColor: "#aaa"
}
});
Length options accept CSS length strings. Numeric JavaScript values are interpreted as pixels. Numeric animation values are interpreted as seconds. Boolean data-attributes accept true/false, 1/0, and yes/no. List options accept arrays in JavaScript and comma-separated data-attribute values.
| Attribute | Default | Description |
|---|---|---|
class | flexdrawer | Mandatory class that marks the element as a drawer. |
id | None | Optional for target-driven use; required by static open, close, and toggle. |
data-target | None | ID of the element that opens or toggles the drawer. |
data-trigger | click | click or hover. Hover falls back to click on non-hover devices. |
data-position | right | top, right, bottom, or left. |
data-width | 80vw | Drawer width as a CSS length. |
data-min-width | 0 | Minimum width. The responsive mobile rule safely reduces it to zero to avoid viewport overflow. |
data-max-width | none | Maximum width as a CSS length or none. |
data-height | 100% | Drawer height. Available viewport height is constrained by offsetTop. |
data-min-height | 0 | Minimum height. |
data-max-height | none | Maximum height, also constrained to the viewport. |
data-offset-top | 0 | Top inset. Useful when a persistent page header must remain visible. |
data-padding | 10px | Any valid CSS padding value. |
data-sliding-time | 0.3s | CSS duration. A unitless value is interpreted as seconds. |
data-responsive | true | For left/right drawers at 640px or below, use the responsive width and remove the configured minimum width. |
data-responsive-width | calc(100vw - 24px) | Mobile width used when responsive behavior is enabled. |
data-background-color | #f6f6f6 | Any CSS color, or none to preserve existing styling. |
data-box-shadow | auto | auto, none, or a custom CSS box-shadow. |
data-z-index | 1000 | Base stacking value. Open drawers are ordered above this value. |
data-container | body | body moves the element under document.body; parent retains it and uses absolute positioning. |
data-close-modes | outside | Comma-separated legacy-compatible modes: outside (or scrim), target, and button. |
data-close-on-scrim | From closeModes | Explicitly enables or disables closing the top drawer from its scrim. |
data-close-on-escape | true | Escape closes only the top open drawer. |
data-close-button | From closeModes | Explicitly enables or disables the generated close button. |
data-close-button-position | right | left, right, or none. A visible close button occupies a 36px row followed by an 8px bottom gap, so drawer content cannot collide with it. none disables the button even when closeModes contains button. |
data-lock-body-scroll | true | Locks background scrolling and restores the prior inline body styles after the final locking drawer closes. |
data-modal | true | Controls aria-modal and whether the shared scrim is active. |
data-focus-trap | true | Contains Tab and Shift+Tab inside the top modal drawer. |
data-restore-focus | true | Returns focus to the element that opened the drawer. |
data-initial-focus | None | Selector resolved inside the drawer. Fallback: first focusable element, then the drawer itself. |
data-accessible-name | Drawer | Accessible label used when the element does not already have aria-label or aria-labelledby. |
data-scrim-opacity | 0.3 | Opacity for this drawer when it is topmost. |
data-scrim-background-color | #aaa | Scrim color for this drawer when it is topmost. |
data-before-open | None | Global callback name. Return false to cancel. |
data-on-open | None | Global callback name invoked after opening. |
data-before-close | None | Global callback name. Return false to cancel. |
data-on-close | None | Global callback name invoked after closing. This preserves the existing callback attribute. |
Each event bubbles from the drawer. beforeopen and beforeclose are cancelable. Call event.preventDefault(), or return false from the corresponding callback, to cancel the action.
| Event | Callback option / attribute | Timing |
|---|---|---|
flexdrawer:beforeopen | beforeOpen / data-before-open | Before state or focus changes; cancelable. |
flexdrawer:open | onOpen / data-on-open | After the open state is applied and initial focus is moved. |
flexdrawer:beforeclose | beforeClose / data-before-close | Before close state or focus restoration; cancelable. |
flexdrawer:close | onClose / data-on-close | After close state and focus restoration. |
Event detail and callback arguments contain drawer, trigger, reason, and sourceEvent. Typical reasons include target, api, button, escape, scrim, closeAll, and destroy.
drawerElement.addEventListener("flexdrawer:beforeclose", event => {
if (formIsDirty && event.detail.reason !== "save") {
event.preventDefault();
}
});
| API | Returns | Description |
|---|---|---|
FlexDrawer.configure(options) | None | Merges global defaults for future instances. |
FlexDrawer.initializeAll(root = document) | Instance array | Initializes uninitialized drawers under a root. Existing instances are reused, so repeated calls do not duplicate handlers. |
FlexDrawer.initialize(elementOrSelector) | Instance or null | Initializes a drawer added after DOMContentLoaded. |
FlexDrawer.getInstance(id) | Instance or null | Gets an initialized drawer. |
FlexDrawer.open(id, trigger?, reason?) | Instance or null | Opens by ID. Existing open(id) calls remain valid. |
FlexDrawer.close(id, reason?) | Instance or null | Closes by ID. Existing close(id) calls remain valid. |
FlexDrawer.toggle(id, trigger?, reason?) | Instance or null | Toggles by ID. |
FlexDrawer.closeAll(reason?) | Instance array | Closes all open drawers top-down. A canceled beforeclose leaves that drawer open. |
drawer.open(trigger?, reason?) | Boolean | Returns false when opening is canceled. |
drawer.close(reason?) | Boolean | Returns false when closing is canceled. |
drawer.toggle(trigger?, reason?) | Boolean | Opens or closes the instance. |
drawer.destroy({ removeElement: false }) | None | Closes, removes instance handlers and generated controls, unregisters the instance, and optionally removes its element. |
const element = document.createElement("div");
element.className = "flexdrawer";
element.id = "dynamicDrawer";
element.setAttribute("data-accessible-name", "Dynamic drawer");
element.innerHTML = "<p>Content may be updated at any time.</p>";
document.body.appendChild(element);
const drawer = FlexDrawer.initialize(element);
drawer.open(document.activeElement, "dynamic");
// FlexDrawer handles presentation and interaction only.
// Fetching data and submitting forms remain application responsibilities.
Open drawers form one ordered stack. The newest open drawer is topmost. The shared scrim belongs to that top drawer, Tab trapping applies only there, and Escape or scrim click closes only that drawer. closeAll() is the explicit way to close the full stack.
Backward-compatible APIs and attributes retained: config, configure, initializeAll, open, close, closeAll, all original layout attributes, data-close-modes, and data-on-close. The documented but non-functional singular data-close spelling is not supported; use data-close-modes.
Behavior change: the old scrim handler called closeAll(). It now closes only the top eligible drawer, which is required for deterministic multi-drawer behavior and focus restoration.