Skip to main content

Drawer

A headless, WCAG-compliant drawer component for React that provides focus trapping, scroll lock, click outside, ESC-to-close, and portal support. Fully customizable — the user controls styles and the close button.


Usage

Basic usage

import { Drawer } from '@nofinite/nui';

<Drawer open={open} onClose={handleClose}>
{/* custom content */}
</Drawer>;

With typical interaction

<Drawer
open={open}
onClose={handleClose}
position="left"
disableEsc={false}
disableClickOutside={false}
>
<div style={{ padding: 20 }}>
<h2>Custom Drawer</h2>
<p>You can style anything in here.</p>
<button onClick={handleClose}>Close</button>
</div>
</Drawer>

Variants

Drawer supports different positions:

<Drawer position="left" />
<Drawer position="right" />
<Drawer position="top" />
<Drawer position="bottom" />

Available variants:

  • left – Drawer slides in from the left side.
  • right – Drawer slides in from the right side (default).
  • top – Drawer slides down from the top.
  • bottom – Drawer slides up from the bottom.

Guidelines:

  • Use left/right for side navigation or menus.
  • Use top/bottom for temporary alerts, modals, or contextual drawers.

Sizes

Sizes are controlled via CSS or custom styling. Width/height varies by position:

  • left / right: 320px width
  • top: 260px height
  • bottom: 280px height

You can override dimensions with custom styles:

<Drawer position="left" className="custom-width">
{/* content */}
</Drawer>

States

<Drawer open={true} />
<Drawer open={false} />
<Drawer disableEsc={true} />
<Drawer disableClickOutside={true} />
  • open – whether the drawer is visible.
  • disableEsc – disables closing with the ESC key.
  • disableClickOutside – disables closing by clicking outside the drawer.

Native Props / Composition

Drawer extends div props. You can pass className, style, or any HTML attributes:

<Drawer
open={open}
onClose={handleClose}
className="my-custom-class"
aria-label="Navigation drawer"
>
{/* content */}
</Drawer>

Props

PropTypeDefaultDescription
openbooleanControls whether the drawer is open.
onClose() => voidCallback invoked when the drawer requests to close.
position"left" | "right" | "top" | "bottom"rightDetermines the drawer slide-in position.
disableEscbooleanfalseIf true, ESC key will not close the drawer.
disableClickOutsidebooleanfalseIf true, clicking outside will not close the drawer.
classNamestring""Additional CSS classes for custom styling.
childrenReact.ReactNodeContent rendered inside the drawer.
...restReact.HTMLAttributes<HTMLDivElement>Any other native HTML attributes forwarded to the drawer.

Behavior Notes

  • Focus is trapped inside the drawer while open.
  • Background scrolling is locked when drawer is open.
  • Clicking outside or pressing ESC closes the drawer (unless disabled).
  • Drawer uses a portal to render at the document root.
  • Focus is restored to the previously focused element on close.
  • Drawer supports inert management for sibling elements to improve accessibility.
<Drawer open={open} onClose={handleClose}>
{/* Example of focus trap and scroll lock in action */}
</Drawer>

Accessibility

  • Renders as: <div role="dialog" aria-modal="true">
  • Keyboard support: Tab and Shift+Tab for focus navigation, ESC to close (if not disabled).
  • Screen readers are notified of the modal context.
  • Proper inert handling ensures background content is not interactable.
  • Icon-only or custom close buttons should have accessible labels.
<Drawer aria-label="Navigation drawer">
<button aria-label="Close drawer">X</button>
</Drawer>

Layout

  • Fixed overlay covers the viewport.
  • Drawer is positioned absolutely relative to overlay based on position.
  • Drawer width/height can be customized via CSS or className.
  • Overlay ensures modal layering and dimming.
<Drawer open={open} style={{ width: '400px' }}>
Full-width custom drawer
</Drawer>

Best Practices

Do

  • Use for side menus, contextual panels, or modal-like overlays.
  • Provide a clear, accessible close button inside the drawer.
  • Combine with proper focus management for accessibility.

Don’t

  • Avoid placing critical content behind a drawer without a clear trigger.
  • Don’t overload with unrelated functionality inside a single drawer.
  • Don’t rely solely on click outside or ESC; always provide an explicit close mechanism.