md-side-sheet spec card
Identity · when to use / when NOT · decision cues · behavioural contract · do/don't · anti-patterns · full API. Paste into your agent when you're implementing with this component.
Supplementary content along the side of the screen. Standard (inline, sits beside your content) or modal (over a scrim), on either logical edge, with optional dividers, an actions row, a back affordance for nested flows, and its own density rung.
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-button id="ss-hero-btn" variant="filled" icon="filter_list">Show filters</md-button>
<md-side-sheet id="ss-hero" variant="modal" side="end" headline="Filters" top-divider bottom-divider>
<label><md-checkbox checked></md-checkbox> In stock</label>
<label><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="text">Reset</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
<script type="module">
var sheet = document.getElementById('ss-hero');
var btn = document.getElementById('ss-hero-btn');
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
document.querySelectorAll('[data-ss-hero-close]').forEach(function (b) {
b.addEventListener('mdClick', function () { sheet.close(); });
});
</script>// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { useEffect, useRef } from 'react';
import { MdButton, MdCheckbox, MdSideSheet } from '@awc-ui/react';
export function Demo() {
const sheetRef = useRef(null);
const btnRef = useRef(null);
useEffect(() => {
const sheet = sheetRef.current;
const btn = btnRef.current;
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
document.querySelectorAll('[data-ss-hero-close]').forEach(function (b) {
b.addEventListener('mdClick', function () { sheet.close(); });
});
}, []);
return (
<>
<MdButton id="ss-hero-btn" ref={btnRef} variant="filled" icon="filter_list">Show filters</MdButton>
<MdSideSheet id="ss-hero" ref={sheetRef} variant="modal" side="end" headline="Filters" topDivider bottom-divider>
<label><MdCheckbox checked></MdCheckbox> In stock</label>
<label><MdCheckbox></MdCheckbox> On sale</label>
<MdButton slot="actions" variant="text">Reset</MdButton>
<MdButton slot="actions" variant="filled">Apply</MdButton>
</MdSideSheet>
</>
);
}// Icons need the Material Symbols stylesheet in index.html — see Installation.
// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
// app.component.ts
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'app-demo',
templateUrl: './app.component.html',
})
export class DemoComponent implements AfterViewInit {
@ViewChild('sheet') sheetRef!: ElementRef;
@ViewChild('btn') btnRef!: ElementRef;
ngAfterViewInit() {
const sheet = this.sheetRef.nativeElement;
const btn = this.btnRef.nativeElement;
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
document.querySelectorAll('[data-ss-hero-close]').forEach(function (b) {
b.addEventListener('mdClick', function () { sheet.close(); });
});
}
}
<!-- app.component.html -->
<md-button id="ss-hero-btn" #btn variant="filled" icon="filter_list">Show filters</md-button>
<md-side-sheet id="ss-hero" #sheet variant="modal" side="end" headline="Filters" top-divider bottom-divider>
<label><md-checkbox checked></md-checkbox> In stock</label>
<label><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="text">Reset</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet><script setup>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { onMounted, ref } from 'vue';
import '@awc-ui/core/define';
const sheetRef = ref(null);
const btnRef = ref(null);
onMounted(() => {
const sheet = sheetRef.value;
const btn = btnRef.value;
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
document.querySelectorAll('[data-ss-hero-close]').forEach(function (b) {
b.addEventListener('mdClick', function () { sheet.close(); });
});
});
</script>
<template>
<md-button id="ss-hero-btn" ref="btnRef" variant="filled" icon="filter_list">Show filters</md-button>
<md-side-sheet id="ss-hero" ref="sheetRef" variant="modal" side="end" headline="Filters" top-divider bottom-divider>
<label><md-checkbox checked></md-checkbox> In stock</label>
<label><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="text">Reset</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</template><script>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { onMount } from 'svelte';
import '@awc-ui/core/define';
let sheetRef;
let btnRef;
onMount(() => {
const sheet = sheetRef;
const btn = btnRef;
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
document.querySelectorAll('[data-ss-hero-close]').forEach(function (b) {
b.addEventListener('mdClick', function () { sheet.close(); });
});
});
</script>
<md-button id="ss-hero-btn" bind:this={btnRef} variant="filled" icon="filter_list">Show filters</md-button>
<md-side-sheet id="ss-hero" bind:this={sheetRef} variant="modal" side="end" headline="Filters" top-divider bottom-divider>
<label><md-checkbox checked></md-checkbox> In stock</label>
<label><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="text">Reset</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
Already installed? See the
Installation guide for one-time package setup
(core + tokens, fonts). Each tab below shows two patterns for using
md-side-sheet in your project: Option A registers every AWC UI
component at once (simplest), Option B imports only this component for
tree-shake-friendly bundles.
<!-- ─── Option A: global registration (all components) ─── -->
<script type="module">
import '@awc-ui/core/define';
</script>
<!-- ─── Option B: single import (tree-shake only md-side-sheet) ─── -->
<script type="module">
import '@awc-ui/core/components/md-side-sheet';
</script>
<md-side-sheet></md-side-sheet>// ─── Option A: typed React wrapper (registers all components) ───
// Importing from '@awc-ui/react' calls defineCustomElements() as a
// side effect, so every md-* element becomes available in the browser.
import { MdSideSheet } from '@awc-ui/react';
export function Example() {
return <MdSideSheet></MdSideSheet>;
}
// ─── Option B: single import (tree-shake to only md-side-sheet) ───
// Skip the wrapper and use the raw custom element. Smallest bundle,
// but you lose typed props/events on JSX.
import '@awc-ui/core/components/md-side-sheet';
export function ExampleTreeShaken() {
return <md-side-sheet></md-side-sheet>;
}// ─── Option A: schema module (any md-* element accepted) ───
// Pair with `defineCustomElements(window)` in main.ts.
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@Component({
standalone: true,
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `<md-side-sheet></md-side-sheet>`,
})
export class ExampleComponent {}
// ─── Option B: typed directive (tree-shake friendly) ───
// Pair with `import '@awc-ui/core/components/md-side-sheet'` in main.ts.
import { Component } from '@angular/core';
import { MdSideSheet } from '@awc-ui/angular';
@Component({
standalone: true,
imports: [MdSideSheet],
template: `<md-side-sheet></md-side-sheet>`,
})
export class ExampleTreeShakenComponent {}<!-- ─── Option A: typed Vue wrapper (registers all components) ─── -->
<script setup lang="ts">
import { MdSideSheet } from '@awc-ui/vue';
</script>
<template>
<MdSideSheet></MdSideSheet>
</template>
<!-- ─── Option B: single import (tree-shake to only md-side-sheet) ─── -->
<script setup lang="ts">
import '@awc-ui/core/components/md-side-sheet';
</script>
<template>
<md-side-sheet></md-side-sheet>
</template><!-- ─── Option A: global registration (done once in main entry) ─── -->
<!-- main.ts: -->
<!-- import { defineCustomElements } from '@awc-ui/svelte'; -->
<!-- defineCustomElements(window); -->
<md-side-sheet></md-side-sheet>
<!-- ─── Option B: single import (tree-shake to only md-side-sheet) ─── -->
<script lang="ts">
import '@awc-ui/core/components/md-side-sheet';
</script>
<md-side-sheet></md-side-sheet>variant="standard").variant="modal").show-back).| Situation | Use instead |
|---|---|
| Mobile supplementary content | md-bottom-sheet |
| A blocking decision | md-dialog |
| Brief feedback | md-snackbar |
| App-level destination navigation | md-navigation-rail / md-navigation-bar |
| A short action list | md-menu |
| Primary content the task depends on | A page, or a md-card in the main column |
| Need | Setting |
|---|---|
| Sits beside content, no scrim | variant="standard" (default) |
| Over the content with a scrim | variant="modal" |
| Trailing edge (M3’s usual choice) | side="end" (default) |
| Leading edge | side="start" |
| Floating, inset from the edge | detached |
| Back arrow for a nested view | show-back (+ mdBack) |
| Prevent click-away (modal) | scrim-dismissible="false" |
A standard sheet is inline, so it can safely be rendered open in a page like this one — the demos below do exactly that. A modal sheet covers the viewport and locks page scroll, so every modal demo on this page opens from a button instead.
The default: a standard sheet on the inline-end edge, sharing the layout box with your content.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">The default: a standard sheet on the inline-end edge, sharing the layout box with your content.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox checked></md-checkbox> In stock</label>
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>import { MdButton, MdCheckbox, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '180px' }}>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0' }}>The default: a standard sheet on the inline-end edge, sharing the layout box with your content.</p>
</div>
<MdSideSheet variant="standard" side="end" headline="Filters" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '240px', '--md-side-sheet-max-width': '240px' }}>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', paddingBlock: '4px' }}><MdCheckbox checked></MdCheckbox> In stock</label>
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', paddingBlock: '4px' }}><MdCheckbox></MdCheckbox> On sale</label>
<MdButton slot="actions" variant="filled">Apply</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">The default: a standard sheet on the inline-end edge, sharing the layout box with your content.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox checked></md-checkbox> In stock</label>
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">The default: a standard sheet on the inline-end edge, sharing the layout box with your content.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox checked></md-checkbox> In stock</label>
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">The default: a standard sheet on the inline-end edge, sharing the layout box with your content.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox checked></md-checkbox> In stock</label>
<label style="display:flex; align-items:center; gap:8px; padding-block:4px;"><md-checkbox></md-checkbox> On sale</label>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>Anchored to the inline-start edge.
Main content sits beside it — a standard sheet never covers the page.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" side="start" headline="Navigation" open style="flex: 0 0 auto; --md-side-sheet-width: 220px; --md-side-sheet-max-width: 220px;">
<p style="margin: 0; font-size: 14px;">Anchored to the inline-start edge.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content sits beside it — a standard sheet never covers the page.</p>
</div>
</div>import { MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '200px' }}>
<MdSideSheet variant="standard" side="start" headline="Navigation" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '220px', '--md-side-sheet-max-width': '220px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>Anchored to the inline-start edge.</p>
</MdSideSheet>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0' }}>Main content sits beside it — a standard sheet never covers the page.</p>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" side="start" headline="Navigation" open style="flex: 0 0 auto; --md-side-sheet-width: 220px; --md-side-sheet-max-width: 220px;">
<p style="margin: 0; font-size: 14px;">Anchored to the inline-start edge.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content sits beside it — a standard sheet never covers the page.</p>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" side="start" headline="Navigation" open style="flex: 0 0 auto; --md-side-sheet-width: 220px; --md-side-sheet-max-width: 220px;">
<p style="margin: 0; font-size: 14px;">Anchored to the inline-start edge.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content sits beside it — a standard sheet never covers the page.</p>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" side="start" headline="Navigation" open style="flex: 0 0 auto; --md-side-sheet-width: 220px; --md-side-sheet-max-width: 220px;">
<p style="margin: 0; font-size: 14px;">Anchored to the inline-start edge.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content sits beside it — a standard sheet never covers the page.</p>
</div>
</div>A wide sheet suits editing forms and detail views that would feel cramped at the default width.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">A wide sheet suits editing forms and detail views that would feel cramped at the default width.</p>
</div>
<md-side-sheet variant="standard" headline="Edit product" open style="flex: 0 0 auto; --md-side-sheet-width: 380px; --md-side-sheet-max-width: 380px;">
<div style="display: grid; gap: 16px;">
<md-text-field label="Name" variant="outlined" style="inline-size: 100%;"></md-text-field>
<md-text-field label="SKU" variant="outlined" style="inline-size: 100%;"></md-text-field>
</div>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet>
</div>import { MdButton, MdSideSheet, MdTextField } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '200px' }}>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0' }}>A wide sheet suits editing forms and detail views that would feel cramped at the default width.</p>
</div>
<MdSideSheet variant="standard" headline="Edit product" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '380px', '--md-side-sheet-max-width': '380px' }}>
<div style={{ display: 'grid', gap: '16px' }}>
<MdTextField label="Name" variant="outlined" style={{ inlineSize: '100%' }}></MdTextField>
<MdTextField label="SKU" variant="outlined" style={{ inlineSize: '100%' }}></MdTextField>
</div>
<MdButton slot="actions" variant="text">Cancel</MdButton>
<MdButton slot="actions" variant="filled">Save</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">A wide sheet suits editing forms and detail views that would feel cramped at the default width.</p>
</div>
<md-side-sheet variant="standard" headline="Edit product" open style="flex: 0 0 auto; --md-side-sheet-width: 380px; --md-side-sheet-max-width: 380px;">
<div style="display: grid; gap: 16px;">
<md-text-field label="Name" variant="outlined" style="inline-size: 100%;"></md-text-field>
<md-text-field label="SKU" variant="outlined" style="inline-size: 100%;"></md-text-field>
</div>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">A wide sheet suits editing forms and detail views that would feel cramped at the default width.</p>
</div>
<md-side-sheet variant="standard" headline="Edit product" open style="flex: 0 0 auto; --md-side-sheet-width: 380px; --md-side-sheet-max-width: 380px;">
<div style="display: grid; gap: 16px;">
<md-text-field label="Name" variant="outlined" style="inline-size: 100%;"></md-text-field>
<md-text-field label="SKU" variant="outlined" style="inline-size: 100%;"></md-text-field>
</div>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">A wide sheet suits editing forms and detail views that would feel cramped at the default width.</p>
</div>
<md-side-sheet variant="standard" headline="Edit product" open style="flex: 0 0 auto; --md-side-sheet-width: 380px; --md-side-sheet-max-width: 380px;">
<div style="display: grid; gap: 16px;">
<md-text-field label="Name" variant="outlined" style="inline-size: 100%;"></md-text-field>
<md-text-field label="SKU" variant="outlined" style="inline-size: 100%;"></md-text-field>
</div>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet>
</div>Order #48211 · 3 items
A modal sheet takes over the side task: it traps focus, dims the page behind a scrim, and closes on Escape or a scrim click.
side is logical, so this panel lands on the leading edge and follows text direction automatically.
show-back only emits mdBack — it does not navigate. You swap the panel content yourself. This one is also detached, so it floats inset from the edge with all four corners rounded.
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-button id="ss-modal-open" variant="filled" icon="info">Open modal sheet</md-button>
<md-side-sheet id="ss-modal" variant="modal" side="end" headline="Order details" top-divider bottom-divider>
<p>Order #48211 · 3 items</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Track order</md-button>
</md-side-sheet>
<md-side-sheet id="ss-modal-back" variant="modal" side="end" headline="Advanced filters" show-back detached>
<p>Detached floats inset from the edge, with all four corners rounded.</p>
</md-side-sheet>
<script type="module">
var pairs = [
['ss-modal-open', 'ss-modal'],
['ss-modal-start-open', 'ss-modal-start'],
['ss-modal-back-open', 'ss-modal-back'],
];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss-close')).close();
});
});
document.getElementById('ss-modal-back').addEventListener('mdBack', function (e) {
e.target.headline = 'Filters';
e.target.showBack = false;
});
</script>// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { useEffect } from 'react';
import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
useEffect(() => {
var pairs = [
['ss-modal-open', 'ss-modal'],
['ss-modal-start-open', 'ss-modal-start'],
['ss-modal-back-open', 'ss-modal-back'],
];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss-close')).close();
});
});
document.getElementById('ss-modal-back').addEventListener('mdBack', function (e) {
e.target.headline = 'Filters';
e.target.showBack = false;
});
}, []);
return (
<>
<MdButton id="ss-modal-open" variant="filled" icon="info">Open modal sheet</MdButton>
<MdSideSheet id="ss-modal" variant="modal" side="end" headline="Order details" topDivider bottom-divider>
<p>Order #48211 · 3 items</p>
<MdButton slot="actions" variant="text">Cancel</MdButton>
<MdButton slot="actions" variant="filled">Track order</MdButton>
</MdSideSheet>
<MdSideSheet id="ss-modal-back" variant="modal" side="end" headline="Advanced filters" showBack detached>
<p>Detached floats inset from the edge, with all four corners rounded.</p>
</MdSideSheet>
</>
);
}// Icons need the Material Symbols stylesheet in index.html — see Installation.
// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
// app.component.ts
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'app-demo',
templateUrl: './app.component.html',
})
export class DemoComponent implements AfterViewInit {
ngAfterViewInit() {
var pairs = [
['ss-modal-open', 'ss-modal'],
['ss-modal-start-open', 'ss-modal-start'],
['ss-modal-back-open', 'ss-modal-back'],
];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss-close')).close();
});
});
document.getElementById('ss-modal-back').addEventListener('mdBack', function (e) {
e.target.headline = 'Filters';
e.target.showBack = false;
});
}
}
<!-- app.component.html -->
<md-button id="ss-modal-open" variant="filled" icon="info">Open modal sheet</md-button>
<md-side-sheet id="ss-modal" variant="modal" side="end" headline="Order details" top-divider bottom-divider>
<p>Order #48211 · 3 items</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Track order</md-button>
</md-side-sheet>
<md-side-sheet id="ss-modal-back" variant="modal" side="end" headline="Advanced filters" show-back detached>
<p>Detached floats inset from the edge, with all four corners rounded.</p>
</md-side-sheet><script setup>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { onMounted } from 'vue';
import '@awc-ui/core/define';
onMounted(() => {
var pairs = [
['ss-modal-open', 'ss-modal'],
['ss-modal-start-open', 'ss-modal-start'],
['ss-modal-back-open', 'ss-modal-back'],
];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss-close')).close();
});
});
document.getElementById('ss-modal-back').addEventListener('mdBack', function (e) {
e.target.headline = 'Filters';
e.target.showBack = false;
});
});
</script>
<template>
<md-button id="ss-modal-open" variant="filled" icon="info">Open modal sheet</md-button>
<md-side-sheet id="ss-modal" variant="modal" side="end" headline="Order details" top-divider bottom-divider>
<p>Order #48211 · 3 items</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Track order</md-button>
</md-side-sheet>
<md-side-sheet id="ss-modal-back" variant="modal" side="end" headline="Advanced filters" show-back detached>
<p>Detached floats inset from the edge, with all four corners rounded.</p>
</md-side-sheet>
</template><script>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { onMount } from 'svelte';
import '@awc-ui/core/define';
onMount(() => {
var pairs = [
['ss-modal-open', 'ss-modal'],
['ss-modal-start-open', 'ss-modal-start'],
['ss-modal-back-open', 'ss-modal-back'],
];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss-close')).close();
});
});
document.getElementById('ss-modal-back').addEventListener('mdBack', function (e) {
e.target.headline = 'Filters';
e.target.showBack = false;
});
});
</script>
<md-button id="ss-modal-open" variant="filled" icon="info">Open modal sheet</md-button>
<md-side-sheet id="ss-modal" variant="modal" side="end" headline="Order details" top-divider bottom-divider>
<p>Order #48211 · 3 items</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Track order</md-button>
</md-side-sheet>
<md-side-sheet id="ss-modal-back" variant="modal" side="end" headline="Advanced filters" show-back detached>
<p>Detached floats inset from the edge, with all four corners rounded.</p>
</md-side-sheet>| Slot | Content |
|---|---|
| (default) | Panel body — scrolls vertically when it overflows |
headline | Custom headline content (replaces the headline prop) |
back | Custom back glyph (modal only, with show-back) |
close | Custom close affordance — only rendered while closeable is true; with closeable="false" the whole close wrapper, slot included, is dropped |
actions | Bottom action bar |
top-divider and bottom-divider add rules between the header, the body and
the actions row — useful once the body scrolls. The actions row and its bottom
divider only render when something is actually slotted into actions.
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-side-sheet variant="standard" side="start" top-divider bottom-divider aria-label="Settings panel" open>
<span slot="headline">
<span class="material-symbols-outlined" aria-hidden="true">settings</span>
Settings
</span>
<label>Notifications <md-switch selected></md-switch></label>
<label>Auto-sync <md-switch></md-switch></label>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet>
<script type="module">
var sheet = document.getElementById('ss-slots');
var toggle = document.getElementById('ss-slots-toggle');
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
</script>// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { useEffect, useRef } from 'react';
import { MdButton, MdSideSheet, MdSwitch } from '@awc-ui/react';
export function Demo() {
const sheetRef = useRef(null);
const toggleRef = useRef(null);
useEffect(() => {
const sheet = sheetRef.current;
const toggle = toggleRef.current;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
}, []);
return (
<>
<MdSideSheet variant="standard" side="start" topDivider bottomDivider aria-label="Settings panel" open>
<span slot="headline">
<span className="material-symbols-outlined" aria-hidden="true">settings</span>
Settings
</span>
<label>Notifications <MdSwitch selected></MdSwitch></label>
<label>Auto-sync <MdSwitch></MdSwitch></label>
<MdButton slot="actions" variant="text">Cancel</MdButton>
<MdButton slot="actions" variant="filled">Save</MdButton>
</MdSideSheet>
</>
);
}// Icons need the Material Symbols stylesheet in index.html — see Installation.
// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
// app.component.ts
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'app-demo',
templateUrl: './app.component.html',
})
export class DemoComponent implements AfterViewInit {
@ViewChild('sheet') sheetRef!: ElementRef;
@ViewChild('toggle') toggleRef!: ElementRef;
ngAfterViewInit() {
const sheet = this.sheetRef.nativeElement;
const toggle = this.toggleRef.nativeElement;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
}
}
<!-- app.component.html -->
<md-side-sheet variant="standard" side="start" top-divider bottom-divider aria-label="Settings panel" open>
<span slot="headline">
<span class="material-symbols-outlined" aria-hidden="true">settings</span>
Settings
</span>
<label>Notifications <md-switch selected></md-switch></label>
<label>Auto-sync <md-switch></md-switch></label>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet><script setup>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { onMounted, ref } from 'vue';
import '@awc-ui/core/define';
const sheetRef = ref(null);
const toggleRef = ref(null);
onMounted(() => {
const sheet = sheetRef.value;
const toggle = toggleRef.value;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
});
</script>
<template>
<md-side-sheet variant="standard" side="start" top-divider bottom-divider aria-label="Settings panel" open>
<span slot="headline">
<span class="material-symbols-outlined" aria-hidden="true">settings</span>
Settings
</span>
<label>Notifications <md-switch selected></md-switch></label>
<label>Auto-sync <md-switch></md-switch></label>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet>
</template><script>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { onMount } from 'svelte';
import '@awc-ui/core/define';
let sheetRef;
let toggleRef;
onMount(() => {
const sheet = sheetRef;
const toggle = toggleRef;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
});
</script>
<md-side-sheet variant="standard" side="start" top-divider bottom-divider aria-label="Settings panel" open>
<span slot="headline">
<span class="material-symbols-outlined" aria-hidden="true">settings</span>
Settings
</span>
<label>Notifications <md-switch selected></md-switch></label>
<label>Auto-sync <md-switch></md-switch></label>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Save</md-button>
</md-side-sheet>Rules under the header and above the actions.
The same panel with both dividers off — the default.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 260px;">
<md-side-sheet variant="standard" headline="Dividers" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Rules under the header and above the actions.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="No dividers" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">The same panel with both dividers off — the default.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div>import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', blockSize: '260px' }}>
<MdSideSheet variant="standard" headline="Dividers" topDivider bottomDivider open style={{ flex: '0 0 auto', '--md-side-sheet-width': '240px', '--md-side-sheet-max-width': '240px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>Rules under the header and above the actions.</p>
<MdButton slot="actions" variant="text">Reset</MdButton>
</MdSideSheet>
<MdSideSheet variant="standard" headline="No dividers" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '240px', '--md-side-sheet-max-width': '240px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>The same panel with both dividers off — the default.</p>
<MdButton slot="actions" variant="text">Reset</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 260px;">
<md-side-sheet variant="standard" headline="Dividers" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Rules under the header and above the actions.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="No dividers" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">The same panel with both dividers off — the default.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 260px;">
<md-side-sheet variant="standard" headline="Dividers" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Rules under the header and above the actions.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="No dividers" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">The same panel with both dividers off — the default.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 260px;">
<md-side-sheet variant="standard" headline="Dividers" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Rules under the header and above the actions.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="No dividers" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">The same panel with both dividers off — the default.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div>Markup in the headline slot replaces the plain headline prop.
Use the slot when the headline needs an icon, a count or a truncating title; use the prop for plain text. A slotted headline does not name the panel — aria-labelledby is wired from the headline prop only — so pair it with aria-label.
<!-- index.html <head> — the icon font the components draw from -->
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<md-side-sheet variant="standard" open aria-label="Slotted headline" style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<span slot="headline" style="display: inline-flex; align-items: center; gap: 8px;">
<span class="material-symbols-outlined" aria-hidden="true" style="font-size: 20px;">tune</span>
Slotted headline
</span>
<p style="margin: 0; font-size: 14px;">Markup in the headline slot replaces the plain <code>headline</code> prop.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Use the slot when the headline needs an icon, a count or a truncating title; use the prop for plain text. A slotted headline does not name the panel — aria-labelledby is wired from the headline prop only — so pair it with aria-label.</p>
</div>
</div>// Icons need the Material Symbols stylesheet in index.html — see Installation.
import { MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '180px' }}>
<MdSideSheet variant="standard" open aria-label="Slotted headline" style={{ flex: '0 0 auto', '--md-side-sheet-width': '260px', '--md-side-sheet-max-width': '260px' }}>
<span slot="headline" style={{ display: 'inline-flex', alignItems: 'center', gap: '8px' }}>
<span className="material-symbols-outlined" aria-hidden="true" style={{ fontSize: '20px' }}>tune</span>
Slotted headline
</span>
<p style={{ margin: '0', fontSize: '14px' }}>Markup in the headline slot replaces the plain <code>headline</code> prop.</p>
</MdSideSheet>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0' }}>Use the slot when the headline needs an icon, a count or a truncating title; use the prop for plain text. A slotted headline does not name the panel — aria-labelledby is wired from the headline prop only — so pair it with aria-label.</p>
</div>
</div>
</>
);
}// Icons need the Material Symbols stylesheet in index.html — see Installation.
// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<md-side-sheet variant="standard" open aria-label="Slotted headline" style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<span slot="headline" style="display: inline-flex; align-items: center; gap: 8px;">
<span class="material-symbols-outlined" aria-hidden="true" style="font-size: 20px;">tune</span>
Slotted headline
</span>
<p style="margin: 0; font-size: 14px;">Markup in the headline slot replaces the plain <code>headline</code> prop.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Use the slot when the headline needs an icon, a count or a truncating title; use the prop for plain text. A slotted headline does not name the panel — aria-labelledby is wired from the headline prop only — so pair it with aria-label.</p>
</div>
</div><script setup>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<md-side-sheet variant="standard" open aria-label="Slotted headline" style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<span slot="headline" style="display: inline-flex; align-items: center; gap: 8px;">
<span class="material-symbols-outlined" aria-hidden="true" style="font-size: 20px;">tune</span>
Slotted headline
</span>
<p style="margin: 0; font-size: 14px;">Markup in the headline slot replaces the plain <code>headline</code> prop.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Use the slot when the headline needs an icon, a count or a truncating title; use the prop for plain text. A slotted headline does not name the panel — aria-labelledby is wired from the headline prop only — so pair it with aria-label.</p>
</div>
</div>
</template><script>
// Icons need the Material Symbols stylesheet in index.html — see Installation.
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 180px;">
<md-side-sheet variant="standard" open aria-label="Slotted headline" style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<span slot="headline" style="display: inline-flex; align-items: center; gap: 8px;">
<span class="material-symbols-outlined" aria-hidden="true" style="font-size: 20px;">tune</span>
Slotted headline
</span>
<p style="margin: 0; font-size: 14px;">Markup in the headline slot replaces the plain <code>headline</code> prop.</p>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Use the slot when the headline needs an icon, a count or a truncating title; use the prop for plain text. A slotted headline does not name the panel — aria-labelledby is wired from the headline prop only — so pair it with aria-label.</p>
</div>
</div>Only the body scrolls — the header and the actions row stay pinned.
Keep adding copy and this region grows a scrollbar of its own.
Another paragraph, so the scroll is unmistakable.
And one more for good measure.
The dividers mark where the scroll region begins and ends.
Scroll inside the panel — the header, the dividers and the actions row do not move.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 240px;">
<md-side-sheet variant="standard" headline="Scrolling body" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 280px; --md-side-sheet-max-width: 280px;">
<p style="margin: 0; font-size: 14px;">Only the body scrolls — the header and the actions row stay pinned.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Keep adding copy and this region grows a scrollbar of its own.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Another paragraph, so the scroll is unmistakable.</p>
<p style="margin: 12px 0 0; font-size: 14px;">And one more for good measure.</p>
<p style="margin: 12px 0 0; font-size: 14px;">The dividers mark where the scroll region begins and ends.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Scroll inside the panel — the header, the dividers and the actions row do not move.</p>
</div>
</div>import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', blockSize: '240px' }}>
<MdSideSheet variant="standard" headline="Scrolling body" topDivider bottomDivider open style={{ flex: '0 0 auto', '--md-side-sheet-width': '280px', '--md-side-sheet-max-width': '280px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>Only the body scrolls — the header and the actions row stay pinned.</p>
<p style={{ margin: '12px 0 0', fontSize: '14px' }}>Keep adding copy and this region grows a scrollbar of its own.</p>
<p style={{ margin: '12px 0 0', fontSize: '14px' }}>Another paragraph, so the scroll is unmistakable.</p>
<p style={{ margin: '12px 0 0', fontSize: '14px' }}>And one more for good measure.</p>
<p style={{ margin: '12px 0 0', fontSize: '14px' }}>The dividers mark where the scroll region begins and ends.</p>
<MdButton slot="actions" variant="filled">Apply</MdButton>
</MdSideSheet>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0' }}>Scroll inside the panel — the header, the dividers and the actions row do not move.</p>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 240px;">
<md-side-sheet variant="standard" headline="Scrolling body" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 280px; --md-side-sheet-max-width: 280px;">
<p style="margin: 0; font-size: 14px;">Only the body scrolls — the header and the actions row stay pinned.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Keep adding copy and this region grows a scrollbar of its own.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Another paragraph, so the scroll is unmistakable.</p>
<p style="margin: 12px 0 0; font-size: 14px;">And one more for good measure.</p>
<p style="margin: 12px 0 0; font-size: 14px;">The dividers mark where the scroll region begins and ends.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Scroll inside the panel — the header, the dividers and the actions row do not move.</p>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 240px;">
<md-side-sheet variant="standard" headline="Scrolling body" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 280px; --md-side-sheet-max-width: 280px;">
<p style="margin: 0; font-size: 14px;">Only the body scrolls — the header and the actions row stay pinned.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Keep adding copy and this region grows a scrollbar of its own.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Another paragraph, so the scroll is unmistakable.</p>
<p style="margin: 12px 0 0; font-size: 14px;">And one more for good measure.</p>
<p style="margin: 12px 0 0; font-size: 14px;">The dividers mark where the scroll region begins and ends.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Scroll inside the panel — the header, the dividers and the actions row do not move.</p>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; block-size: 240px;">
<md-side-sheet variant="standard" headline="Scrolling body" top-divider bottom-divider open style="flex: 0 0 auto; --md-side-sheet-width: 280px; --md-side-sheet-max-width: 280px;">
<p style="margin: 0; font-size: 14px;">Only the body scrolls — the header and the actions row stay pinned.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Keep adding copy and this region grows a scrollbar of its own.</p>
<p style="margin: 12px 0 0; font-size: 14px;">Another paragraph, so the scroll is unmistakable.</p>
<p style="margin: 12px 0 0; font-size: 14px;">And one more for good measure.</p>
<p style="margin: 12px 0 0; font-size: 14px;">The dividers mark where the scroll region begins and ends.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Scroll inside the panel — the header, the dividers and the actions row do not move.</p>
</div>
</div>closeable defaults to true here — unlike
md-bottom-sheet, where it defaults to false.mdBack is emitted by the back affordance only; it does not navigate. You
swap the panel’s content, update headline, and clear showBack yourself.Escape entirely, so one keypress can never collapse every inline panel on
the page.mdClose if you drive one from a button.The scrim will not dismiss this sheet, and Escape is ignored — finish the choice below.
No close glyph in the header — dismissal is the scrim, Escape, or your own control.
A detached sheet floats inset from the edges with all four corners rounded.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-side-sheet variant="modal" headline="Confirm export" scrim-dismissible="false">
<p>Neither the scrim nor Escape dismisses this sheet.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Export</md-button>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Reading pane" closeable="false">
<p>No close glyph in the header.</p>
</md-side-sheet>
<md-side-sheet variant="modal" detached headline="Order details" top-divider bottom-divider>
<p>Floats inset from every edge.</p>
<md-button slot="actions" variant="filled">Track</md-button>
</md-side-sheet>
<script type="module">
var pairs = [['ss-nd-btn', 'ss-nd'], ['ss-ncb-btn', 'ss-ncb'], ['ss-det-btn', 'ss-det']];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss2-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss2-close')).close();
});
});
</script>import { useEffect } from 'react';
import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
useEffect(() => {
var pairs = [['ss-nd-btn', 'ss-nd'], ['ss-ncb-btn', 'ss-ncb'], ['ss-det-btn', 'ss-det']];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss2-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss2-close')).close();
});
});
}, []);
return (
<>
<MdSideSheet variant="modal" headline="Confirm export" scrimDismissible="false">
<p>Neither the scrim nor Escape dismisses this sheet.</p>
<MdButton slot="actions" variant="text">Cancel</MdButton>
<MdButton slot="actions" variant="filled">Export</MdButton>
</MdSideSheet>
<MdSideSheet variant="modal" headline="Reading pane" closeable="false">
<p>No close glyph in the header.</p>
</MdSideSheet>
<MdSideSheet variant="modal" detached headline="Order details" topDivider bottom-divider>
<p>Floats inset from every edge.</p>
<MdButton slot="actions" variant="filled">Track</MdButton>
</MdSideSheet>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
// app.component.ts
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'app-demo',
templateUrl: './app.component.html',
})
export class DemoComponent implements AfterViewInit {
ngAfterViewInit() {
var pairs = [['ss-nd-btn', 'ss-nd'], ['ss-ncb-btn', 'ss-ncb'], ['ss-det-btn', 'ss-det']];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss2-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss2-close')).close();
});
});
}
}
<!-- app.component.html -->
<md-side-sheet variant="modal" headline="Confirm export" scrim-dismissible="false">
<p>Neither the scrim nor Escape dismisses this sheet.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Export</md-button>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Reading pane" closeable="false">
<p>No close glyph in the header.</p>
</md-side-sheet>
<md-side-sheet variant="modal" detached headline="Order details" top-divider bottom-divider>
<p>Floats inset from every edge.</p>
<md-button slot="actions" variant="filled">Track</md-button>
</md-side-sheet><script setup>
import { onMounted } from 'vue';
import '@awc-ui/core/define';
onMounted(() => {
var pairs = [['ss-nd-btn', 'ss-nd'], ['ss-ncb-btn', 'ss-ncb'], ['ss-det-btn', 'ss-det']];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss2-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss2-close')).close();
});
});
});
</script>
<template>
<md-side-sheet variant="modal" headline="Confirm export" scrim-dismissible="false">
<p>Neither the scrim nor Escape dismisses this sheet.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Export</md-button>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Reading pane" closeable="false">
<p>No close glyph in the header.</p>
</md-side-sheet>
<md-side-sheet variant="modal" detached headline="Order details" top-divider bottom-divider>
<p>Floats inset from every edge.</p>
<md-button slot="actions" variant="filled">Track</md-button>
</md-side-sheet>
</template><script>
import { onMount } from 'svelte';
import '@awc-ui/core/define';
onMount(() => {
var pairs = [['ss-nd-btn', 'ss-nd'], ['ss-ncb-btn', 'ss-ncb'], ['ss-det-btn', 'ss-det']];
pairs.forEach(function (pair) {
var btn = document.querySelector('#' + pair[0]);
var sheet = document.querySelector('#' + pair[1]);
btn.addEventListener('mdClick', function () { sheet.show(); });
sheet.addEventListener('mdClose', function () { btn.focus({ preventScroll: true }); });
});
document.querySelectorAll('[data-ss2-close]').forEach(function (b) {
b.addEventListener('mdClick', function () {
document.querySelector('#' + b.getAttribute('data-ss2-close')).close();
});
});
});
</script>
<md-side-sheet variant="modal" headline="Confirm export" scrim-dismissible="false">
<p>Neither the scrim nor Escape dismisses this sheet.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Export</md-button>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Reading pane" closeable="false">
<p>No close glyph in the header.</p>
</md-side-sheet>
<md-side-sheet variant="modal" detached headline="Order details" top-divider bottom-divider>
<p>Floats inset from every edge.</p>
<md-button slot="actions" variant="filled">Track</md-button>
</md-side-sheet>The panel is a container, not a workflow — the workflow is yours. This one wires
the whole loop: a trigger, a modal filter sheet, an actions row that applies
the selection, and a summary written back into the page on mdClose.
<md-button id="filter-btn" variant="filled" icon="filter_list">Filter results</md-button>
<span id="filter-summary">No filters applied.</span>
<md-side-sheet id="filters" variant="modal" side="end" headline="Filter results" top-divider bottom-divider>
<label><md-checkbox data-filter="In stock" checked></md-checkbox> In stock</label>
<label><md-checkbox data-filter="On sale"></md-checkbox> On sale</label>
<md-button slot="actions" variant="text" id="filter-reset">Reset</md-button>
<md-button slot="actions" variant="filled" id="filter-apply">Apply</md-button>
</md-side-sheet>
<script type="module">
const panel = document.getElementById('filters');
const trigger = document.getElementById('filter-btn');
const summary = document.getElementById('filter-summary');
const boxes = [...panel.querySelectorAll('[data-filter]')];
trigger.addEventListener('mdClick', () => panel.show());
document.getElementById('filter-reset').addEventListener('mdClick', () => {
boxes.forEach((b) => (b.checked = false));
});
document.getElementById('filter-apply').addEventListener('mdClick', () => {
const picked = boxes.filter((b) => b.checked).map((b) => b.dataset.filter);
summary.textContent = picked.length ? picked.join(', ') : 'No filters applied.';
panel.close();
});
panel.addEventListener('mdClose', () => trigger.focus({ preventScroll: true }));
</script>import { useState } from 'react';
import { MdSideSheet, MdButton, MdCheckbox } from '@awc-ui/react';
const FILTERS = ['In stock', 'On sale'];
export function FilterPanel() {
const [open, setOpen] = useState(false);
const [draft, setDraft] = useState<string[]>(['In stock']);
const [applied, setApplied] = useState<string[]>([]);
const toggle = (name: string) =>
setDraft((d) => (d.includes(name) ? d.filter((n) => n !== name) : [...d, name]));
return (
<>
<MdButton variant="filled" icon="filter_list" onMdClick={() => setOpen(true)}>
Filter results
</MdButton>
<span>{applied.length ? applied.join(', ') : 'No filters applied.'}</span>
<MdSideSheet
variant="modal"
side="end"
headline="Filter results"
topDivider
bottomDivider
open={open}
onMdClose={() => setOpen(false)}
>
{FILTERS.map((name) => (
<label key={name}>
<MdCheckbox checked={draft.includes(name)} onMdChange={() => toggle(name)} />
{name}
</label>
))}
<MdButton slot="actions" variant="text" onMdClick={() => setDraft([])}>
Reset
</MdButton>
<MdButton
slot="actions"
variant="filled"
onMdClick={() => { setApplied(draft); setOpen(false); }}
>
Apply
</MdButton>
</MdSideSheet>
</>
);
}import { Component } from '@angular/core';
@Component({
selector: 'app-filter-panel',
template: `
<md-button variant="filled" icon="filter_list" (mdClick)="open = true">
Filter results
</md-button>
<span>{{ applied.length ? applied.join(', ') : 'No filters applied.' }}</span>
<md-side-sheet
variant="modal"
side="end"
headline="Filter results"
top-divider
bottom-divider
[open]="open"
(mdClose)="open = false"
>
<label *ngFor="let name of filters">
<md-checkbox
[checked]="draft.includes(name)"
(mdChange)="toggle(name)"
></md-checkbox>
{{ name }}
</label>
<md-button slot="actions" variant="text" (mdClick)="draft = []">Reset</md-button>
<md-button slot="actions" variant="filled" (mdClick)="apply()">Apply</md-button>
</md-side-sheet>
`,
})
export class FilterPanelComponent {
filters = ['In stock', 'On sale'];
draft: string[] = ['In stock'];
applied: string[] = [];
open = false;
toggle(name: string) {
this.draft = this.draft.includes(name)
? this.draft.filter((n) => n !== name)
: [...this.draft, name];
}
apply() {
this.applied = [...this.draft];
this.open = false;
}
}<script setup lang="ts">
import { ref } from 'vue';
const filters = ['In stock', 'On sale'];
const draft = ref<string[]>(['In stock']);
const applied = ref<string[]>([]);
const open = ref(false);
function toggle(name: string) {
draft.value = draft.value.includes(name)
? draft.value.filter((n) => n !== name)
: [...draft.value, name];
}
function apply() {
applied.value = [...draft.value];
open.value = false;
}
</script>
<template>
<md-button variant="filled" icon="filter_list" @mdClick="open = true">
Filter results
</md-button>
<span>{{ applied.length ? applied.join(', ') : 'No filters applied.' }}</span>
<!-- :prop on a custom element is a property binding, so no ref is needed. -->
<md-side-sheet
variant="modal"
side="end"
headline="Filter results"
top-divider
bottom-divider
:open="open"
@mdClose="open = false"
>
<label v-for="name in filters" :key="name">
<md-checkbox :checked="draft.includes(name)" @mdChange="toggle(name)" />
{{ name }}
</label>
<md-button slot="actions" variant="text" @mdClick="draft = []">Reset</md-button>
<md-button slot="actions" variant="filled" @mdClick="apply">Apply</md-button>
</md-side-sheet>
</template><script lang="ts">
const filters = ['In stock', 'On sale'];
let draft: string[] = ['In stock'];
let applied: string[] = [];
let open = false;
function toggle(name: string) {
draft = draft.includes(name) ? draft.filter((n) => n !== name) : [...draft, name];
}
function apply() {
applied = [...draft];
open = false;
}
</script>
<md-button variant="filled" icon="filter_list" on:mdClick={() => (open = true)}>
Filter results
</md-button>
<span>{applied.length ? applied.join(', ') : 'No filters applied.'}</span>
<md-side-sheet
variant="modal"
side="end"
headline="Filter results"
top-divider
bottom-divider
{open}
on:mdClose={() => (open = false)}
>
{#each filters as name}
<label>
<md-checkbox checked={draft.includes(name)} on:mdChange={() => toggle(name)}></md-checkbox>
{name}
</label>
{/each}
<md-button slot="actions" variant="text" on:mdClick={() => (draft = [])}>Reset</md-button>
<md-button slot="actions" variant="filled" on:mdClick={apply}>Apply</md-button>
</md-side-sheet>| Event | Cancelable | Detail | Fires |
|---|---|---|---|
mdOpen | no | void | The sheet opens |
mdClose | no | void | The sheet closes, by any route |
mdCancel | no | void | The sheet is dismissed — Escape, a scrim click, or the header close button |
mdBack | no | void | The back affordance is pressed |
mdCancel and mdClose are not interchangeablemdCancel is dismissal only. mdClose fires on every close, including the
one that immediately follows a dismissal and the one from your own close()
call. Treat them as the same event and you will handle every dismissal twice.
| You want to… | Listen to |
|---|---|
| Restore focus to the trigger | mdClose |
| Persist or discard panel state on close | mdClose |
| Warn that the user is abandoning unsaved edits | mdCancel |
| Distinguish Apply from Escape | mdCancel, and set a flag your mdClose handler reads |
| Swap the panel to its parent view | mdBack |
The close glyph, Escape and the scrim each take a different route out. The back arrow stays put — it only reports the press, and the log shows what you would act on.
<md-button id="open-panel" variant="filled">Open the panel</md-button>
<md-side-sheet id="panel" variant="modal" headline="Advanced filters" show-back></md-side-sheet>
<script type="module">
const panel = document.getElementById('panel');
const trigger = document.getElementById('open-panel');
trigger.addEventListener('mdClick', () => panel.show());
panel.addEventListener('mdOpen', () => console.log('mdOpen'));
panel.addEventListener('mdBack', () => { // you swap the content
panel.headline = 'Filters';
panel.showBack = false;
});
panel.addEventListener('mdCancel', () => console.log('dismissed, not applied'));
panel.addEventListener('mdClose', () => trigger.focus({ preventScroll: true }));
</script>import { useState } from 'react';
import { MdSideSheet, MdButton } from '@awc-ui/react';
export function FiltersPanel() {
const [open, setOpen] = useState(false);
const [headline, setHeadline] = useState('Advanced filters');
const [showBack, setShowBack] = useState(true);
return (
<>
<MdButton variant="filled" onMdClick={() => setOpen(true)}>Open the panel</MdButton>
<MdSideSheet
variant="modal"
open={open}
headline={headline}
showBack={showBack}
onMdOpen={() => console.log('mdOpen')}
onMdBack={() => { setHeadline('Filters'); setShowBack(false); }}
onMdCancel={() => console.log('dismissed, not applied')}
onMdClose={() => {
setOpen(false);
setHeadline('Advanced filters');
setShowBack(true);
}}
/>
</>
);
}import { Component } from '@angular/core';
@Component({
selector: 'app-filters-panel',
template: `
<md-button variant="filled" (mdClick)="open = true">Open the panel</md-button>
<md-side-sheet
variant="modal"
[open]="open"
[headline]="headline"
[showBack]="showBack"
(mdOpen)="log('mdOpen')"
(mdBack)="onBack()"
(mdCancel)="log('dismissed, not applied')"
(mdClose)="onClose()"
></md-side-sheet>
`,
})
export class FiltersPanelComponent {
open = false;
headline = 'Advanced filters';
showBack = true;
log(message: string) { console.log(message); }
onBack() {
this.headline = 'Filters';
this.showBack = false;
}
onClose() {
this.open = false;
this.headline = 'Advanced filters';
this.showBack = true;
}
}<script setup lang="ts">
import { ref } from 'vue';
const open = ref(false);
const headline = ref('Advanced filters');
const showBack = ref(true);
function onBack() {
headline.value = 'Filters';
showBack.value = false;
}
function onClose() {
open.value = false;
headline.value = 'Advanced filters';
showBack.value = true;
}
</script>
<template>
<md-button variant="filled" @mdClick="open = true">Open the panel</md-button>
<!-- :prop on a custom element is a property binding, so no ref is needed. -->
<md-side-sheet
variant="modal"
:open="open"
:headline="headline"
:showBack="showBack"
@mdOpen="console.log('mdOpen')"
@mdBack="onBack"
@mdCancel="console.log('dismissed, not applied')"
@mdClose="onClose"
/>
</template><script lang="ts">
let open = false;
let headline = 'Advanced filters';
let showBack = true;
function onBack() {
headline = 'Filters';
showBack = false;
}
function onClose() {
open = false;
headline = 'Advanced filters';
showBack = true;
}
</script>
<md-button variant="filled" on:mdClick={() => (open = true)}>Open the panel</md-button>
<md-side-sheet
variant="modal"
{open}
{headline}
show-back={showBack || undefined}
on:mdOpen={() => console.log('mdOpen')}
on:mdBack={onBack}
on:mdCancel={() => console.log('dismissed, not applied')}
on:mdClose={onClose}
></md-side-sheet>Nested flows are the one pattern the preview above cannot show end to end: the back arrow only tells you it was pressed, so re-rendering the panel’s body is yours to do. Here is that step, per technology.
<md-button id="open-panel" variant="filled">Filters</md-button>
<md-side-sheet id="panel" variant="modal" headline="Filters"></md-side-sheet>
<script type="module">
const panel = document.getElementById('panel');
const trigger = document.getElementById('open-panel');
const views = {
root: { headline: 'Filters', back: false, body: '<p>Pick a category to drill in.</p>' },
brand: { headline: 'Brand', back: true, body: '<p>Acme · Globex · Initech</p>' },
};
function render(name) {
const view = views[name];
panel.headline = view.headline;
panel.showBack = view.back;
panel.innerHTML = view.body;
}
trigger.addEventListener('mdClick', () => { render('root'); panel.show(); });
// mdBack does NOT navigate — it only reports the press.
panel.addEventListener('mdBack', () => render('root'));
panel.addEventListener('mdClose', () => trigger.focus({ preventScroll: true }));
</script>import { useState } from 'react';
import { MdSideSheet, MdButton } from '@awc-ui/react';
const VIEWS = {
root: { headline: 'Filters', back: false },
brand: { headline: 'Brand', back: true },
} as const;
export function NestedFilters() {
const [open, setOpen] = useState(false);
const [view, setView] = useState<keyof typeof VIEWS>('root');
return (
<>
<MdButton variant="filled" onMdClick={() => { setView('root'); setOpen(true); }}>
Filters
</MdButton>
<MdSideSheet
variant="modal"
open={open}
headline={VIEWS[view].headline}
showBack={VIEWS[view].back}
onMdBack={() => setView('root')}
onMdClose={() => setOpen(false)}
>
{view === 'root' ? (
<button onClick={() => setView('brand')}>Brand</button>
) : (
<p>Acme · Globex · Initech</p>
)}
</MdSideSheet>
</>
);
}import { Component } from '@angular/core';
type View = 'root' | 'brand';
@Component({
selector: 'app-nested-filters',
template: `
<md-button variant="filled" (mdClick)="openAt('root')">Filters</md-button>
<md-side-sheet
variant="modal"
[open]="open"
[headline]="view === 'root' ? 'Filters' : 'Brand'"
[showBack]="view !== 'root'"
(mdBack)="view = 'root'"
(mdClose)="open = false"
>
<button *ngIf="view === 'root'" (click)="view = 'brand'">Brand</button>
<p *ngIf="view === 'brand'">Acme · Globex · Initech</p>
</md-side-sheet>
`,
})
export class NestedFiltersComponent {
open = false;
view: View = 'root';
openAt(view: View) {
this.view = view;
this.open = true;
}
}<script setup lang="ts">
import { ref } from 'vue';
const open = ref(false);
const view = ref<'root' | 'brand'>('root');
function openPanel() {
view.value = 'root';
open.value = true;
}
</script>
<template>
<md-button variant="filled" @mdClick="openPanel">Filters</md-button>
<md-side-sheet
variant="modal"
:open="open"
:headline="view === 'root' ? 'Filters' : 'Brand'"
:showBack="view !== 'root'"
@mdBack="view = 'root'"
@mdClose="open = false"
>
<button v-if="view === 'root'" @click="view = 'brand'">Brand</button>
<p v-else>Acme · Globex · Initech</p>
</md-side-sheet>
</template><script lang="ts">
let open = false;
let view: 'root' | 'brand' = 'root';
function openPanel() {
view = 'root';
open = true;
}
</script>
<md-button variant="filled" on:mdClick={openPanel}>Filters</md-button>
<md-side-sheet
variant="modal"
{open}
headline={view === 'root' ? 'Filters' : 'Brand'}
show-back={view !== 'root' || undefined}
on:mdBack={() => (view = 'root')}
on:mdClose={() => (open = false)}
>
{#if view === 'root'}
<button on:click={() => (view = 'brand')}>Brand</button>
{:else}
<p>Acme · Globex · Initech</p>
{/if}
</md-side-sheet>| Property | Attribute | Type | Default | Reflects |
|---|---|---|---|---|
open | open | boolean | false | Yes |
variant | variant | 'standard' | 'modal' | 'standard' | Yes |
side | side | 'start' | 'end' | 'end' | Yes |
headline | headline | string | '' | — |
closeable | closeable | boolean | true | Yes |
showBack | show-back | boolean | false | Yes |
scrimDismissible | scrim-dismissible | boolean | true | — |
topDivider | top-divider | boolean | false | Yes |
bottomDivider | bottom-divider | boolean | false | Yes |
detached | detached | boolean | false | Yes |
sheetAriaLabel | aria-label | string | '' | — |
density | density | 0 | -1 | -2 | -3 | -4 | 0 | Yes |
| Method | Parameters |
|---|---|
show() | none |
close() | none |
| Slot | Description |
|---|---|
(default) | — |
back | Custom back icon element (modal only) |
headline | Custom headline content |
close | Custom close element |
actions | Bottom action buttons |
Override on the host element for per-instance theming:
| Property | Description |
|---|---|
--md-side-sheet-container-color | Container background |
--md-side-sheet-container-shape | Container corner radius (detached) |
--md-side-sheet-headline-color | Headline text color |
--md-side-sheet-content-color | Content text color |
--md-side-sheet-scrim-color | Modal scrim overlay color |
--md-side-sheet-divider-color | Divider color |
--md-side-sheet-width | Sheet inline size |
--md-side-sheet-max-width | Maximum inline size |
--md-side-sheet-icon-color | Close / back icon color |
Style internal elements through shadow DOM with ::part():
| Part | Description |
|---|---|
scrim | Modal scrim overlay |
container | Sheet surface |
header | Header row |
headline | Headline text |
close | Close button wrapper |
divider-top | Divider between header and content |
content | Scrollable content area |
divider-bottom | Divider between content and actions |
actions | Bottom action bar |
role="dialog" with aria-modal="true"; a
standard sheet’s container is role="region". That choice is the whole
accessibility contract, so pick it deliberately.headline (wired up as aria-labelledby) or
aria-label. With neither, the container falls back to the label
Side sheet — accurate, but useless to a screen-reader user. Never ship an
unnamed panel.inert, so its close button
and slotted controls are dropped from the tab order and the a11y tree while
hidden: no aria-hidden-focus violations. A closed standard sheet is
display: none instead, which removes it from the layout and the a11y tree
outright; it carries the same inert for consistency.closeable (on by default), Escape, or a cancel
button in the actions row.Tab through the pair below. In the standard sheet you can tab straight past the
panel back into the page; in the modal one, Tab cycles inside the panel until
you press Escape, and focus lands back on the button that opened it.
Not trapped — Tab moves on into the page.
role=region, no scrim, Escape ignored.
Tab repeatedly — focus cycles between these controls and never leaves the panel.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-side-sheet variant="standard" headline="Related links" aria-label="Related links" open>
<p>Not trapped — Tab moves on into the page.</p>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Trapped focus" top-divider bottom-divider>
<md-text-field label="Search" variant="outlined"></md-text-field>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
<script type="module">
var sheet = document.getElementById('ss-a11y');
var btn = document.getElementById('ss-a11y-btn');
btn.addEventListener('mdClick', function () { sheet.show(); });
document.getElementById('ss-a11y-close').addEventListener('mdClick', function () { sheet.close(); });
</script>import { useEffect, useRef } from 'react';
import { MdButton, MdSideSheet, MdTextField } from '@awc-ui/react';
export function Demo() {
const sheetRef = useRef(null);
const btnRef = useRef(null);
useEffect(() => {
const sheet = sheetRef.current;
const btn = btnRef.current;
btn.addEventListener('mdClick', function () { sheet.show(); });
document.getElementById('ss-a11y-close').addEventListener('mdClick', function () { sheet.close(); });
}, []);
return (
<>
<MdSideSheet variant="standard" headline="Related links" aria-label="Related links" open>
<p>Not trapped — Tab moves on into the page.</p>
</MdSideSheet>
<MdSideSheet variant="modal" headline="Trapped focus" topDivider bottom-divider>
<MdTextField label="Search" variant="outlined"></MdTextField>
<MdButton slot="actions" variant="filled">Apply</MdButton>
</MdSideSheet>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
// app.component.ts
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'app-demo',
templateUrl: './app.component.html',
})
export class DemoComponent implements AfterViewInit {
@ViewChild('sheet') sheetRef!: ElementRef;
@ViewChild('btn') btnRef!: ElementRef;
ngAfterViewInit() {
const sheet = this.sheetRef.nativeElement;
const btn = this.btnRef.nativeElement;
btn.addEventListener('mdClick', function () { sheet.show(); });
document.getElementById('ss-a11y-close').addEventListener('mdClick', function () { sheet.close(); });
}
}
<!-- app.component.html -->
<md-side-sheet variant="standard" headline="Related links" aria-label="Related links" open>
<p>Not trapped — Tab moves on into the page.</p>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Trapped focus" top-divider bottom-divider>
<md-text-field label="Search" variant="outlined"></md-text-field>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet><script setup>
import { onMounted, ref } from 'vue';
import '@awc-ui/core/define';
const sheetRef = ref(null);
const btnRef = ref(null);
onMounted(() => {
const sheet = sheetRef.value;
const btn = btnRef.value;
btn.addEventListener('mdClick', function () { sheet.show(); });
document.getElementById('ss-a11y-close').addEventListener('mdClick', function () { sheet.close(); });
});
</script>
<template>
<md-side-sheet variant="standard" headline="Related links" aria-label="Related links" open>
<p>Not trapped — Tab moves on into the page.</p>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Trapped focus" top-divider bottom-divider>
<md-text-field label="Search" variant="outlined"></md-text-field>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</template><script>
import { onMount } from 'svelte';
import '@awc-ui/core/define';
let sheetRef;
let btnRef;
onMount(() => {
const sheet = sheetRef;
const btn = btnRef;
btn.addEventListener('mdClick', function () { sheet.show(); });
document.getElementById('ss-a11y-close').addEventListener('mdClick', function () { sheet.close(); });
});
</script>
<md-side-sheet variant="standard" headline="Related links" aria-label="Related links" open>
<p>Not trapped — Tab moves on into the page.</p>
</md-side-sheet>
<md-side-sheet variant="modal" headline="Trapped focus" top-divider bottom-divider>
<md-text-field label="Search" variant="outlined"></md-text-field>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>The modal sheet restores focus itself, with preventScroll so the page does not
jump. A standard sheet you drive from a button does not, which is why the demos
above listen for mdClose and call focus() on the trigger.
RTL — side="start" / side="end" and every padding are logical, so the
same markup lands on the correct edge under dir="rtl" with no extra work:
<md-side-sheet variant="standard" side="end" headline="Filters"></md-side-sheet>Main content.
Trailing edge is the right.
المحتوى الرئيسي.
الحافة النهائية هي اليسار.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">Main content.</p></div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">Trailing edge is the right.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">المحتوى الرئيسي.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">الحافة النهائية هي اليسار.</p>
</md-side-sheet>
</div>
</div>import { MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>ltr</span>
<div dir="ltr" style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '150px', border: '1px dashed var(--md-sys-color-outline-variant)', borderRadius: '12px', padding: '8px' }}>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}><p style={{ margin: '0' }}>Main content.</p></div>
<MdSideSheet variant="standard" side="end" headline="Filters" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '220px', '--md-side-sheet-max-width': '220px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>Trailing edge is the right.</p>
</MdSideSheet>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>rtl</span>
<div dir="rtl" style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '150px', border: '1px dashed var(--md-sys-color-outline-variant)', borderRadius: '12px', padding: '8px' }}>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}><p style={{ margin: '0' }}>المحتوى الرئيسي.</p></div>
<MdSideSheet variant="standard" side="end" headline="عوامل التصفية" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '220px', '--md-side-sheet-max-width': '220px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>الحافة النهائية هي اليسار.</p>
</MdSideSheet>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">Main content.</p></div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">Trailing edge is the right.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">المحتوى الرئيسي.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">الحافة النهائية هي اليسار.</p>
</md-side-sheet>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">Main content.</p></div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">Trailing edge is the right.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">المحتوى الرئيسي.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">الحافة النهائية هي اليسار.</p>
</md-side-sheet>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">ltr</span>
<div dir="ltr" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">Main content.</p></div>
<md-side-sheet variant="standard" side="end" headline="Filters" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">Trailing edge is the right.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">rtl</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0;">المحتوى الرئيسي.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:220px; --md-side-sheet-max-width:220px;">
<p style="margin:0; font-size:14px;">الحافة النهائية هي اليسار.</p>
</md-side-sheet>
</div>
</div>side is logical, not physicalThere is no side="right". side="end" means the trailing edge, which is the
right in LTR and the left in RTL — so if you reach for side="start" because a
mock shows the panel on the left, it will jump to the right the moment the app
is translated into Arabic or Hebrew. Both rows below are dir="rtl":
side=end — supplementary content on the trailing edge, wherever that is.
تتبع اتجاه النص.
هنا لأن التصميم قال يسار.
side=start picked to mean the left — under RTL it is now the right, and the panel has swapped sides.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">do</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=end — supplementary content on the trailing edge, wherever that is.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">تتبع اتجاه النص.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">don't</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-error); border-radius:12px; padding:8px;">
<md-side-sheet variant="standard" side="start" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">هنا لأن التصميم قال يسار.</p>
</md-side-sheet>
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=start picked to mean the left — under RTL it is now the right, and the panel has swapped sides.</p></div>
</div>
</div>import { MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>do</span>
<div dir="rtl" style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '150px', border: '1px dashed var(--md-sys-color-outline-variant)', borderRadius: '12px', padding: '8px' }}>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}><p style={{ margin: '0', fontSize: '14px' }}>side=end — supplementary content on the trailing edge, wherever that is.</p></div>
<MdSideSheet variant="standard" side="end" headline="عوامل التصفية" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '210px', '--md-side-sheet-max-width': '210px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>تتبع اتجاه النص.</p>
</MdSideSheet>
</div>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>don't</span>
<div dir="rtl" style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '150px', border: '1px dashed var(--md-sys-color-error)', borderRadius: '12px', padding: '8px' }}>
<MdSideSheet variant="standard" side="start" headline="عوامل التصفية" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '210px', '--md-side-sheet-max-width': '210px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>هنا لأن التصميم قال يسار.</p>
</MdSideSheet>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}><p style={{ margin: '0', fontSize: '14px' }}>side=start picked to mean the left — under RTL it is now the right, and the panel has swapped sides.</p></div>
</div>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">do</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=end — supplementary content on the trailing edge, wherever that is.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">تتبع اتجاه النص.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">don't</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-error); border-radius:12px; padding:8px;">
<md-side-sheet variant="standard" side="start" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">هنا لأن التصميم قال يسار.</p>
</md-side-sheet>
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=start picked to mean the left — under RTL it is now the right, and the panel has swapped sides.</p></div>
</div>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">do</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=end — supplementary content on the trailing edge, wherever that is.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">تتبع اتجاه النص.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">don't</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-error); border-radius:12px; padding:8px;">
<md-side-sheet variant="standard" side="start" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">هنا لأن التصميم قال يسار.</p>
</md-side-sheet>
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=start picked to mean the left — under RTL it is now the right, and the panel has swapped sides.</p></div>
</div>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">do</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-outline-variant); border-radius:12px; padding:8px;">
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=end — supplementary content on the trailing edge, wherever that is.</p></div>
<md-side-sheet variant="standard" side="end" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">تتبع اتجاه النص.</p>
</md-side-sheet>
</div>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">don't</span>
<div dir="rtl" style="display:flex; gap:16px; align-items:stretch; min-block-size:150px; border:1px dashed var(--md-sys-color-error); border-radius:12px; padding:8px;">
<md-side-sheet variant="standard" side="start" headline="عوامل التصفية" open style="flex:0 0 auto; --md-side-sheet-width:210px; --md-side-sheet-max-width:210px;">
<p style="margin:0; font-size:14px;">هنا لأن التصميم قال يسار.</p>
</md-side-sheet>
<div style="flex:1; padding:8px; color:var(--md-sys-color-on-surface-variant);"><p style="margin:0; font-size:14px;">side=start picked to mean the left — under RTL it is now the right, and the panel has swapped sides.</p></div>
</div>
</div>density="-1…-4" compacts the header, the content padding and the actions row,
and overrides the rung inherited from a global data-density ancestor. The 0
row below is the untouched default — not a rule of its own.
Default padding.
One rung tighter.
Admin density.
Dense dashboards.
The floor.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">0</span>
<md-side-sheet variant="standard" headline="Filters" density="0" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Default padding.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-1</span>
<md-side-sheet variant="standard" headline="Filters" density="-1" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">One rung tighter.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-2</span>
<md-side-sheet variant="standard" headline="Filters" density="-2" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Admin density.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-3</span>
<md-side-sheet variant="standard" headline="Filters" density="-3" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Dense dashboards.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-4</span>
<md-side-sheet variant="standard" headline="Filters" density="-4" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">The floor.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div>import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '14px 16px', alignItems: 'center' }}>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>0</span>
<MdSideSheet variant="standard" headline="Filters" density="0" open style={{ '--md-side-sheet-width': '260px', '--md-side-sheet-max-width': '260px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>Default padding.</p>
<MdButton slot="actions" variant="text">Reset</MdButton>
</MdSideSheet>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-1</span>
<MdSideSheet variant="standard" headline="Filters" density="-1" open style={{ '--md-side-sheet-width': '260px', '--md-side-sheet-max-width': '260px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>One rung tighter.</p>
<MdButton slot="actions" variant="text">Reset</MdButton>
</MdSideSheet>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-2</span>
<MdSideSheet variant="standard" headline="Filters" density="-2" open style={{ '--md-side-sheet-width': '260px', '--md-side-sheet-max-width': '260px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>Admin density.</p>
<MdButton slot="actions" variant="text">Reset</MdButton>
</MdSideSheet>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-3</span>
<MdSideSheet variant="standard" headline="Filters" density="-3" open style={{ '--md-side-sheet-width': '260px', '--md-side-sheet-max-width': '260px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>Dense dashboards.</p>
<MdButton slot="actions" variant="text">Reset</MdButton>
</MdSideSheet>
<span style={{ inlineSize: '3.5rem', opacity: '.65', fontSize: '.75rem', fontFamily: 'ui-monospace,monospace' }}>-4</span>
<MdSideSheet variant="standard" headline="Filters" density="-4" open style={{ '--md-side-sheet-width': '260px', '--md-side-sheet-max-width': '260px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>The floor.</p>
<MdButton slot="actions" variant="text">Reset</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">0</span>
<md-side-sheet variant="standard" headline="Filters" density="0" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Default padding.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-1</span>
<md-side-sheet variant="standard" headline="Filters" density="-1" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">One rung tighter.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-2</span>
<md-side-sheet variant="standard" headline="Filters" density="-2" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Admin density.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-3</span>
<md-side-sheet variant="standard" headline="Filters" density="-3" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Dense dashboards.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-4</span>
<md-side-sheet variant="standard" headline="Filters" density="-4" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">The floor.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">0</span>
<md-side-sheet variant="standard" headline="Filters" density="0" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Default padding.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-1</span>
<md-side-sheet variant="standard" headline="Filters" density="-1" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">One rung tighter.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-2</span>
<md-side-sheet variant="standard" headline="Filters" density="-2" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Admin density.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-3</span>
<md-side-sheet variant="standard" headline="Filters" density="-3" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Dense dashboards.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-4</span>
<md-side-sheet variant="standard" headline="Filters" density="-4" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">The floor.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display:grid; grid-template-columns:auto 1fr; gap:14px 16px; align-items:center;">
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">0</span>
<md-side-sheet variant="standard" headline="Filters" density="0" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Default padding.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-1</span>
<md-side-sheet variant="standard" headline="Filters" density="-1" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">One rung tighter.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-2</span>
<md-side-sheet variant="standard" headline="Filters" density="-2" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Admin density.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-3</span>
<md-side-sheet variant="standard" headline="Filters" density="-3" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">Dense dashboards.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
<span style="inline-size:3.5rem; opacity:.65; font-size:.75rem; font-family:ui-monospace,monospace;">-4</span>
<md-side-sheet variant="standard" headline="Filters" density="-4" open style="--md-side-sheet-width:260px; --md-side-sheet-max-width:260px;">
<p style="margin:0; font-size:13px;">The floor.</p>
<md-button slot="actions" variant="text">Reset</md-button>
</md-side-sheet>
</div>Measured across the five: the header goes 76 → 69 → 62 → 59 → 56px and the content padding 12/24 → 11/22 → 10/20 → 9/18 → 8/16px.
They compose: a data-density ancestor sets the rung for everything below it,
dir="rtl" flips the edge, and a local density="-1…-4" prop tightens one panel
further. Going back the other way needs the custom property, not density="0" —
the third panel below resets with style="--md-sys-density-scale: 0".
dir=rtl, data-density=-2 on the wrapper.
يرث الدرجة -2 من الأصل.
density="-4" يضغط أكثر من الأصل.
--md-sys-density-scale: 0 يعيد الضبط.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div dir="rtl" data-density="-2" style="display:flex; gap:16px; align-items:stretch; min-block-size:180px; border:1px dashed var(--md-sys-color-outline); border-radius:12px; padding:12px;">
<div style="flex:1; min-inline-size:6rem; padding:8px; color:var(--md-sys-color-on-surface-variant);">
<p style="margin:0; font-size:14px;">dir=rtl, data-density=-2 on the wrapper.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="موروث" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">يرث الدرجة -2 من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="مضغوط" density="-4" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">density="-4" يضغط أكثر من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="عادي" open style="flex:0 0 auto; --md-sys-density-scale:0; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">--md-sys-density-scale: 0 يعيد الضبط.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
</div>import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div dir="rtl" data-density="-2" style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '180px', border: '1px dashed var(--md-sys-color-outline)', borderRadius: '12px', padding: '12px' }}>
<div style={{ flex: '1', minInlineSize: '6rem', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0', fontSize: '14px' }}>dir=rtl, data-density=-2 on the wrapper.</p>
</div>
<MdSideSheet variant="standard" side="end" headline="موروث" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '190px', '--md-side-sheet-max-width': '190px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>يرث الدرجة -2 من الأصل.</p>
<MdButton slot="actions" variant="text">إعادة</MdButton>
</MdSideSheet>
<MdSideSheet variant="standard" side="end" headline="مضغوط" density="-4" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '190px', '--md-side-sheet-max-width': '190px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>density="-4" يضغط أكثر من الأصل.</p>
<MdButton slot="actions" variant="text">إعادة</MdButton>
</MdSideSheet>
<MdSideSheet variant="standard" side="end" headline="عادي" open style={{ flex: '0 0 auto', '--md-sys-density-scale': '0', '--md-side-sheet-width': '190px', '--md-side-sheet-max-width': '190px' }}>
<p style={{ margin: '0', fontSize: '13px' }}>--md-sys-density-scale: 0 يعيد الضبط.</p>
<MdButton slot="actions" variant="text">إعادة</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div dir="rtl" data-density="-2" style="display:flex; gap:16px; align-items:stretch; min-block-size:180px; border:1px dashed var(--md-sys-color-outline); border-radius:12px; padding:12px;">
<div style="flex:1; min-inline-size:6rem; padding:8px; color:var(--md-sys-color-on-surface-variant);">
<p style="margin:0; font-size:14px;">dir=rtl, data-density=-2 on the wrapper.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="موروث" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">يرث الدرجة -2 من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="مضغوط" density="-4" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">density="-4" يضغط أكثر من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="عادي" open style="flex:0 0 auto; --md-sys-density-scale:0; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">--md-sys-density-scale: 0 يعيد الضبط.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div dir="rtl" data-density="-2" style="display:flex; gap:16px; align-items:stretch; min-block-size:180px; border:1px dashed var(--md-sys-color-outline); border-radius:12px; padding:12px;">
<div style="flex:1; min-inline-size:6rem; padding:8px; color:var(--md-sys-color-on-surface-variant);">
<p style="margin:0; font-size:14px;">dir=rtl, data-density=-2 on the wrapper.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="موروث" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">يرث الدرجة -2 من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="مضغوط" density="-4" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">density="-4" يضغط أكثر من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="عادي" open style="flex:0 0 auto; --md-sys-density-scale:0; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">--md-sys-density-scale: 0 يعيد الضبط.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div dir="rtl" data-density="-2" style="display:flex; gap:16px; align-items:stretch; min-block-size:180px; border:1px dashed var(--md-sys-color-outline); border-radius:12px; padding:12px;">
<div style="flex:1; min-inline-size:6rem; padding:8px; color:var(--md-sys-color-on-surface-variant);">
<p style="margin:0; font-size:14px;">dir=rtl, data-density=-2 on the wrapper.</p>
</div>
<md-side-sheet variant="standard" side="end" headline="موروث" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">يرث الدرجة -2 من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="مضغوط" density="-4" open style="flex:0 0 auto; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">density="-4" يضغط أكثر من الأصل.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" side="end" headline="عادي" open style="flex:0 0 auto; --md-sys-density-scale:0; --md-side-sheet-width:190px; --md-side-sheet-max-width:190px;">
<p style="margin:0; font-size:13px;">--md-sys-density-scale: 0 يعيد الضبط.</p>
<md-button slot="actions" variant="text">إعادة</md-button>
</md-side-sheet>
</div>The panel’s width does not grow with its content, so a headline or action label that fits in English can wrap — or ellipsize, since the headline is a single truncating line. Check each locale at your narrowest rung.
Längere Übersetzungen können in einem schmalen Panel umbrechen — prüfen Sie die Breite pro Sprache.
見出し、本文、操作ラベルをすべて翻訳します。
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" headline="Filter" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Längere Übersetzungen können in einem schmalen Panel umbrechen — prüfen Sie die Breite pro Sprache.</p>
<md-button slot="actions" variant="text">Zurücksetzen</md-button>
<md-button slot="actions" variant="filled">Anwenden</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="フィルター" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">見出し、本文、操作ラベルをすべて翻訳します。</p>
<md-button slot="actions" variant="text">リセット</md-button>
<md-button slot="actions" variant="filled">適用</md-button>
</md-side-sheet>
</div>import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '200px' }}>
<MdSideSheet variant="standard" headline="Filter" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '240px', '--md-side-sheet-max-width': '240px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>Längere Übersetzungen können in einem schmalen Panel umbrechen — prüfen Sie die Breite pro Sprache.</p>
<MdButton slot="actions" variant="text">Zurücksetzen</MdButton>
<MdButton slot="actions" variant="filled">Anwenden</MdButton>
</MdSideSheet>
<MdSideSheet variant="standard" headline="フィルター" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '240px', '--md-side-sheet-max-width': '240px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>見出し、本文、操作ラベルをすべて翻訳します。</p>
<MdButton slot="actions" variant="text">リセット</MdButton>
<MdButton slot="actions" variant="filled">適用</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" headline="Filter" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Längere Übersetzungen können in einem schmalen Panel umbrechen — prüfen Sie die Breite pro Sprache.</p>
<md-button slot="actions" variant="text">Zurücksetzen</md-button>
<md-button slot="actions" variant="filled">Anwenden</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="フィルター" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">見出し、本文、操作ラベルをすべて翻訳します。</p>
<md-button slot="actions" variant="text">リセット</md-button>
<md-button slot="actions" variant="filled">適用</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" headline="Filter" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Längere Übersetzungen können in einem schmalen Panel umbrechen — prüfen Sie die Breite pro Sprache.</p>
<md-button slot="actions" variant="text">Zurücksetzen</md-button>
<md-button slot="actions" variant="filled">Anwenden</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="フィルター" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">見出し、本文、操作ラベルをすべて翻訳します。</p>
<md-button slot="actions" variant="text">リセット</md-button>
<md-button slot="actions" variant="filled">適用</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px;">
<md-side-sheet variant="standard" headline="Filter" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Längere Übersetzungen können in einem schmalen Panel umbrechen — prüfen Sie die Breite pro Sprache.</p>
<md-button slot="actions" variant="text">Zurücksetzen</md-button>
<md-button slot="actions" variant="filled">Anwenden</md-button>
</md-side-sheet>
<md-side-sheet variant="standard" headline="フィルター" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">見出し、本文、操作ラベルをすべて翻訳します。</p>
<md-button slot="actions" variant="text">リセット</md-button>
<md-button slot="actions" variant="filled">適用</md-button>
</md-side-sheet>
</div>Density — set it globally with data-density on any ancestor, or locally
with the density="-1…-4" prop, which wins over the inherited rung. density="0"
is not defined, so it inherits rather than resets; use
--md-sys-density-scale: 0 for that. See Density.
i18n — translate headline, aria-label and every action label. The panel
width is fixed-ish, so check that longer translations do not wrap awkwardly.
| Custom property | Purpose | Default |
|---|---|---|
--md-side-sheet-container-color | Surface background — variant="standard" only | --md-sys-color-surface (a modal container is fixed at --md-sys-color-surface-container-low and ignores this property) |
--md-side-sheet-container-shape | Corner radius | 0px, or --md-sys-shape-corner-large when detached |
--md-side-sheet-headline-color | Headline text | --md-sys-color-on-surface-variant |
--md-side-sheet-content-color | Body text | --md-sys-color-on-surface |
--md-side-sheet-scrim-color | Modal backdrop | rgba(0, 0, 0, 0.32) |
--md-side-sheet-divider-color | Top / bottom rules | --md-sys-color-outline-variant |
--md-side-sheet-icon-color | Close and back glyphs | --md-sys-color-on-surface-variant |
--md-side-sheet-width | Panel inline size | max(280px, 360px + rung × 16px) |
--md-side-sheet-max-width | Maximum inline size | max(320px, 400px + rung × 16px) |
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<md-side-sheet
variant="standard"
side="end"
headline="Themed"
top-divider
open
style="
--md-side-sheet-container-color: var(--md-sys-color-surface-container-highest);
--md-side-sheet-headline-color: var(--md-sys-color-primary);
--md-side-sheet-divider-color: var(--md-sys-color-primary);
--md-side-sheet-width: 240px;
--md-side-sheet-max-width: 240px;
"
>
<p>Narrower panel, primary-tinted headline and divider.</p>
</md-side-sheet>
<script type="module">
var sheet = document.getElementById('ss-theme');
var toggle = document.getElementById('ss-theme-toggle');
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
</script>import { useEffect, useRef } from 'react';
import { MdSideSheet } from '@awc-ui/react';
export function Demo() {
const sheetRef = useRef(null);
const toggleRef = useRef(null);
useEffect(() => {
const sheet = sheetRef.current;
const toggle = toggleRef.current;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
}, []);
return (
<>
<MdSideSheet
variant="standard"
side="end"
headline="Themed"
topDivider
open
style={{ '--md-side-sheet-container-color': 'var(--md-sys-color-surface-container-highest)', '--md-side-sheet-headline-color': 'var(--md-sys-color-primary)', '--md-side-sheet-divider-color': 'var(--md-sys-color-primary)', '--md-side-sheet-width': '240px', '--md-side-sheet-max-width': '240px' }}
>
<p>Narrower panel, primary-tinted headline and divider.</p>
</MdSideSheet>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
// app.component.ts
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core';
@Component({
selector: 'app-demo',
templateUrl: './app.component.html',
})
export class DemoComponent implements AfterViewInit {
@ViewChild('sheet') sheetRef!: ElementRef;
@ViewChild('toggle') toggleRef!: ElementRef;
ngAfterViewInit() {
const sheet = this.sheetRef.nativeElement;
const toggle = this.toggleRef.nativeElement;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
}
}
<!-- app.component.html -->
<md-side-sheet
variant="standard"
side="end"
headline="Themed"
top-divider
open
style="
--md-side-sheet-container-color: var(--md-sys-color-surface-container-highest);
--md-side-sheet-headline-color: var(--md-sys-color-primary);
--md-side-sheet-divider-color: var(--md-sys-color-primary);
--md-side-sheet-width: 240px;
--md-side-sheet-max-width: 240px;
"
>
<p>Narrower panel, primary-tinted headline and divider.</p>
</md-side-sheet><script setup>
import { onMounted, ref } from 'vue';
import '@awc-ui/core/define';
const sheetRef = ref(null);
const toggleRef = ref(null);
onMounted(() => {
const sheet = sheetRef.value;
const toggle = toggleRef.value;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
});
</script>
<template>
<md-side-sheet
variant="standard"
side="end"
headline="Themed"
top-divider
open
style="
--md-side-sheet-container-color: var(--md-sys-color-surface-container-highest);
--md-side-sheet-headline-color: var(--md-sys-color-primary);
--md-side-sheet-divider-color: var(--md-sys-color-primary);
--md-side-sheet-width: 240px;
--md-side-sheet-max-width: 240px;
"
>
<p>Narrower panel, primary-tinted headline and divider.</p>
</md-side-sheet>
</template><script>
import { onMount } from 'svelte';
import '@awc-ui/core/define';
let sheetRef;
let toggleRef;
onMount(() => {
const sheet = sheetRef;
const toggle = toggleRef;
toggle.addEventListener('mdClick', function () {
if (sheet.open) sheet.close();
else sheet.show();
});
sheet.addEventListener('mdClose', function () { toggle.focus({ preventScroll: true }); });
});
</script>
<md-side-sheet
variant="standard"
side="end"
headline="Themed"
top-divider
open
style="
--md-side-sheet-container-color: var(--md-sys-color-surface-container-highest);
--md-side-sheet-headline-color: var(--md-sys-color-primary);
--md-side-sheet-divider-color: var(--md-sys-color-primary);
--md-side-sheet-width: 240px;
--md-side-sheet-max-width: 240px;
"
>
<p>Narrower panel, primary-tinted headline and divider.</p>
</md-side-sheet>Check any override in both themes — the sheet sits on a surface role that is much closer to the page background on dark, so a panel that reads as clearly separated on light can lose its edge.
Pinned to the dark palette regardless of the theme you are reading in.
Surface, divider and text roles all resolve from the dark palette.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<div data-theme="dark" style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px; padding: 12px; border-radius: 12px; background: var(--md-sys-color-surface);">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Pinned to the dark palette regardless of the theme you are reading in.</p>
</div>
<md-side-sheet variant="standard" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Surface, divider and text roles all resolve from the dark palette.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<div data-theme="dark" style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '200px', padding: '12px', borderRadius: '12px', background: 'var(--md-sys-color-surface)' }}>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0' }}>Pinned to the dark palette regardless of the theme you are reading in.</p>
</div>
<MdSideSheet variant="standard" headline="Filters" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '240px', '--md-side-sheet-max-width': '240px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>Surface, divider and text roles all resolve from the dark palette.</p>
<MdButton slot="actions" variant="filled">Apply</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<div data-theme="dark" style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px; padding: 12px; border-radius: 12px; background: var(--md-sys-color-surface);">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Pinned to the dark palette regardless of the theme you are reading in.</p>
</div>
<md-side-sheet variant="standard" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Surface, divider and text roles all resolve from the dark palette.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<div data-theme="dark" style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px; padding: 12px; border-radius: 12px; background: var(--md-sys-color-surface);">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Pinned to the dark palette regardless of the theme you are reading in.</p>
</div>
<md-side-sheet variant="standard" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Surface, divider and text roles all resolve from the dark palette.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<div data-theme="dark" style="display: flex; gap: 16px; align-items: stretch; min-block-size: 200px; padding: 12px; border-radius: 12px; background: var(--md-sys-color-surface);">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Pinned to the dark palette regardless of the theme you are reading in.</p>
</div>
<md-side-sheet variant="standard" headline="Filters" open style="flex: 0 0 auto; --md-side-sheet-width: 240px; --md-side-sheet-max-width: 240px;">
<p style="margin: 0; font-size: 14px;">Surface, divider and text roles all resolve from the dark palette.</p>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>CSS parts — scrim, container, header, headline, close,
divider-top, content, divider-bottom, actions. Reach for them when a
custom property is not enough: an accent border on the container, a different
headline treatment, a wider gap between actions.
Main content — the panel beside it is styled through its parts.
An accent edge on the container, an italic headline and a wider action gap.
<!-- index.html — register the AWC UI elements once -->
<script type="module">
import '@awc-ui/core/define';
</script>
<style>
.ss-parts::part(container) { border-inline-start: 3px solid var(--md-sys-color-primary); }
.ss-parts::part(headline) { font-style: italic; letter-spacing: .04em; }
.ss-parts::part(actions) { gap: 16px; }
</style>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 220px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content — the panel beside it is styled through its parts.</p>
</div>
<md-side-sheet class="ss-parts" variant="standard" headline="Styled with ::part()" open style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<p style="margin: 0; font-size: 14px;">An accent edge on the container, an italic headline and a wider action gap.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>import { MdButton, MdSideSheet } from '@awc-ui/react';
export function Demo() {
return (
<>
<style>
.ss-parts::part(container) { border-inline-start: 3px solid var(--md-sys-color-primary); }
.ss-parts::part(headline) { font-style: italic; letter-spacing: .04em; }
.ss-parts::part(actions) { gap: 16px; }
</style>
<div style={{ display: 'flex', gap: '16px', alignItems: 'stretch', minBlockSize: '220px' }}>
<div style={{ flex: '1', padding: '8px', color: 'var(--md-sys-color-on-surface-variant)' }}>
<p style={{ margin: '0' }}>Main content — the panel beside it is styled through its parts.</p>
</div>
<MdSideSheet className="ss-parts" variant="standard" headline="Styled with ::part()" open style={{ flex: '0 0 auto', '--md-side-sheet-width': '260px', '--md-side-sheet-max-width': '260px' }}>
<p style={{ margin: '0', fontSize: '14px' }}>An accent edge on the container, an italic headline and a wider action gap.</p>
<MdButton slot="actions" variant="text">Cancel</MdButton>
<MdButton slot="actions" variant="filled">Apply</MdButton>
</MdSideSheet>
</div>
</>
);
}// app.module.ts — register the AWC UI elements once
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { AwcUiModule } from '@awc-ui/angular';
@NgModule({
imports: [AwcUiModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
<!-- app.component.html -->
<style>
.ss-parts::part(container) { border-inline-start: 3px solid var(--md-sys-color-primary); }
.ss-parts::part(headline) { font-style: italic; letter-spacing: .04em; }
.ss-parts::part(actions) { gap: 16px; }
</style>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 220px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content — the panel beside it is styled through its parts.</p>
</div>
<md-side-sheet class="ss-parts" variant="standard" headline="Styled with ::part()" open style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<p style="margin: 0; font-size: 14px;">An accent edge on the container, an italic headline and a wider action gap.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div><script setup>
import '@awc-ui/core/define';
</script>
<template>
<style>
.ss-parts::part(container) { border-inline-start: 3px solid var(--md-sys-color-primary); }
.ss-parts::part(headline) { font-style: italic; letter-spacing: .04em; }
.ss-parts::part(actions) { gap: 16px; }
</style>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 220px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content — the panel beside it is styled through its parts.</p>
</div>
<md-side-sheet class="ss-parts" variant="standard" headline="Styled with ::part()" open style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<p style="margin: 0; font-size: 14px;">An accent edge on the container, an italic headline and a wider action gap.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>
</template><script>
import '@awc-ui/core/define';
</script>
<style>
.ss-parts::part(container) { border-inline-start: 3px solid var(--md-sys-color-primary); }
.ss-parts::part(headline) { font-style: italic; letter-spacing: .04em; }
.ss-parts::part(actions) { gap: 16px; }
</style>
<div style="display: flex; gap: 16px; align-items: stretch; min-block-size: 220px;">
<div style="flex: 1; padding: 8px; color: var(--md-sys-color-on-surface-variant);">
<p style="margin: 0;">Main content — the panel beside it is styled through its parts.</p>
</div>
<md-side-sheet class="ss-parts" variant="standard" headline="Styled with ::part()" open style="flex: 0 0 auto; --md-side-sheet-width: 260px; --md-side-sheet-max-width: 260px;">
<p style="margin: 0; font-size: 14px;">An accent edge on the container, an italic headline and a wider action gap.</p>
<md-button slot="actions" variant="text">Cancel</md-button>
<md-button slot="actions" variant="filled">Apply</md-button>
</md-side-sheet>
</div>md-side-sheet::part(container) { border-inline-start: 3px solid var(--md-sys-color-primary);}
md-side-sheet::part(content) { padding-inline: 24px;}md-bottom-sheet ·
md-dialog ·
md-navigation-rail ·
md-navigation-bar ·
md-menu ·
md-card ·
md-icon-button
md-side-sheetTwo artefacts to give your AI agent so it generates correct UI with this component. The per-component spec answers "how do I use this exact tag?". The main-llm spec answers "which tag should I pick in the first place?".
md-side-sheet spec card
Identity · when to use / when NOT · decision cues · behavioural contract · do/don't · anti-patterns · full API. Paste into your agent when you're implementing with this component.
System-prompt preamble · decision matrix · token reference · page recipes · anti-patterns. Paste into the system prompt at the start of a piece of work.