MDC

Side Sheet

Demo

Actions

Code
<mdc-side-sheet id="ss-actions-with" variant="modal">
    <span slot="headline">With actions</span>
    <p>Body content.</p>
    <mdc-button slot="actions" onclick="this.closest('mdc-side-sheet').close('save')"><span>Save</span></mdc-button>
    <mdc-button slot="actions" variant="outlined" onclick="this.closest('mdc-side-sheet').close('cancel')"><span>Cancel</span></mdc-button>
</mdc-side-sheet>

<mdc-side-sheet id="ss-actions-without" variant="modal">
    <span slot="headline">Without actions</span>
    <p>Body content. The actions footer is hidden.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-actions-with').show()"><span>With actions</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-actions-without').show()"><span>Without actions</span></mdc-button>

Cancelable

Code
<mdc-side-sheet id="ss-cancelable-on" variant="modal" cancelable>
    <span slot="headline">Cancelable (default)</span>
    <p>Press Esc or click the scrim to close.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-cancelable-off" variant="modal" cancelable="false">
    <span slot="headline">Not cancelable</span>
    <p>Esc and scrim taps are no-ops; only the close button dismisses.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-cancelable-on').show()"><span>Cancelable</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-cancelable-off').show()"><span>Not cancelable</span></mdc-button>

Draggable

Code
<mdc-side-sheet id="ss-draggable-on" variant="modal" draggable>
    <span slot="headline">Draggable (default)</span>
    <p>Drag the top handle: push it towards the docked edge to dismiss, or pull it across the viewport midline to relocate to the other side.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-draggable-off" variant="modal" draggable="false">
    <span slot="headline">Not draggable</span>
    <p>Handle-drag gestures are disabled.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-draggable-on').show()"><span>Draggable</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-draggable-off').show()"><span>Not draggable</span></mdc-button>

Handle Mode

Code
<mdc-side-sheet id="ss-handle-open-only" variant="standard" handle-mode="open-only" draggable>
    <span slot="headline">Open-only (default)</span>
    <p>The top handle exists on the open sheet only; a closed sheet exposes nothing.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-handle-open-only').show()"><span>Open</span></mdc-button>

Headline

Code
<mdc-side-sheet id="ss-headline-with" variant="modal">
    <span slot="headline">Headline text</span>
    <p>Body content.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-headline-without" variant="modal">
    <p>No headline; the title row still renders with an empty leading slot.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-headline-with').show()"><span>With headline</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-headline-without').show()"><span>Without headline</span></mdc-button>

Max Width

Code
<mdc-side-sheet id="ss-max-width-280" variant="modal" max-width="280"
    style="--mdc-side-sheet-enabled-container-width: 640px">
    <span slot="headline">640px token, 280px ceiling</span>
    <p>max-width clamps the container-width token.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-max-width-400" variant="modal" max-width="400"
    style="--mdc-side-sheet-enabled-container-width: 640px">
    <span slot="headline">640px token, 400px ceiling</span>
    <p>The MD3 spec width, enforced as a ceiling.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-max-width-none" variant="modal"
    style="--mdc-side-sheet-enabled-container-width: 640px">
    <span slot="headline">640px token, no ceiling</span>
    <p>Without max-width the token drives the width outright.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-max-width-280').show()"><span>280px ceiling</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-max-width-400').show()"><span>400px ceiling</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-max-width-none').show()"><span>No ceiling</span></mdc-button>

No Focus Trap

Code
<mdc-side-sheet id="ss-focus-trap-off" variant="standard" no-focus-trap>
    <span slot="headline">No focus trap</span>
    <p>Tab moves out of the sheet and on through the page.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-focus-trap-on" variant="standard">
    <span slot="headline">Traps focus (default)</span>
    <p>Tab wraps around inside the sheet.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-focus-trap-off').show()"><span>No focus trap</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-focus-trap-on').show()"><span>Focus trap</span></mdc-button>

Open

Code
<mdc-side-sheet id="ss-open-imperative" variant="modal">
    <span slot="headline">Opened via show()</span>
    <p>Imperative: <code>sheet.show()</code> sets <code>open</code> and promotes the dialog to the top layer.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-open-declarative" variant="modal" open>
    <span slot="headline">Opened via the open property</span>
    <p>Declarative: setting <code>open = true</code> (or the <code>open</code> attribute) drives the same lifecycle.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-open-imperative').show()"><span>show()</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-open-declarative').show()"><span>show() declarative</span></mdc-button>

Peek

Code
<mdc-side-sheet id="ss-handle-peek" variant="standard" handle-mode="peek" draggable>
    <span slot="headline">Peek</span>
    <p>A closed sheet keeps only a vertical grip docked at the edge — drag it to pull the sheet out or push it back. Drag it across the viewport midline to relocate the sheet to the opposite edge.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-handle-peek').show()"><span>Open</span></mdc-button>

Position

Code
<mdc-side-sheet id="ss-position-right" variant="modal" position="right">
    <span slot="headline">Right (default)</span>
    <p>Docked to the viewport's right edge.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-position-left" variant="modal" position="left">
    <span slot="headline">Left</span>
    <p>Docked to the viewport's left edge.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-position-right').show()"><span>Right</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-position-left').show()"><span>Left</span></mdc-button>

Quick

Code
<mdc-side-sheet id="ss-quick-on" variant="modal" quick>
    <span slot="headline">Quick Mode</span>
    <p>Skips entrance and exit animations.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-quick-on').show()"><span>Open quick</span></mdc-button>

Show Back Button

Code
<mdc-side-sheet id="ss-back-on" variant="modal" show-back-button>
    <svg slot="headline-icon" viewBox="0 0 24 24" width="24" height="24"
        fill="currentColor" aria-hidden="true">
        <path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/>
    </svg>
    <span slot="headline">With back button</span>
    <p>The back icon-button emits <code>side-sheet-action</code> with <code>source: 'back'</code>.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-back-off" variant="modal">
    <span slot="headline">Without back button</span>
    <p>Body content.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-back-on').show()"><span>With back button</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-back-off').show()"><span>Without back button</span></mdc-button>

Variant

Code
<mdc-side-sheet id="ss-variant-standard" variant="standard">
    <span slot="headline">Standard</span>
    <p>Co-exists with the page: no scrim, and the rest of the UI stays interactive.</p>
</mdc-side-sheet>

<mdc-side-sheet id="ss-variant-modal" variant="modal">
    <span slot="headline">Modal</span>
    <p>Blocks the page behind a scrim until dismissed.</p>
</mdc-side-sheet>

<mdc-button onclick="this.getRootNode().querySelector('#ss-variant-standard').show()"><span>Standard</span></mdc-button>
<mdc-button onclick="this.getRootNode().querySelector('#ss-variant-modal').show()"><span>Modal</span></mdc-button>