docs / core / drawer

Drawer

the same anatomy as Dialog, pinned to an edge instead of centered. a panel slides in from any side; a bottom sheet is just side="bottom".

intensity · recedesrsc · client

provenance

shaped from personal-website · sisu-plus

layer

core / primitives

intensity

recedes · safe anywhere, including dense surfaces

composition

settings panels, widget libraries, filters that keep the page visible behind the scrimthe slide-up sheet is this primitive with side="bottom"not navigation chrome. a persistent sidebar is layout, not a Drawernever two edges open at once

a11y

role="dialog" named by its Title · focus is trapped, Escape closes · Drawer.Close keeps a 44px minimum targetjest-axe

dependencies

@base-ui/react · Card from the same package
live demo · try it out
customize
sidewhich edge it pins to
sizeinline size, or block size on horizontal edges
surfacehow the panel sits above the scrim
highlightwash, inner edge, or glow ring
titlethe heading that names the dialog
descriptionsupporting line under the title
usagecopy
import { Button } from "@usva-ui/react/primitives/button";
import { Drawer } from "@usva-ui/react/primitives/drawer";

<Drawer>
  <Drawer.Trigger render={<Button>Open</Button>} />
  <Drawer.Content>
    <Drawer.Title>Widget library</Drawer.Title>
    <Drawer.Description>Drag a widget onto the grid to add it.</Drawer.Description>
    <Drawer.Close render={<Button variant="ghost">Done</Button>} />
  </Drawer.Content>
</Drawer>

props

proptypedefaultnotes
side"top" | "right" | "bottom" | "left""right"which edge the panel is pinned to.
size"sm" | "md" | "lg""md"inline size on the vertical edges, block size on the horizontal ones.
surface"elevated" | "flat" | "glass""elevated"how the panel sits above the scrim. shared with Card and Dialog.
highlight"none" | "wash" | "edge" | "ring""none"accent treatment on Drawer.Content: a wash, a top edge hairline, or a glow ring. the same vocabulary as Card and Dialog.
backdropClassNamestringextra classes on the scrim, on Drawer.Content.

get it

bun add @usva-ui/reactcopy
usagecopy
import { Button } from "@usva-ui/react/primitives/button";
import { Drawer } from "@usva-ui/react/primitives/drawer";

<Drawer>
  <Drawer.Trigger render={<Button>Edit layout</Button>} />
  <Drawer.Content side="right" size="md">
    <Drawer.Title>Widget library</Drawer.Title>
    <Drawer.Description>Drag a widget onto the grid.</Drawer.Description>
    <Drawer.Close render={<Button variant="ghost">Done</Button>} />
  </Drawer.Content>
</Drawer>