abaabil

Drawer

25th lightest of the thirty-two, by js weight

A modal panel pinned to one edge of the viewport. A drawer is a modal dialog with different geometry, so it is a native <dialog> with different geometry.

Example (a11y tier)

Filters

A native <dialog> pinned to one edge. Focus containment, Escape, the inert background and the top layer are all showModal(); the slide is a CSS @starting-style transition with nothing holding an “is opening” flag.

Import

import Drawer from 'abaabil/drawer'         // structure only
import Drawer from 'abaabil/drawer/styled'  // + CSS
import Drawer from 'abaabil/drawer/a11y'    // + open, label, scroll lock

Everything hard about a drawer is showModal()

The top layer, focus containment, an inert background, Escape to close and a real backdrop are all things the platform does for a modal <dialog>. Reimplementing them over a fixed-position <div> is most of why other libraries' drawers weigh what they do: this one is 606 B where the lightest rival on the comparison is several thousand.

Like dialog, this deliberately does not implement a focus trap. There is nothing to implement.

side is logical, not physical

end is the right edge in English and the left edge in Arabic, because it resolves against the document's direction rather than the screen. The entry animation mirrors with it, so a drawer that slides in from the right in one language slides in from the left in the other with no second component and no prop change. See the RTL demo.

The slide is CSS, not state

@starting-style lets the drawer animate from a state that only exists at the moment it enters the top layer. Without it a component has to hold an “is opening” flag, and then a “closing” one, and delay its own close() until a transition ends. That state machine is what this component does not contain.

Browsers without @starting-style show the drawer immediately, which is a fine degradation. Under prefers-reduced-motion so does everyone.

Scroll lock

A drawer leaves most of the page visible, which makes scrolling behind it look like the page is working when it is inert. So the a11y tier locks body overflow while open and restores whatever was there before on close, rather than assuming it was visible.

Props

PropTypeDefaultTierDescription
side'start' | 'end' | 'top' | 'bottom''end'allLogical. Applied as data-side.
openbooleanfalsea11yDrives showModal() and close().
labelstringa11yAccessible name. The platform supplies none.
onClose() => voida11yEscape, backdrop click and close().
classNamestringallMerged with the base class.