Scaffold
A scaffold arranges the bars, rails and panes around an app's content, and adapts them to the window size.
Your messages appear here.
<md-gb-app-scaffold style="inline-size: 100%; block-size: 360px">
<md-gb-app-bar slot="top-app-bar">Inbox</md-gb-app-bar>
<md-gb-nav-bar slot="navigation-bar" aria-label="Primary">
<md-gb-nav-bar-item active>
<md-gb-icon slot="icon">inbox</md-gb-icon>
Inbox
</md-gb-nav-bar-item>
<md-gb-nav-bar-item>
<md-gb-icon slot="icon">send</md-gb-icon>
Sent
</md-gb-nav-bar-item>
</md-gb-nav-bar>
<md-gb-nav-rail slot="navigation-rail" aria-label="Primary">
<md-gb-nav-rail-item selected>
<md-gb-icon slot="icon">inbox</md-gb-icon>
Inbox
</md-gb-nav-rail-item>
<md-gb-nav-rail-item>
<md-gb-icon slot="icon">send</md-gb-icon>
Sent
</md-gb-nav-rail-item>
</md-gb-nav-rail>
<p>Your messages appear here.</p>
</md-gb-app-scaffold>Usage guidelines
Link to “Usage guidelines”- Structure the app in bars, rails and panes. Bars frame the page, rails run along its edges, and panes hold the content.
- Provide both navigation components. Give the scaffold a navigation bar and a navigation rail with the same destinations. It shows the bar in compact windows and the rail from medium windows up, and you keep their selection in sync.
- Pick the pane layout by content. Use list-detail for a collection and its details, supporting pane for a focus area with related content, and feed for a grid of items.
- Use one to three panes. The number of visible panes follows the window size.
This component is new in M3 Expressive.
Anatomy
Link to “Anatomy”md-gb-app-scaffold places bars and rails around its content. md-gb-pane-scaffold goes in the content and arranges the panes.
<md-gb-app-scaffold style="inline-size: 100%; block-size: 360px">
<md-gb-app-bar slot="top-app-bar">Notes</md-gb-app-bar>
<md-gb-nav-bar slot="navigation-bar" aria-label="Primary">
<md-gb-nav-bar-item active>
<md-gb-icon slot="icon">notes</md-gb-icon>
Notes
</md-gb-nav-bar-item>
<md-gb-nav-bar-item>
<md-gb-icon slot="icon">archive</md-gb-icon>
Archive
</md-gb-nav-bar-item>
</md-gb-nav-bar>
<md-gb-nav-rail slot="navigation-rail" aria-label="Primary">
<md-gb-nav-rail-item selected>
<md-gb-icon slot="icon">notes</md-gb-icon>
Notes
</md-gb-nav-rail-item>
<md-gb-nav-rail-item>
<md-gb-icon slot="icon">archive</md-gb-icon>
Archive
</md-gb-nav-rail-item>
</md-gb-nav-rail>
<md-gb-fab slot="fab" aria-label="New note">
<md-gb-icon>add</md-gb-icon>
</md-gb-fab>
<md-gb-pane-scaffold>
<md-gb-list slot="secondary" aria-label="Notes">
<md-gb-list-item>Groceries</md-gb-list-item>
<md-gb-list-item>Trip ideas</md-gb-list-item>
</md-gb-list>
<article>
<h2>Groceries</h2>
<p>Milk, eggs and bread.</p>
</article>
<p slot="placeholder">Select a note</p>
</md-gb-pane-scaffold>
</md-gb-app-scaffold>Examples
Link to “Examples”List-detail
Link to “List-detail”The default layout shows a list in the secondary slot and its detail in the default slot. In windows with one pane they take turns: call openDetail() when someone picks an item and closeDetail() from a back button. The placeholder slot fills the detail pane until one is open.
<md-gb-pane-scaffold style="inline-size: 100%; block-size: 240px">
<md-gb-list slot="secondary" aria-label="Conversations">
<md-gb-list-item>Ali Connors</md-gb-list-item>
<md-gb-list-item>Sandra Adams</md-gb-list-item>
<md-gb-list-item>Trevor Hansen</md-gb-list-item>
</md-gb-list>
<article>
<h2>Brunch this weekend?</h2>
<p>From Ali Connors</p>
</article>
<p slot="placeholder">Select a conversation</p>
</md-gb-pane-scaffold>Supporting pane
Link to “Supporting pane”Set layout="supporting-pane" for a focus area in the default slot with related content in the secondary slot, at the trailing side by default.
<md-gb-pane-scaffold layout="supporting-pane" style="inline-size: 100%; block-size: 360px">
<article>
<h2>Quarterly plan</h2>
<p>The goals and milestones for the next three months.</p>
</article>
<aside slot="secondary">
<h3>Related notes</h3>
<p>Budget review</p>
</aside>
</md-gb-pane-scaffold>Feed
Link to “Feed”Set layout="feed" to lay the default slot's items out on a grid, with an optional secondary pane beside it.
<md-gb-pane-scaffold layout="feed" style="inline-size: 100%; block-size: 240px">
<md-gb-card>Lemon pasta</md-gb-card>
<md-gb-card>Sourdough</md-gb-card>
<md-gb-card>Pad thai</md-gb-card>
<md-gb-card>Summer salad</md-gb-card>
</md-gb-pane-scaffold>Resizable panes
Link to “Resizable panes”Add resizable to a two-pane layout to show a drag handle between the panes. pane-width sets the width of the secondary pane in pixels, and collapsed-pane records a pane collapsed with the handle. The scaffold fires pane-resize when the panes change size.
<md-gb-pane-scaffold resizable pane-width="240" style="inline-size: 100%; block-size: 240px">
<md-gb-list slot="secondary" aria-label="Folders">
<md-gb-list-item>Inbox</md-gb-list-item>
<md-gb-list-item>Drafts</md-gb-list-item>
</md-gb-list>
<article>
<h2>Inbox</h2>
<p>Drag the handle to resize the list.</p>
</article>
</md-gb-pane-scaffold>Floating and docked panes
Link to “Floating and docked panes”When there is no room for a supporting pane beside the content, set levitate to floating or docked to lift the secondary pane above it instead of stacking it below. A docked pane sits at the bottom edge on compact windows, like a bottom sheet. Open it with openLevitated() and close it with closeLevitated(). Add levitate-modal for a scrim, and levitate-label to name the pane.
<md-gb-button id="comments-button">Comments</md-gb-button>
<md-gb-pane-scaffold layout="supporting-pane" levitate="floating" levitate-label="Comments">
<article>
<h2>Quarterly plan</h2>
<p>The goals and milestones for the next three months.</p>
</article>
<aside slot="secondary">
<h3>Comments</h3>
<p>Looks good to me.</p>
</aside>
</md-gb-pane-scaffold>md-gb-pane-scaffold {
inline-size: 100%;
block-size: 280px;
}const scaffold = document.querySelector('md-gb-pane-scaffold')!;
document.querySelector('#comments-button')!.addEventListener('click', () => {
scaffold.openLevitated();
});Accessibility
Link to “Accessibility”- Give each navigation component an
aria-label, such as "Primary navigation", and keep the bar and rail selections in sync. - In a single-pane list-detail layout, provide a back button that calls
closeDetail(). - A modal levitated pane takes focus, closes with Escape and when someone uses the content behind it, and is named by
levitate-label. - A floating pane's move and resize handles also work with the arrow keys. Use
drag-handle-label,levitate-move-labelandlevitate-resize-labelto translate their names.
API reference
Link to “API reference”<md-gb-app-scaffold>
Link to “<md-gb-app-scaffold>”A Material Design app scaffold (bars, rails, FAB, snackbar).
Properties
Link to “Properties”| Property | Attribute | Type | Default |
|---|---|---|---|
autoExpandRailWhether to expand a slotted navigation rail at large and extra-large windows and collapse it below (spec: breakpoints, swapping components). Applied when the window size class changes. |
auto-expand-rail |
boolean |
false |
navigationWhich navigation component to show. |
navigation |
ScaffoldNavigation |
'auto' |
sideSheetNavigationWhat the navigation rail does while a side sheet is present (spec: breakpoints and scaffold): keep it as is, collapse it to the collapsed rail, or hide it completely. A side sheet is present while the nested pane scaffold shows its tertiary pane or side-sheet-open is set. |
side-sheet-navigation |
SideSheetNavigation |
'keep' |
sideSheetOpenWhether an app-managed side sheet is open. |
side-sheet-open |
boolean |
false |
Slots
Link to “Slots”| Slot | Description |
|---|---|
| default | The content, typically an md-gb-pane-scaffold. Scrolls. |
companion-rail |
A companion rail on the trailing side of large and extra-large windows, holding supporting controls or actions that modify or relate to the content in a pane. |
fab |
A FAB, 16px from the trailing and bottom edges of the content. |
navigation-bar |
A navigation bar (md-gb-nav-bar) at the bottom. |
navigation-rail |
A navigation rail (md-gb-nav-rail) at the leading edge. |
snackbar |
A snackbar host (md-gb-snackbar), above the FAB. |
toolbar |
A toolbar floating in the bottom rail region, centered above the navigation bar (mobile). |
top-app-bar |
A top app bar (md-gb-app-bar), beside the rail. |
Events
Link to “Events”| Event | Description |
|---|---|
navigation-changeCustomEvent<NavigationChangeDetail> |
Fired when the shown navigation component changes. |
window-class-changeCustomEvent<WindowClassChangeDetail> |
Fired when the window size class changes. |
window-height-class-changeCustomEvent<WindowHeightClassChangeDetail> |
Fired when the window height size class changes. |
CSS parts
Link to “CSS parts”| Part | Description |
|---|---|
::part(body) |
The content region (content, FAB and snackbar). |
::part(companion-rail) |
The companion rail region. |
::part(content) |
The scrolling content container. |
::part(navigation-bar) |
The navigation bar region. |
::part(rail) |
The navigation rail region. |
::part(scaffold) |
The scaffold grid. |
::part(toolbar) |
The floating toolbar region. |
::part(top-app-bar) |
The top app bar region. |
CSS custom properties
Link to “CSS custom properties”| Property | Description |
|---|---|
--container-color |
Scaffold background. |
--content-color |
Scaffold content color. |
--scrollbar-gutter |
stable reserves the content's scrollbar gutter, so a scrollbar that appears doesn't move the content (default auto: the pane widths are measured to the edges). |
<md-gb-pane-scaffold>
Link to “<md-gb-pane-scaffold>”A Material Design pane scaffold (list-detail, supporting pane, feed).
Properties
Link to “Properties”| Property | Attribute | Type | Default |
|---|---|---|---|
arrangementHow two panes share the width. |
arrangement |
PaneArrangement |
'fixed-flexible' |
collapsedPaneA pane collapsed with the drag handle, or null. |
collapsed-pane |
"primary" |
"secondary" |
detailOpenList-detail: whether an item is selected. Single-pane windows show the detail (primary) pane when true and the list (secondary) pane when false; two-pane windows show the placeholder slot instead of the detail while false. |
detail-open |
boolean |
false |
dragHandleLabelAccessible label of the drag handle. |
drag-handle-label |
string |
'Resize panes' |
handleTapWhat a tap, Enter or Space on the drag handle does, the single-pointer alternative to dragging it: toggle (default) switches between one and two panes; cycle steps through the snap widths and then collapses the secondary pane. |
handle-tap |
PaneHandleTap |
'toggle' |
layoutThe canonical layout. |
layout |
PaneScaffoldLayout |
'list-detail' |
levitateThe levitate strategy for the secondary pane of supporting pane and feed layouts in windows too small for two panes: none reflows it below the primary pane, floating floats it above, docked docks it to the bottom edge at compact (floating from medium). |
levitate |
PaneLevitate |
'none' |
levitateCoplanarKeeps a levitated pane co-planar at large and extra-large windows. By default it floats there (spec: scaffold, "On large screens: floating panes are the default"). |
levitate-coplanar |
boolean |
false |
levitateDraggableLets a floating pane be dragged by its handle, or moved with the arrow keys while the handle is focused (spec: scaffold, floating panes "can be customized to be dragged or resized"). |
levitate-draggable |
boolean |
false |
levitateLabelAccessible label of a modal levitated pane (its dialog role). |
levitate-label |
string |
'' |
levitateModalWhether the levitated secondary pane is modal (scrim, inert panes). |
levitate-modal |
boolean |
false |
levitateMoveLabelAccessible label of the floating pane's move handle. |
levitate-move-label |
string |
'Move pane' |
levitateOpenWhether the levitated secondary pane is shown. |
levitate-open |
boolean |
false |
levitateResizableLets a floating pane be resized by its corner handle, or with the arrow keys while the handle is focused. |
levitate-resizable |
boolean |
false |
levitateResizeLabelAccessible label of the floating pane's resize handle. |
levitate-resize-label |
string |
'Resize pane' |
mediumTwoPaneWhether medium windows show two panes (50% each) instead of one. The spec limits this to low-density content such as settings. |
medium-two-pane |
boolean |
false |
paneWidthWidth in px of the secondary pane set with the drag handle, or null for the default width. Set it to restore a persisted width. |
pane-width |
number |
null |
resizableWhether two-pane layouts render a drag handle to resize the panes. |
resizable |
boolean |
false |
resizeBehaviorpersistent keeps a resized width or collapsed pane across window size class changes; temporary returns to the default layout. Defaults to persistent for list-detail and temporary for the other layouts. |
resize-behavior |
PaneResizeBehavior |
undefined |
scrollLabelAccessible label of the stacked panes' scroll region. Only used while the stacked panes overflow and hold nothing focusable: the region is then focusable (so the keyboard can scroll it) and a labelled region. |
scroll-label |
string |
'Panes' |
secondaryPositionWhere the secondary pane sits in two-pane layouts. Defaults to start for list-detail and end for supporting pane and feed layouts. Mirrors in right-to-left. |
secondary-position |
PanePosition |
undefined |
Slots
Link to “Slots”| Slot | Description |
|---|---|
| default | The primary (flexible) pane: the detail pane of a list-detail layout, the focus pane of a supporting pane layout, or the feed items (laid out on a grid) of a feed layout. |
placeholder |
Shown in the primary pane of a two-pane list-detail layout while detail-open is false (no item selected). Levitate (spec: scaffold, "Levitate"): with levitate="floating" or levitate="docked", the secondary pane of a supporting pane or feed layout floats above the primary pane (or docks to the bottom edge at compact, like a bottom sheet) in windows too small for two co-planar panes, while levitate-open is set. levitate-modal makes it modal: a scrim covers the panes, the primary pane is inert, focus moves into the pane and back to the trigger, and the pane closes when something behind it is used or Escape is pressed. Modality is scoped to the scaffold; use md-gb-dialog or md-gb-sheet for app-wide modals. At large and extra-large windows a levitated pane keeps floating (spec: "On large screens, floating panes are the default"); the scrim is optional (levitate-modal adds it). levitate-coplanar opts into a co-planar pane there instead. levitate-draggable and levitate-resizable add a move handle and a resize corner to a floating pane: drag them, or focus them and use the arrow keys (Shift moves in larger steps). levitate-change fires after each move or resize. Foldables: the scaffold reads the fold (hinge) from the Viewport Segments API and keeps panes off it. A vertical fold splits two panes at the fold with the spacer on it (at least the spacer width); a horizontal fold (tabletop) stacks the supporting pane below it. The fold crossing the scaffold is reflected as the fold attribute (vertical or horizontal). Browsers without the API keep the regular layout. |
secondary |
The secondary pane: the list of a list-detail layout or the supporting pane. It is the fixed pane in fixed-and-flexible arrangements. |
tertiary |
An optional third pane (e.g. a standard side sheet), shown at extra-large only. |
Events
Link to “Events”| Event | Description |
|---|---|
levitate-closeEvent |
Fired when the scaffold closes a levitated pane (Escape, or using something behind a modal pane). |
pane-layout-changeCustomEvent<PaneLayoutChangeDetail> |
Fired when the visible panes change. |
pane-resizeCustomEvent<PaneResizeDetail> |
Fired when the panes are resized or collapsed with the drag handle. |
window-class-changeCustomEvent<WindowClassChangeDetail> |
Fired when the window size class changes. |
window-height-class-changeCustomEvent<WindowHeightClassChangeDetail> |
Fired when the window height size class changes. |
Methods
Link to “Methods”| Method | Description |
|---|---|
closeDetail() => void |
List-detail: returns to the list (e.g. from the detail pane's back button in a single-pane window). |
closeLevitated() => void |
Hides the levitated secondary pane. |
measureFold() => void |
Finds where the viewport's fold crosses the scaffold. Call it after moving the scaffold without resizing it. |
openDetail() => void |
List-detail: shows the detail pane (e.g. after selecting an item). |
openLevitated() => void |
Shows the levitated secondary pane. |
resetPaneWidth() => void |
Returns the panes to their default widths. |
CSS parts
Link to “CSS parts”| Part | Description |
|---|---|
::part(drag-handle) |
The drag handle. |
::part(pane) |
Each pane. |
::part(primary) |
The primary pane. |
::part(scaffold) |
The flex container of the panes. |
::part(scrim) |
The scrim behind a modal levitated pane. |
::part(secondary) |
The secondary pane. |
::part(spacer) |
The spacer between panes. |
::part(tertiary) |
The tertiary pane. |
CSS custom properties
Link to “CSS custom properties”| Property | Description |
|---|---|
--feed-columns |
Overrides the number of feed grid columns. |
--md-gb-scaffold-companion-inline-size |
Width of a companion rail on the trailing side of the scaffold. Set by md-gb-app-scaffold. |
--md-gb-scaffold-nav-inline-size |
Width of a navigation rail beside the scaffold, so split panes keep the spacer centered in the window. Set by md-gb-app-scaffold. |
--pane-container-color |
Pane background (transparent: panes blend with the background, implicit grouping). |
--pane-container-shape |
Pane corner radius. |
--scrollbar-gutter |
stable reserves the panes' scrollbar gutters, so a scrollbar that appears doesn't move their content (default auto: the spacer is centered on the pane edges). |