|Kit

Drawer

Edge-anchored panel on Ark UI's Drawer machine — swipe-to-dismiss, snap points and a drag grabber, with an RTL-aware placement prop.

The Drawer is an edge-anchored panel built on Ark UI's Drawer state machine — so it ships swipe-to-dismiss, snap points and a drag grabber out of the box. The kit layers on an RTL-aware placement prop (Ark has none): docking, sizing and the slide animation are pure CSS keyed on data-placement, so start/end flip automatically under dir="rtl".

import { Drawer } from '@42-central/ui-react/drawer';

<Drawer open={open} onOpenChange={setOpen} placement="end" title="Filters">
  <Text>Slides in from the inline-end edge.</Text>
</Drawer>

Placement

placement accepts the logical edges start / end / top / bottom. start and end resolve against text direction.

Code

<Drawer placement="start" … />
<Drawer placement="end" … />   // default
<Drawer placement="top" … />
<Drawer placement="bottom" … />

Sizes

Inline placements (start / end) size on width; block placements (top / bottom) size on height. Both read the size token (xs–xl).

Code

<Drawer placement="end" size="sm" … />
<Drawer placement="end" size="lg" … />

Grabber

Set withGrabber to show a draggable handle — useful for bottom sheets on touch devices, where the whole panel is swipe-dismissable.

Code

<Drawer placement="bottom" withGrabber title="Quick actions" … />

Composable parts

Like Modal, the high-level <Drawer> is backed by parts for full control:

<Drawer.Root open={open} onOpenChange={({ open }) => setOpen(open)} swipeDirection="end">
  <Drawer.Backdrop />
  <Drawer.Positioner data-placement="end">
    <Drawer.Content data-placement="end">
      <Drawer.Header>
        <Drawer.Title>Filters</Drawer.Title>
        <Drawer.CloseTrigger />
      </Drawer.Header>
      <Drawer.Body>…</Drawer.Body>
    </Drawer.Content>
  </Drawer.Positioner>
</Drawer.Root>

Drawer.Root, Drawer.Trigger, and Drawer.Context are raw Ark re-exports with no DOM node (or styling) of their own, so none take a testId. Drawer.Backdrop, Drawer.Title, Drawer.Description, Drawer.Grabber, Drawer.Header, Drawer.Body, and Drawer.Footer each take their own testId, landing on their own rendered element. Drawer.CloseTrigger's testId routes to the actual rendered close button — an inner ActionIcon, since CloseTrigger itself is asChild over it — the same pattern as Modal.CloseTrigger. See Testing.

API

Prop

Type

All other props (snapPoints, closeThreshold, modal, trapFocus, …) forward to Ark's Drawer.Root.

Accessibility

  • Same focus-trap, scroll-lock and focus-restore guarantees as Modal — Ark's Drawer machine is a dialog under the hood.
  • placement uses logical edges and CSS logical properties, so the panel and its slide animation mirror correctly under dir="rtl".
  • Swipe-to-dismiss is a progressive enhancement; keyboard and click paths work without it.

Changelog

v0.19.0
  • A translations prop for the close, dismiss, collapse/expand and region labels; <Notifications /> forwards its keys to every toast

    #331
v0.18.0
  • asChild is a compile error on Combobox.Control, Group, Content, Panel and Item, Drawer/Modal.Positioner, Drawer.Grabber, Popover.Content and Tooltip.Arrow

    #294
  • CloseTrigger asChild uses your element in place of the icon button, without the forced aria-label

    #288
v0.16.0
  • An outside click no longer dismisses the parent while a nested overlay is open

    #251
v0.9.0
  • --modal-z rises from 50 to 150, leaving room for the toast band below it

    #135
v0.4.0
  • Floating surfaces take a brand tint

    #41
v0.3.0
  • onClose fires alongside onOpenChange, as on Modal

    #34
v0.0.1
  • Modal and Drawer, controlled by open/onOpenChange; Drawer slides in from any edge

On this page