Skip to content
Component

Drawer

A panel that slides in from any edge and can be dragged back to dismiss. It spans its edge by default; variant='sheet' detaches it as an inset card.

All sides

side picks the edge. Each of these sets swipeDirection to match, so the panel can be dragged back towards the edge it came from.

  • Use side="bottom" as the mobile-first action sheet: same component, no separate Sheet needed
  • Add variant="sheet" for the detached card presentation - inset from every edge rather than spanning one

Bottom drawer

side='bottom' with swipeDirection='down' rises from the bottom edge, spans it, shows a drag handle, and can be flicked away. On a phone this is the shape most actions should take rather than a centred dialog.

  • swipeDirection must match the side - the root cannot see which side its content chose
  • The drag handle is rendered automatically for side='bottom'

Sheet variant

variant='sheet' detaches the panel from the edge: inset all round, rounded on every corner, width-capped, with the dimmed page still visible around it. Reach for it when the panel is a short, self-contained task - a share menu, a confirmation - rather than navigation or a long form.

  • Available on all four sides - the margin is what insets it, so a left or right sheet gets its height from the same rule

Detail panel

A right-side drawer used as a full record view alongside the page it was opened from - a long, scrollable panel rather than a short confirmation.

When to use

  • Secondary navigation or filters the user may want to keep referencing (site nav on mobile, a filters panel).
  • A cart, notification list, or detail panel that should slide in alongside the page rather than fully block it.
  • side="bottom" as a mobile-first "sheet" - actions, quick forms, or a picker triggered from a bottom bar.

When not to use

  • A task the user must complete or explicitly dismiss before continuing - use Dialog (or Dialog with mobileBehavior="sheet", which is the desktop-dialog/mobile-sheet combination Drawer doesn't do on its own).
  • Short, anchored content next to a trigger - use Popover instead of a full-height panel.

Keyboard

KeyAction
EscapeCloses the drawer and returns focus to the trigger.
Tab / Shift+TabCycles focus within the drawer only - focus is trapped while open.

Mobile behavior

  • side="left" / "right": full-height panel, width caps at calc(100vw - 3rem) so the page edge stays visible.
  • side="top" / "bottom": full-width panel, height caps at 85vh; side="bottom" is the standard mobile action-sheet pattern. variant="sheet" insets and caps it instead, on any side.
  • Adds the safe-area inset to the panel's own padding on side='bottom' (and the top inset on side='top'), so content clears the home indicator and notch.
  • A drag towards the swipeDirection edge moves the panel with the finger: a short drag springs back, a long or fast one dismisses.

Accessibility notes

  • Uses Base UI's Drawer primitive: role="dialog", focus trap, and scroll lock on the page behind it.
  • Drawer.Title is required for an accessible name - pass a visually-hidden one if the panel doesn't need a visible heading.

Common mistakes

  • Putting primary page navigation only in a Drawer on desktop - reserve Drawer navigation for mobile; use a persistent Sidebar on larger screens.
  • Skipping Drawer.Title - the panel then announces with no accessible name.
  • Stacking more than one Drawer open at once - close the first before opening a second, or use Popover for the secondary surface.

Known limitations

  • No built-in resizable width - dragging dismisses the panel, it does not resize it.

Related components

CriterionStatusNote
Keyboard supportSupportedEscape closes; Tab/Shift+Tab cycle within a focus trap.
Focus managementSupportedFocus enters the panel on open, returns to the trigger on close.
Screen reader labelsPartialDrawer.Title gives an accessible name; omitting it leaves the panel unlabeled.
Reduced motionSupportedprefers-reduced-motion: reduce zeroes all Fuji transition durations globally.
Reduced transparencySupportedprefers-reduced-transparency: reduce flattens Glass to opaque surfaces (portals included).
RTL layoutPartialLogical flex/grid gap works under dir="rtl"; directional chevrons are not yet mirrored.

API reference

Also accepts everything from React.ComponentPropsWithoutRef<typeof import("@base-ui/react/drawer").Drawer.Root>.

Drawer.Content props

hideCloseButtonfalse
boolean

Drops the built-in close button. Leave a way out - Escape alone is not enough for a pointer user.

side"right"
DrawerSide

Which edge the panel slides in from. Match `Drawer`'s `swipeDirection` to it.

variant"full"
DrawerVariant

`"full"` (default) spans the edge; `"sheet"` is a detached, inset card.

width"md"
DrawerWidth

Side-panel width: `"sm"` 16rem, `"md"` 20rem, `"lg"` 28rem, `"full"` viewport less 3rem. Default `"md"`. Capped at `calc(100vw - 3rem)`; ignored for `top`/`bottom`; `className` still wins.

Also accepts everything from React.ComponentPropsWithoutRef<typeof import("@base-ui/react/drawer").Drawer.Popup>.

Coding agents read this reference, with its examples, from the version your project has installed, through the Fuji UI MCP server. Set up your agent