Sheets
Sheets show supplementary content and actions anchored to the bottom or the side of the window.
<md-gb-button id="open-actions">Show actions</md-gb-button>
<md-gb-bottom-sheet id="actions" modal label="File actions">
<md-gb-list>
<md-gb-list-item>Share</md-gb-list-item>
<md-gb-list-item>Get link</md-gb-list-item>
<md-gb-list-item>Make a copy</md-gb-list-item>
</md-gb-list>
</md-gb-bottom-sheet>document.querySelector('#open-actions').addEventListener('click', () => {
document.querySelector('#actions').show();
});Install with shadcn/ui: npx shadcn@latest add https://material-web.dev/3.0/r/md-sheet.json (setup)
Usage guidelines
Link to “Usage guidelines”- Secondary content. Sheets hold extra content and actions, not the main content of the app.
- Match the window size. Use a bottom sheet in compact and medium windows and a side sheet in wider ones.
- Standard or modal. A standard sheet sits beside the content so people can keep using it. A modal sheet blocks the page under a scrim until it is closed.
Anatomy
Link to “Anatomy”A bottom sheet has a container and an optional drag handle. A side sheet adds a headline, a close button and actions.
<md-gb-button id="open-bottom">Bottom sheet</md-gb-button>
<md-gb-button id="open-side">Side sheet</md-gb-button>
<md-gb-bottom-sheet id="bottom" modal label="Share">
<p>Share this photo with friends.</p>
</md-gb-bottom-sheet>
<md-gb-side-sheet id="side" modal>
<span slot="headline">Filters</span>
<p>Narrow the results by date or author.</p>
<md-gb-button slot="actions">Apply</md-gb-button>
</md-gb-side-sheet>document.querySelector('#open-bottom').addEventListener('click', () => {
document.querySelector('#bottom').show();
});
document.querySelector('#open-side').addEventListener('click', () => {
document.querySelector('#side').show();
});Examples
Link to “Examples”Bottom sheets
Link to “Bottom sheets”A bottom sheet rests at a partial height and expands when dragged or when its handle is activated. Without modal it is a standard sheet with no scrim. Set state="expanded" to open it at full height.
<md-gb-button id="open-expanded">Show details</md-gb-button>
<md-gb-bottom-sheet id="expanded" modal state="expanded" label="Photo details">
<p>Taken on June 3 in Lisbon.</p>
</md-gb-bottom-sheet>document.querySelector('#open-expanded').addEventListener('click', () => {
document.querySelector('#expanded').show();
});Without a drag handle
Link to “Without a drag handle”Add hide-drag-handle to remove the handle and dragging. Add skip-partially-expanded for a sheet that has no partial height.
<md-gb-button id="open-plain">Show options</md-gb-button>
<md-gb-bottom-sheet id="plain" modal hide-drag-handle label="Sort options">
<p>Sort by name, date, or size.</p>
</md-gb-bottom-sheet>document.querySelector('#open-plain').addEventListener('click', () => {
document.querySelector('#plain').show();
});Side sheets
Link to “Side sheets”A side sheet has a headline, a close button and an actions slot. Add divider to separate the actions, and detached to float the sheet with margins.
<md-gb-button id="open-filters">Filters</md-gb-button>
<md-gb-side-sheet id="filters" modal headline="Filters">
<p>Narrow the results by date or author.</p>
<md-gb-button slot="actions">Save</md-gb-button>
<md-gb-button slot="actions" color="outlined">Cancel</md-gb-button>
</md-gb-side-sheet>document.querySelector('#open-filters').addEventListener('click', () => {
document.querySelector('#filters').show();
});Back button
Link to “Back button”Set has-back-button on a side sheet to let people go back to an earlier region. The sheet fires back when it is pressed.
<md-gb-button id="open-detail">Details</md-gb-button>
<md-gb-side-sheet id="detail" modal has-back-button headline="Details">
<p>Created by Ada on May 2.</p>
</md-gb-side-sheet>document.querySelector('#open-detail').addEventListener('click', () => {
document.querySelector('#detail').show();
});Accessibility
Link to “Accessibility”- A modal sheet is a
<dialog>: focus moves into it, stays inside, and returns to the opener on close. Escape and a click on the scrim close it. - Name a bottom sheet with
label. A side sheet is named by itsheadline, or bylabelwhen it has none. - The drag handle is a button, so keyboard users can expand and collapse the sheet. Localize
drag-handle-label,close-labelandback-label.
Compatibility
Link to “Compatibility”Material Design 30 uncovered50% tokens
163 of 299 buildable spec units are tested, 6 are excluded with a written reason and 0 are uncovered (the target is 0). 20 of 40 token declarations match the spec (50%), 2 differ on purpose or are being fixed, and 18 have no spec token.
bottom-sheets on m3.material.io (opens in a new tab) side-sheets on m3.material.io (opens in a new tab) How compliance is measured
BaselineWidely availableChrome 124Edge 124Firefox 125Safari 17.4
The component’s own CSS and JavaScript rely only on web platform features that are Baseline widely available: it works in Chrome 124, Edge 124, Firefox 125, Safari 17.4 and later.
Newer features it uses where the browser has them (progressive enhancements):
- @starting-style (opens in a new tab) Newly available degrades safely where it is missing
- Cursor styles (opens in a new tab) Limited availability degrades safely where it is missing
- overscroll-behavior (opens in a new tab) Limited availability degrades safely where it is missing
- scrollbar-color (opens in a new tab) Newly available degrades safely where it is missing
- scrollbar-gutter (opens in a new tab) Newly available degrades safely where it is missing
- scrollbar-width (opens in a new tab) Newly available degrades safely where it is missing
- user-select (opens in a new tab) Limited availability used inside an
@supportsguard
Browser support Learn more about Baseline (opens in a new tab)
WAI-ARIAaxe and ARIA 1.3 passButtonDialog (Modal)
Roles the component renders: button (opens in a new tab), dialog (opens in a new tab).
Follows the WAI-ARIA Authoring Practices: Button (opens in a new tab), Dialog (Modal) (opens in a new tab).
4 rendered states run through axe-core and the WAI-ARIA 1.3 role and attribute rules in a real browser, with no known gaps.
WAI-ARIA 1.3 (opens in a new tab) ARIA Authoring Practices (opens in a new tab) Accessibility
Lighthouse95 · 100 · 100 · 100
Performance Accessibility Best practices SEO
Audits under 90:
- Largest Contentful Paint
- Largest Contentful Paint element
- Eliminate render-blocking resources
- Minify JavaScript
- Reduce unused CSS
- Reduce unused JavaScript
- Enable text compression
- Network dependency tree
- Render blocking requests
Lighthouse 12.8.2 (desktop, 2026-11-08) on the component alone: its first example on a page of its own, without this site's shell. The modules are the development build (not bundled or minified), so the performance score is indicative.
API reference
Link to “API reference”<md-gb-bottom-sheet>
Link to “<md-gb-bottom-sheet>”A Material Design bottom sheet.
Properties
Link to “Properties”| Property | Attribute | Type | Default |
|---|---|---|---|
closeLabelAccessible label of the close icon button of a full-screen sheet. |
close-label |
string |
'Close' |
collapseLabelAccessible label of the collapse icon button of a full-screen sheet. |
collapse-label |
string |
'Collapse' |
dragHandleLabelAccessible label of the drag handle button. |
drag-handle-label |
string |
'Drag handle' |
hideDragHandleWhether to hide the drag handle (which also disables dragging). |
hide-drag-handle |
boolean |
false |
labelAccessible label of the sheet dialog. |
label |
string |
'Bottom sheet' |
modalWhether the sheet is modal: shown above a scrim, blocking the rest of the page, and closed by Escape or a scrim click. |
modal |
boolean |
false |
openWhether the sheet is open. Setting it calls show() or close(). |
open |
boolean |
|
quickWhether to skip the opening and closing motion. |
quick |
boolean |
false |
skipPartiallyExpandedWhether the sheet has no partially expanded height: it opens expanded and the drag handle closes it. |
skip-partially-expanded |
boolean |
false |
stateThe resting height while open: partially-expanded or expanded. Updated when the user drags or activates the drag handle. |
state |
BottomSheetState |
BOTTOM_SHEET_STATES.partiallyExpanded |
Slots
Link to “Slots”| Slot | Description |
|---|---|
| default | The sheet content. It scrolls when taller than the sheet. |
Events
Link to “Events”| Event | Description |
|---|---|
closeCustomEvent<{reason: string}> |
Fired when the sheet begins closing. Cancelable; canceling keeps it open. |
closedCustomEvent<{reason: string}> |
Fired after the closing motion. |
openEvent |
Fired when the sheet begins opening. Cancelable. |
openedEvent |
Fired after the opening motion. |
state-changeEvent |
Fired when the user moves the sheet to another height (state). |
Methods
Link to “Methods”| Method | Description |
|---|---|
close(reason?: string) => Promise<void> |
Closes the sheet. Resolves after the closing motion. |
expand() => void |
Expands the sheet to its full height. |
handleBack() => Promise<void> |
Handles a back request (the Android back gesture or button, which a modal sheet receives through its dialog): plays the predictive back motion and closes the sheet with reason back. If the close event is canceled, the sheet settles back. Resolves after the closing motion. Call it for an in-app back control that should behave like the system back. |
partialExpand() => void |
Moves the sheet to its partially expanded height, when it has one. |
render() => TemplateResult<1> |
Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's ChildPart - typically a TemplateResult. Setting properties inside this method will not trigger the element to update. |
show() => Promise<void> |
Opens the sheet. Resolves after the opening motion. |
CSS parts
Link to “CSS parts”| Part | Description |
|---|---|
::part(container) |
The sheet container. |
::part(content) |
The container of the default slot. |
::part(dialog) |
The <dialog> holding the sheet; its ::backdrop is the scrim. |
::part(drag-handle) |
The drag handle button. |
CSS custom properties
Link to “CSS custom properties”| Property | Description |
|---|---|
--container-color |
Container color. |
--container-elevation |
Container box shadow. |
--container-shape |
Top corner radius. |
--drag-handle-color |
Drag handle color. |
--drag-handle-height |
Drag handle height. |
--drag-handle-padding-block |
Space above and below the drag handle. |
--drag-handle-width |
Drag handle width. |
--max-width |
Maximum container width. |
--partially-expanded-height |
Maximum visible height of a partially expanded modal sheet. |
--peek-height |
Visible height of a partially expanded standard sheet. |
--scrim-color |
Scrim color of a modal sheet. |
--scrim-opacity |
Scrim opacity of a modal sheet. |
--top-margin |
Minimum space above the expanded sheet. |
--wide-margin |
Top and side margins when the sheet is wider than its max width. |
<md-gb-side-sheet>
Link to “<md-gb-side-sheet>”A Material Design side sheet.
Properties
Link to “Properties”| Property | Attribute | Type | Default |
|---|---|---|---|
backLabelAccessible label of the back icon button. |
back-label |
string |
'Back' |
closeLabelAccessible label of the close icon button. |
close-label |
string |
'Close' |
detachedWhether the sheet floats inset from the window edges with rounded corners, instead of touching them. |
detached |
boolean |
false |
dividerWhether to draw dividers: along the inline start edge of a standard docked sheet, and above the actions. |
divider |
boolean |
false |
gesturesDisabledWhether to turn off swipe to dismiss on a modal sheet. |
gestures-disabled |
boolean |
false |
hasBackButtonWhether to show the back icon button before the headline. |
has-back-button |
boolean |
false |
headlineThe headline text. |
headline |
string |
'' |
hideCloseButtonWhether to hide the close icon button. Material requires a close affordance in every side sheet; provide another one when hiding it. |
hide-close-button |
boolean |
false |
labelAccessible label of the sheet dialog, used when it has no headline. |
label |
string |
'' |
modalWhether the sheet is modal: shown above a scrim, blocking the rest of the page, and closed by Escape or a scrim click. |
modal |
boolean |
false |
openWhether the sheet is open. Setting it calls show() or close(). |
open |
boolean |
|
quickWhether to skip the opening and closing motion. |
quick |
boolean |
false |
Slots
Link to “Slots”| Slot | Description |
|---|---|
| default | The sheet content. It scrolls vertically when taller than the sheet. |
actions |
Action buttons at the bottom of the sheet, such as Save and Cancel. |
headline |
Headline content; replaces the headline text. |
Events
Link to “Events”| Event | Description |
|---|---|
backEvent |
Fired when the back icon button is activated. |
closeCustomEvent<{reason: string}> |
Fired when the sheet begins closing. Cancelable; canceling keeps it open. |
closedCustomEvent<{reason: string}> |
Fired after the closing motion. |
openEvent |
Fired when the sheet begins opening. Cancelable. |
openedEvent |
Fired after the opening motion. |
Methods
Link to “Methods”| Method | Description |
|---|---|
close(reason?: string) => Promise<void> |
Closes the sheet. Resolves after the closing motion. |
handleBack() => Promise<void> |
Handles a back request (the Android back gesture or button, which a modal sheet receives through its dialog): plays the predictive back motion and closes the sheet with reason back. If the close event is canceled, the sheet settles back. Resolves after the closing motion. Call it for an in-app back control that should behave like the system back. |
render() => TemplateResult<1> |
Invoked on each update to perform rendering tasks. This method may return any value renderable by lit-html's ChildPart - typically a TemplateResult. Setting properties inside this method will not trigger the element to update. |
show() => Promise<void> |
Opens the sheet. Resolves after the opening motion. |
CSS parts
Link to “CSS parts”| Part | Description |
|---|---|
::part(actions) |
The container of the actions slot. |
::part(container) |
The sheet container. |
::part(content) |
The container of the default slot. |
::part(dialog) |
The <dialog> holding the sheet; its ::backdrop is the scrim. |
::part(header) |
The header row. |
::part(headline) |
The headline. |
CSS custom properties
Link to “CSS custom properties”| Property | Description |
|---|---|
--actions-height |
Actions row minimum height. |
--actions-padding-block-end |
Space below the actions. |
--actions-padding-block-start |
Space above the actions. |
--container-color |
Container color. |
--container-elevation |
Container box shadow. |
--container-height |
Height of a standard sheet. |
--container-margin |
Inset from the window edges (16px when detached). |
--container-shape |
Corner radius (the inline start corners of a docked modal sheet; every corner of a detached sheet). |
--container-width |
Container width (capped at --max-width). |
--divider-color |
Divider color. |
--header-gap |
Space between header elements. |
--header-height |
Header minimum height. |
--headline |
Headline typography. |
--headline-axes |
Headline font variation settings. |
--headline-color |
Headline color. |
--headline-tracking |
Headline letter spacing. |
--icon-padding-inline |
Header padding next to the back or close icon button. |
--max-width |
Maximum container width. |
--padding-inline |
Start and end padding. |
--scrim-color |
Scrim color of a modal sheet. |
--scrim-opacity |
Scrim opacity of a modal sheet. |