Sheet
What a popup becomes on a phone: a bottom sheet, as every dialog is there. Select's list, a Menu, SearchSelect and DateRangePicker each stay their own Base UI part — keys, focus and all — and wear this sheet under sm, pinned to the screen's foot.
On a phone
The floating glass across the screen's foot, its top corners rounded, the page dimmed behind; rows grow to 44px, a thumb's size. A pick, a press outside or a drag down on its handle closes it. It stands on a phone's keyboard, so SearchSelect's search stays in view. Narrow this window, or open the catalog on a phone, and open a Select, Menu, SearchSelect or DateRangePicker to see it.
Settings
Sign out
// Inside a shared component's phone branch, Menu's for one:
const drag = useSheetDrag(() => actions.current?.close());
<Menu.Portal>
<Menu.Backdrop className={SHEET_BACKDROP} />
<Menu.Positioner className={SHEET_POSITIONER}>
<Menu.Popup {...drag.popup} className={POPUP_SHEET}>
<SheetHandle {...drag.handle} />
{children}
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>Guidelines
- A popup's phone branch, never a page's: features use Select, Menu, SearchSelect and DateRangePicker, which switch on their own (usePhone, under sm).
- A dialog's sheet is Base UI's Drawer instead (Dialog): this one keeps a popup's own keyboard and focus behaviour.
- It moves on the motion tokens (POPUP_SHEET_MOTION): up on duration-slow, down a step quicker, following the finger while it's dragged.
API
| Prop | Type | Default | Description |
|---|---|---|---|
| POPUP_SHEET | string | — | The popup's classes: the glass, the rounded top, capped below the screen (max-h-sheet), its motion. |
| SHEET_POSITIONER | string | — | Pins the positioner to the screen's foot over Base UI's placing, standing on the keyboard. |
| SHEET_BACKDROP | string | — | The page behind, dimmed and softly blurred. |
| useSheetDrag | (close: () => void) => { popup, handle } | — | Dragging it down by its handle: spread popup on the popup and handle on SheetHandle. |
| SheetHandle | pointer handlers | — | The bar, and a strip across the top wide enough for a thumb. Hidden from screen readers. |
| sheetLetsGo | (dy, height, ms) => boolean | — | Whether a drag lets go: a quarter of the way down, or a flick. |