Bottom sheets

Bottom sheets (COMPONENT_SPEC §30) hold supplementary content anchored to the bottom of the screen. The modal bottom sheet is Compose's ModalBottomSheet: a dialog over a 32% scrim that opens partially expanded (half the window, or the whole sheet when it is shorter) and can be dragged up to expanded or down to dismiss. The standard bottom sheet is Compose's BottomSheet: the same sheet fixed to the bottom of its container, alongside the page content, with an optional peek height (Compose's BottomSheetScaffold; the scaffold's own layout waits for the Scaffold primitive).

The sheet takes surface-container-low with extra-large top corners, is at most 640dp wide and centered, and sits flush with the bottom with no margins (Compose; m3.material.io shows 72dp / 56dp margins). It shows and expands on the default spatial spring and hides on the fast effects spring. A drag released 56dp from where it started, or flung at 125dp/s, moves to the next value; the settle starts at the release velocity. The drag handle is a button named "Drag handle" with a built-in tooltip: Enter or Space expands a partially expanded sheet and dismisses an expanded one; ArrowUp and ArrowDown expand and collapse it (announced with aria-keyshortcuts; the web's channel for Compose's expand, collapse and dismiss accessibility actions). Escape partially expands an expanded sheet, else hides it. When keyboard focus reaches something a partially expanded sheet hides below its visible part, such as the button in the peek sheet below, the sheet expands so the focused element shows (without animating under reduced motion).

<m3e-bottom-sheet variant="modal">: show() (or setting open) opens it partially expanded (skip-partially-expanded: expanded); the child nodes are the content. open reflects whether value is not hidden; value-change ({ value }) and then, when the sheet shows or hides, open-change ({ open }) are cancelable when the sheet asks. The page is inert while it is open, Tab stays inside and focus returns to the opener when it hides. The first one is Compose's ModalBottomSheetSample.

value-change and open-change bubble in 1.x, like every state event: a listener on an element also hears the same event from an element nested inside it, such as a tooltip in a dialog or a time picker in a tab panel. Check the target first: if (e.target !== host) return;. DECISIONS D25 proposes that 2.0 stop bubbling state events; item events such as action keep bubbling.

  • Item 0
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
  • Item 6
  • Item 7
  • Item 8
  • Item 9
  • Item 10
  • Item 11
  • Item 12
  • Item 13
  • Item 14
  • Item 15
  • Item 16
  • Item 17
  • Item 18
  • Item 19
  • Item 20
  • Item 21
  • Item 22
  • Item 23
  • Item 24
  • Item 0
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
  • Item 6
  • Item 7
  • Item 8
  • Item 9
  • Item 10
  • Item 11
  • Item 12
  • Item 13
  • Item 14
  • Item 15
  • Item 16
  • Item 17
  • Item 18
  • Item 19
  • Item 20
  • Item 21
  • Item 22
  • Item 23
  • Item 24
  • Item 0
  • Item 1
  • Item 2

Standard bottom sheet (element)

<m3e-bottom-sheet value="partially-expanded"> in a positioned container (position: relative): the sheet covers the bottom of the container without a scrim, and the content behind it stays usable. Drag it, use its handle, or Escape in it.

Page content

  • Item 0
  • Item 1
  • Item 2
  • Item 3
  • Item 4
  • Item 5
  • Item 6
  • Item 7
  • Item 8
  • Item 9
  • Item 10
  • Item 11

Peek height

peek-height="128" (Compose's SimpleBottomSheetScaffoldSample): partially expanded, the sheet shows its top 128dp; skip-hidden-state keeps it from hiding (the scaffold's default), so its handle collapses an expanded sheet instead.

Scaffold Content

Swipe up to expand sheet

Sheet content

React

<ModalBottomSheet isOpen onOpenChange skipPartiallyExpanded> and <BottomSheet value onValueChange peekHeight skipHiddenState> render the same DOM as the element. onOpenChange(false) reports the handle, a drag, Escape and the scrim (Compose's onDismissRequest).

Sources

androidx Compose Material3 1.5.0-beta01 (19991f2c): SheetBottomTokens.kt as read by SheetDefaults.kt (BottomSheetDefaults L512–589: shape, color and the 32 × 4dp drag handle; SheetMaxWidth L536) and BottomSheet.kt (BottomSheetImpl, anchors L293–328), ModalBottomSheet.kt (the scrim, L143–157), BottomSheetScaffold.kt, Scrim.kt (L50–79), ComposeMaterial3Flags.kt and ModalBottomSheet.android.kt; foundation gestures/AnchoredDraggable.kt (L1485–1514, L1716–1790) and gestures/snapping/SnapFlingBehavior.kt; material3 res strings.xml L79–87 and compose/ui res strings.xml L46; the values Compose renders that are not tokens in components/bottom-sheet-defaults.css (lines in PARITY.md). BottomSheetSamples.kt for the examples; the device tests AnchoredDraggableStateTest.kt, BottomSheetTest.kt, ModalBottomSheetTest.kt and SheetStateTest.kt are ported as reference tests.

m3.material.io Bottom sheets (Specs, Accessibility; token DB md.comp.sheet.bottom). SOURCES register #47 and #77 (no margins, as Compose; owner decision M9 #12); DECISIONS D20 (9) for the handle's ArrowUp / ArrowDown (announced with aria-keyshortcuts) and D21 (3): focus that enters content below a partially expanded sheet expands it (WCAG 2.4.11).