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.

Markup

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.

Default configuration

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.

Data-attributes
Attribute Default Description
classflexdrawerMandatory class that marks the element as a drawer.
idNoneOptional for target-driven use; required by static open, close, and toggle.
data-targetNoneID of the element that opens or toggles the drawer.
data-triggerclickclick or hover. Hover falls back to click on non-hover devices.
data-positionrighttop, right, bottom, or left.
data-width80vwDrawer width as a CSS length.
data-min-width0Minimum width. The responsive mobile rule safely reduces it to zero to avoid viewport overflow.
data-max-widthnoneMaximum width as a CSS length or none.
data-height100%Drawer height. Available viewport height is constrained by offsetTop.
data-min-height0Minimum height.
data-max-heightnoneMaximum height, also constrained to the viewport.
data-offset-top0Top inset. Useful when a persistent page header must remain visible.
data-padding10pxAny valid CSS padding value.
data-sliding-time0.3sCSS duration. A unitless value is interpreted as seconds.
data-responsivetrueFor left/right drawers at 640px or below, use the responsive width and remove the configured minimum width.
data-responsive-widthcalc(100vw - 24px)Mobile width used when responsive behavior is enabled.
data-background-color#f6f6f6Any CSS color, or none to preserve existing styling.
data-box-shadowautoauto, none, or a custom CSS box-shadow.
data-z-index1000Base stacking value. Open drawers are ordered above this value.
data-containerbodybody moves the element under document.body; parent retains it and uses absolute positioning.
data-close-modesoutsideComma-separated legacy-compatible modes: outside (or scrim), target, and button.
data-close-on-scrimFrom closeModesExplicitly enables or disables closing the top drawer from its scrim.
data-close-on-escapetrueEscape closes only the top open drawer.
data-close-buttonFrom closeModesExplicitly enables or disables the generated close button.
data-close-button-positionrightleft, 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-scrolltrueLocks background scrolling and restores the prior inline body styles after the final locking drawer closes.
data-modaltrueControls aria-modal and whether the shared scrim is active.
data-focus-traptrueContains Tab and Shift+Tab inside the top modal drawer.
data-restore-focustrueReturns focus to the element that opened the drawer.
data-initial-focusNoneSelector resolved inside the drawer. Fallback: first focusable element, then the drawer itself.
data-accessible-nameDrawerAccessible label used when the element does not already have aria-label or aria-labelledby.
data-scrim-opacity0.3Opacity for this drawer when it is topmost.
data-scrim-background-color#aaaScrim color for this drawer when it is topmost.
data-before-openNoneGlobal callback name. Return false to cancel.
data-on-openNoneGlobal callback name invoked after opening.
data-before-closeNoneGlobal callback name. Return false to cancel.
data-on-closeNoneGlobal callback name invoked after closing. This preserves the existing callback attribute.
Events and callbacks

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.

EventCallback option / attributeTiming
flexdrawer:beforeopenbeforeOpen / data-before-openBefore state or focus changes; cancelable.
flexdrawer:openonOpen / data-on-openAfter the open state is applied and initial focus is moved.
flexdrawer:beforeclosebeforeClose / data-before-closeBefore close state or focus restoration; cancelable.
flexdrawer:closeonClose / data-on-closeAfter 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
APIReturnsDescription
FlexDrawer.configure(options)NoneMerges global defaults for future instances.
FlexDrawer.initializeAll(root = document)Instance arrayInitializes uninitialized drawers under a root. Existing instances are reused, so repeated calls do not duplicate handlers.
FlexDrawer.initialize(elementOrSelector)Instance or nullInitializes a drawer added after DOMContentLoaded.
FlexDrawer.getInstance(id)Instance or nullGets an initialized drawer.
FlexDrawer.open(id, trigger?, reason?)Instance or nullOpens by ID. Existing open(id) calls remain valid.
FlexDrawer.close(id, reason?)Instance or nullCloses by ID. Existing close(id) calls remain valid.
FlexDrawer.toggle(id, trigger?, reason?)Instance or nullToggles by ID.
FlexDrawer.closeAll(reason?)Instance arrayCloses all open drawers top-down. A canceled beforeclose leaves that drawer open.
drawer.open(trigger?, reason?)BooleanReturns false when opening is canceled.
drawer.close(reason?)BooleanReturns false when closing is canceled.
drawer.toggle(trigger?, reason?)BooleanOpens or closes the instance.
drawer.destroy({ removeElement: false })NoneCloses, 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.
Stack and compatibility

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.