A .panes (or .pane-layout, or
.list-detail) is the container. Two or three
.pane children are the surfaces. There is no
JavaScript — the HTML is the layout.
Tokens follow the
M3 canonical layouts.
Coplanar is the default: full-bleed surfaces and a 1dp
outline-variant divider. The split is 840px, from
either the viewport or the panes container itself
(container-type: inline-size). Below that, one pane
at a time. Compact windows add 16dp inline margins; every wider
layout uses 24dp margins and 24dp spacers. Give the container a
height — it is height: 100%.
Semantic child names are aliases of .pane:
.list-pane, .detail-pane,
.primary-pane, .supporting-pane.
Mark the visible pane on compact windows with
active. Optional content that should overlay the
page is a
side sheet, not a pane.
List-detail
The default. A 360dp list pane beside a flexible detail pane.
People pick a row; the detail shows that item. Use
.list-detail or a plain .panes.
Pair the list pane with a
list.
Inbox
Brunch this weekend?
I will be in your neighborhood doing errands this weekend. Want to grab brunch on Saturday?
<div class="list-detail">
<section class="list-pane">
<header>
<h2>Inbox</h2>
</header>
<ul class="list">…</ul>
</section>
<section class="detail-pane">
<header>
<h2>Subject</h2>
</header>
<div>…</div>
</section>
</div>
Compact
On Compact windows (below 600px), the layout has 16dp inline
margins. Medium, Expanded, Large, and Extra-large windows use
24dp inline margins and 24dp spacers. On Compact and Medium
windows (below 840px), every pane is hidden except
active. If none is active, the first pane shows.
Toggle active yourself when the user picks a row
or taps back — AutoInit() does not start panes.
On Expanded windows both panes are shown regardless of
active, so the same markup works at every size.
The illustration below is forced to one pane so the swap is visible here. Narrow the window below 840px to see the component do it itself — the list-detail demo above is the live compact view.
Inbox
Brunch this weekend?
I will be in your neighborhood doing errands this weekend. Want to grab brunch on Saturday?
list.querySelectorAll('a').forEach((row) => {
row.addEventListener('click', (event) => {
event.preventDefault();
detailPane.classList.add('active');
listPane.classList.remove('active');
});
});
back.addEventListener('click', () => {
detailPane.classList.remove('active');
listPane.classList.add('active');
});
Supporting pane
A flexible primary pane plus a 360dp supporting pane on the
trailing edge. Use it when the extra content is secondary — a
related list, inspector, or outline — and should stay in view
beside the focus. Add supporting, or use
.supporting-pane-layout.
start (or left) docks the supporting
pane on the leading edge instead.
Article
The primary pane holds the focus of the screen. Supporting
content sits beside it on expanded windows and hides on
compact ones until you mark it active.
A supporting pane is in the page flow. A side sheet overlays the page and can be dismissed.
Contents
<div class="panes supporting">
<section class="primary-pane">…</section>
<section class="supporting-pane">…</section>
</div>
<div class="panes supporting start">…</div>
Equal
equal splits two panes 1fr / 1fr. Use it when the
two surfaces have the same weight — two documents, a diff, an
editor and a preview.
Draft
Write in this pane. Both columns grow equally once the window is at least 840px wide.
Preview
The preview stays in lockstep with the draft. Neither pane is the list; neither is supporting.
<div class="panes equal">
<section class="pane">…</section>
<section class="pane">…</section>
</div>
Three-pane
three-pane is list + focus + supporting. It
needs 1200px: 360dp list, a flexible middle, 360dp supporting.
Between 840px and 1200px the default two-column list-detail
grid still applies, so the third pane wraps. Below 840px it
is the same single-pane active pattern as the
others.
Brunch this weekend?
I will be in your neighborhood doing errands this weekend. Want to grab brunch on Saturday?
Details
-
Ali Connors
From
-
Sat, 10:00
When
<div class="panes three-pane">
<section class="list-pane">…</section>
<section class="detail-pane">…</section>
<section class="supporting-pane">…</section>
</div>
Appearance
Coplanar is the default: the panes share one surface, with a
1dp divider on expanded windows. separated (or
floating) insets the panes 24dp, rounds them to
16dp, and fills each with
surface-container-low.
On a separated pane, elevated adds elevation 1.
outlined switches the fill to surface
and draws a 1dp outline.
Outlined
Surface, 1dp outline-variant stroke, no elevation.
Elevated
Surface-container-low at elevation 1.
<div class="panes equal separated">
<section class="pane outlined">…</section>
<section class="pane elevated">…</section>
</div>
A pane
Each pane is a column. A child <header>
(or .pane-header) is the 64dp top bar: icon-only
buttons, then a title-large heading. A child
<main>, .pane-content,
.pane-body, or <div> is the
scrolling body. A last-child <footer>,
.pane-footer, or <nav> is the
56dp action bar.
A direct .list fills the pane with no extra
padding, so list rows can run edge to edge under the header.
<section class="pane">
<header>
<button type="button" aria-label="Back">
<span class="material-symbols" aria-hidden="true">arrow_back</span>
</button>
<h2>Headline</h2>
<button type="button" aria-label="More">
<span class="material-symbols" aria-hidden="true">more_vert</span>
</button>
</header>
<div>…</div>
<footer>
<button type="button" class="text">Action</button>
</footer>
</section>
Tokens
| Token | Default |
|---|---|
--md-comp-pane-margin |
16px Compact; 24px Medium and wider |
--md-comp-pane-gap | 24px |
--md-comp-pane-divider-color | outline-variant |
--md-comp-pane-container-color | surface |
--md-comp-pane-container-shape | 0px (16px separated) |
--md-comp-pane-list-width | 360px |
--md-comp-pane-supporting-width | 360px |