MD3 React

Bottom sheet

A modal surface anchored to the bottom edge, dismissed by drag or scrim.
import {
  BottomSheet,
  BottomSheetTrigger,
  BottomSheetContent,
} from "@brijbyte/md3-react/bottom-sheet";
@import "@brijbyte/md3-react/bottom-sheet.css";

Bottom sheets bring in a surface anchored to the bottom edge for a focused task — picking an option, confirming an action, showing supplementary detail — without leaving the page behind a full navigation. This is the modal variant: a scrim dims the page, focus is trapped inside, and the sheet dismisses by dragging it down, tapping the scrim, or pressing Escape. BottomSheet wraps Base UI's Drawer, so a swipe-down gesture works out of the box:

<BottomSheet>
  <BottomSheetTrigger render={<Button variant="filled" />}>Open sheet</BottomSheetTrigger>
  <BottomSheetContent>
    <Typography variant="title-large">Add to playlist</Typography>
  </BottomSheetContent>
</BottomSheet>

Basic

A minimal sheet: a trigger, a drag handle rendered by default above the content, and whatever you put inside. Pass dragHandle={false} to BottomSheetContent to omit the handle, or a node to replace it.

With header and actions

Give the sheet an accessible name with BottomSheetTitle, and a BottomSheetClose for users who'd rather tap a button than drag or hit Escape — it renders whatever control you pass it (an IconButton here) and closes the sheet on click in addition to running its own onClick.

Content patterns

Bottom sheets are a plain container — what goes inside is up to you. A few common shapes, straight off the MD3 guidelines page:

Snap points

Pass snapPoints to size the sheet against fractions of the viewport height instead of its content — [0.4, 1] gives a half-open "peek" state and a fully expanded one, matching Compose's PartiallyExpanded/Expanded model. Dragging past a point's threshold or with enough velocity snaps to the next one; dragging down past the lowest point dismisses the sheet.

Standard (non-modal)

Pass variant="standard" for a sheet that coexists with the page instead of blocking it — no scrim, no focus trap, no scroll lock, and the rest of the page stays interactive around it. Use it for a persistent utility like a mini player that should stay put while people keep browsing, rather than a one-off task that needs their full attention:

<BottomSheet variant="standard" open>
  <BottomSheetContent dragHandle={false}>{/* ... */}</BottomSheetContent>
</BottomSheet>
Albums

Accessibility

The sheet traps focus and moves it in on open (to the first tabbable element, or the popup itself if there isn't one) and back to the trigger on close — no extra wiring needed. Give it an accessible name with BottomSheetTitle, or an aria-label on BottomSheetContent if a visible title doesn't fit the design. Escape and scrim clicks both dismiss the sheet; a BottomSheetClose button gives pointer and screen-reader users an explicit dismiss action too.