Drawer

Modal side panel with open state, role="dialog", side placement (data-side), and the same modal overlay chrome as Dialog: portal mounting, body scroll lock, focus trap, and Escape dismiss.

PreviewModal side panel

Usage

tsx
import { useState } from "react";
import { Drawer } from "@sometic/react/overlay";

export function Example() {
    const [open, setOpen] = useState(false);
    return (
        <>
            <button type="button" onClick={() => setOpen(true)}>
                Open
            </button>
            <Drawer open={open} onOpenChange={setOpen} side="right">
                Account settings
            </Drawer>
        </>
    );
}
tsx
import { useState } from "react";
import { Drawer } from "@sometic/react/overlay";

export function Example(): JSX.Element {
    const [open, setOpen] = useState(false);
    return (
        <>
            <button type="button" onClick={() => setOpen(true)}>
                Open
            </button>
            <Drawer open={open} onOpenChange={setOpen} side="right">
                Account settings
            </Drawer>
        </>
    );
}
js
import { createDrawerController, resolveDrawer } from "@sometic/dom/drawer";

const panel = document.querySelector("#drawer");
const controller = createDrawerController({
    defaultOpen: false,
    side: "right",
    getContent: () => panel,
    onOpenChange: (open) => {
        const view = resolveDrawer({ open, side: "right" });
        for (const [key, value] of Object.entries(view.attributes)) {
            panel.setAttribute(key, value);
        }
        panel.hidden = !open;
    },
});

document.querySelector("#open-drawer").addEventListener("click", () => {
    controller.setOpen(true);
});

Custom element not shipped in this beta; use the DOM controller.

Custom element not shipped for Drawer. Vanilla uses @sometic/dom/drawer. React + DOM are primary; no Vue Drawer component.

How it works

  1. Resolve (resolveDrawer): pure view model with role="dialog", data-side, data-state, and aria-modal when open.
  2. Controller (createDrawerController): wraps createOverlayController({ modal: true }) like Dialog.
  3. React adapter: syncs open / defaultOpen / side, disposes on unmount, returns null when closed.

Anatomy

Partdata-slot / attrsRole
Panelroot, data-sideDialog surface anchored to a side
TriggerApp-owned opener

Props / attributes

React DrawerProps

Extends HTMLAttributes<HTMLDivElement>. Remaining native div attrs are forwarded to the panel when open.

PropTypeDefaultDescription
openbooleanControlled open
defaultOpenbooleanfalseUncontrolled initial
onOpenChange(open: boolean) => voidOpen changes including Escape
side"left" | "right" | "top" | "bottom""right"Placement side
childrenReactNodePanel content
Native attrsremaining div HTML attrsForwarded to the panel

Engine resolve also supports titleId, descriptionId, disabled, and styling hooks (unstyled, classes, styles, cssVariables, …) when calling resolveDrawer / createDrawerController directly.

Vue

No Vue Drawer component. Use React or @sometic/dom/drawer.

Custom element

CE not shipped. Use Vanilla DOM controller or React.

Events / callbacks

SurfaceEventPayload
ReactonOpenChangeboolean
Vue
Custom element
DOM controlleronOpenChangeboolean

Controlled vs uncontrolled

  • Controlled: pass open and update from onOpenChange (including Escape).
  • Uncontrolled: omit open, use defaultOpen.

Accessibility

  • Modal path: focus trap, scroll lock, Escape dismiss, aria-modal="true".
  • Name the panel with titleId / aria-label (engine options or native attrs).
  • Prefer one open drawer at a time.

Styling

Target [data-side], [data-state="open"], [role="dialog"]. Unstyled by default.

When to use / When not

Use for side settings panels and secondary flows that still need modal chrome.

Do not use for centered confirms (Dialog) or non-modal menus (Menu).

FAQ

Same chrome as Dialog? Yes. Modal overlay controller.

Outside click? Does not dismiss (modal).

Is there an sometic-drawer? No. CE not shipped.

Vue adapter? Not shipped. React + DOM primary.

Does React forward native attrs? Yes, onto the panel when open.

SSR? Create controllers only in the browser.