App shell
A sidebar that stays while the main region scrolls, and a drawer when it is narrow.
An app shell is the frame of an application: a sidebar that stays in place while the main region moves. It is built on the shell layout classes, which hold the parts utilities cannot write: heights in dvh, the sticky sidebar with its own scroll, the inset for the home indicator, and the width at which the sidebar steps aside.
The shell draws nothing. In the example the hairline is a border utility, the bar is a navbar, the links are a nav and the tiles are cards in an auto grid.
App shell
<div class="shell bg-surface-base fg-text-body text-sm"> <a class="skip" href="#app-main">Skip to content</a> <aside class="shell-sidebar gap-md p-sm bxe(1) bxe-solid b-line-hair"> <a class="navbar-brand h(40) px-xs" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <nav class="nav" aria-label="Workspace"> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> <button type="button" class="btn btn-quiet justify-start mt-auto"> <span class="avatar avatar-xs"> <img class="avatar-image" src="/demo/portrait-1.svg" alt> </span>Ada Lovelace</button> </aside> <main class="shell-main" id="app-main" tabindex="-1"> <header class="navbar"> <button type="button" class="btn btn-quiet btn-square btn-sm shell-toggle" commandfor="shell-nav" command="show-modal" aria-label="Open navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 8h16M4 16h16" /> </svg> </button> <h1 class="heading heading-sm">Projects</h1> <div class="navbar-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Search"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 11a7 7 0 1 0 14 0a7 7 0 0 0-14 0M20 20l-4-4" /> </svg> </button> <button type="button" class="btn btn-primary btn-sm"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 5v14M5 12h14" /> </svg>New project</button> </div> </header> <div class="flex flex-col gap-lg p-lg"> <div class="auto-grid"> <article class="card"> <header class="card-header"> <h3 class="card-title">Atlas</h3> <p class="card-description">atlas.dev</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Borealis</h3> <p class="card-description">borealis.app</p> <span class="badge badge-info badge-dot card-action">Building</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Cinder</h3> <p class="card-description">cinder.io</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Drift</h3> <p class="card-description">drift.so</p> <span class="badge badge-danger badge-dot card-action">Failed</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Ember</h3> <p class="card-description">ember.dev</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Fathom</h3> <p class="card-description">fathom.app</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> </div> </div> </main> <dialog class="dialog dialog-drawer dialog-drawer-start" id="shell-nav" closedby="any" aria-label="Navigation"> <div class="dialog-body flex flex-col gap-md"> <a class="navbar-brand h(40) px-xs" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <nav class="nav" aria-label="Workspace, in the drawer"> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> </div> <button type="button" class="btn btn-quiet btn-square btn-sm dialog-close" commandfor="shell-nav" command="close" aria-label="Close navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6 6 18" /> </svg> </button> </dialog></div>#How it is built
| Part | Class | What it does |
|---|---|---|
| The frame | shell | A grid at least as tall as the viewport, and a size container named shell |
| The sidebar | shell-sidebar | Sticks under the header, as tall as the room left in the viewport, with its own scroll |
| The main region | shell-main | Takes the column that is left and never grows past it |
| The toggle | shell-toggle | Any control that should exist only while the sidebar is away |
By default the document scrolls. A sticky navbar keeps working, links to headings land where they should, and the browser restores the scroll position on the way back.
Below 48rem of shell the sidebar is removed from the layout. Nothing replaces it by itself: put the same navigation in a drawer on the start edge and open it from a button with shell-toggle. The drawer is a native <dialog>, opened by commandfor, so the whole arrangement needs no script.
The threshold measures the shell, not the screen: a shell inside a narrow panel collapses there, on any display.
#On a tray
Set the shell on the tray tone and stand the main region on a sheet, 8px in. The sidebar then reads as part of the frame and the content as the thing on it. The same classes; only the surfaces changed.
On a tray
<div class="shell bg-surface-tray fg-text-body text-sm"> <a class="skip" href="#app-main-inset">Skip to content</a> <aside class="shell-sidebar gap-md p-sm"> <a class="navbar-brand h(40) px-xs" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <nav class="nav" aria-label="Workspace"> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> <button type="button" class="btn btn-quiet justify-start mt-auto"> <span class="avatar avatar-xs"> <img class="avatar-image" src="/demo/portrait-1.svg" alt> </span>Ada Lovelace</button> </aside> <div class="shell-main flex flex-col p(8) pxs(0)@container(--3xl)"> <main class="sheet grow(1)" id="app-main-inset" tabindex="-1"> <header class="navbar" style="--navbar-color: var(--color-surface-raised)"> <button type="button" class="btn btn-quiet btn-square btn-sm shell-toggle" commandfor="shell-nav-inset" command="show-modal" aria-label="Open navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 8h16M4 16h16" /> </svg> </button> <h1 class="heading heading-sm">Projects</h1> <div class="navbar-end"> <button type="button" class="btn btn-primary btn-sm"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 5v14M5 12h14" /> </svg>New project</button> </div> </header> <div class="auto-grid p-lg"> <article class="card card-flat"> <header class="card-header"> <h3 class="card-title">Atlas</h3> <p class="card-description">atlas.dev</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card card-flat"> <header class="card-header"> <h3 class="card-title">Borealis</h3> <p class="card-description">borealis.app</p> <span class="badge badge-info badge-dot card-action">Building</span> </header> </article> <article class="card card-flat"> <header class="card-header"> <h3 class="card-title">Cinder</h3> <p class="card-description">cinder.io</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card card-flat"> <header class="card-header"> <h3 class="card-title">Drift</h3> <p class="card-description">drift.so</p> <span class="badge badge-danger badge-dot card-action">Failed</span> </header> </article> <article class="card card-flat"> <header class="card-header"> <h3 class="card-title">Ember</h3> <p class="card-description">ember.dev</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card card-flat"> <header class="card-header"> <h3 class="card-title">Fathom</h3> <p class="card-description">fathom.app</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> </div> </main> </div> <dialog class="dialog dialog-drawer dialog-drawer-start" id="shell-nav-inset" closedby="any" aria-label="Navigation"> <div class="dialog-body flex flex-col gap-md"> <a class="navbar-brand h(40) px-xs" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <nav class="nav" aria-label="Workspace, in the drawer"> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> </div> <button type="button" class="btn btn-quiet btn-square btn-sm dialog-close" commandfor="shell-nav-inset" command="close" aria-label="Close navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6 6 18" /> </svg> </button> </dialog></div>The navbar's pane is tinted with the surface behind it. On a sheet, set --navbar-color to the sheet's color.
#With a header
shell-header spans the shell above both columns. The sidebar then sticks under it: the shell reserves --shell-header, 3.5rem by default, which is a navbar's height. Change the property when your header is taller.
With a header
<div class="shell bg-surface-base fg-text-body text-sm"> <a class="skip" href="#app-main-header">Skip to content</a> <header class="navbar shell-header bb(1) bb-solid b-line-hair"> <button type="button" class="btn btn-quiet btn-square btn-sm shell-toggle" commandfor="shell-nav-header" command="show-modal" aria-label="Open navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 8h16M4 16h16" /> </svg> </button> <a class="navbar-brand" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <div class="navbar-end"> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Notifications"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M10 5a2 2 0 1 1 4 0a7 7 0 0 1 4 6v3a4 4 0 0 0 2 3H4a4 4 0 0 0 2-3v-3a7 7 0 0 1 4-6M9 17v1a3 3 0 0 0 6 0v-1" /> </svg> </button> <span class="avatar avatar-sm"> <img class="avatar-image" src="/demo/portrait-1.svg" alt="Ada Lovelace"> </span> </div> </header> <aside class="shell-sidebar p-sm bxe(1) bxe-solid b-line-hair"> <nav class="nav" aria-label="Workspace"> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> </aside> <main class="shell-main flex flex-col gap-lg p-lg" id="app-main-header" tabindex="-1"> <h1 class="heading heading-lg">Projects</h1> <div class="auto-grid"> <article class="card"> <header class="card-header"> <h3 class="card-title">Atlas</h3> <p class="card-description">atlas.dev</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Borealis</h3> <p class="card-description">borealis.app</p> <span class="badge badge-info badge-dot card-action">Building</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Cinder</h3> <p class="card-description">cinder.io</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Drift</h3> <p class="card-description">drift.so</p> <span class="badge badge-danger badge-dot card-action">Failed</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Ember</h3> <p class="card-description">ember.dev</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> <article class="card"> <header class="card-header"> <h3 class="card-title">Fathom</h3> <p class="card-description">fathom.app</p> <span class="badge badge-success badge-dot card-action">Ready</span> </header> </article> </div> </main> <dialog class="dialog dialog-drawer dialog-drawer-start" id="shell-nav-header" closedby="any" aria-label="Navigation"> <div class="dialog-body flex flex-col gap-md"> <a class="navbar-brand h(40) px-xs" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18M12 3a9 9 0 0 0 0 18" /> </svg>Atlas</a> <nav class="nav" aria-label="Workspace, in the drawer"> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 12 12 5l7 7M7 10v9h10v-9" /> </svg>Overview</a> <a class="nav-item" href="#" aria-current="page"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z" /> </svg>Projects <span class="nav-end">12</span> </a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0-18 0M3 12h18M12 3a14 14 0 0 1 0 18M12 3a14 14 0 0 0 0 18" /> </svg>Domains</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 19h16M7 16V9M12 16V5M17 16v-4" /> </svg>Analytics</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M5 7a4 4 0 1 0 8 0a4 4 0 0 0-8 0M3 21v-2a4 4 0 0 1 4-4h4a4 4 0 0 1 4 4v2M16 3.1a4 4 0 0 1 0 7.8M21 21v-2a4 4 0 0 0-3-3.85" /> </svg>Team</a> <a class="nav-item" href="#"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M14 6a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 6h10M18 6h2M6 12a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 12h2M10 12h10M15 18a2 2 0 1 0 4 0a2 2 0 0 0-4 0M4 18h11M19 18h1" /> </svg>Settings</a> </nav> </div> <button type="button" class="btn btn-quiet btn-square btn-sm dialog-close" commandfor="shell-nav-header" command="close" aria-label="Close navigation"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6 6 18" /> </svg> </button> </dialog></div>#Fixed
shell-fixed makes the shell exactly the viewport. Nothing scrolls but the regions, each by itself: the list keeps its place while the reader moves through what they opened. Use it for an inbox, an editor or a chat, where two things are read side by side. Use the default for everything else: a document that scrolls as a whole behaves better on a phone, where the browser's toolbars collapse as the page moves.
--shell-sidebar sets the sidebar's width; here it is 20rem, for a list of messages.
Fixed
<div class="shell shell-fixed bg-surface-base fg-text-body text-sm" style="--shell-sidebar: 20rem"> <aside class="shell-sidebar bxe(1) bxe-solid b-line-hair"> <header class="flex items-center justify-between p-md"> <h1 class="heading heading-sm">Inbox</h1> <button type="button" class="btn btn-quiet btn-square btn-sm" aria-label="Filter"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M4 6h16M7 12h10M10 18h4" /> </svg> </button> </header> <ul class="list list-interactive"> <li> <a class="list-row" href="#" aria-current="true"> <div class="list-body"> <p class="list-title">Deploy failed on drift.so</p> <p class="list-description">The install step exited with code 1.</p> </div> <span class="list-end">09:41</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Ada invited you to Borealis</p> <p class="list-description">You now have access as an editor.</p> </div> <span class="list-end">09:12</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Your invoice for October</p> <p class="list-description">$48.00, paid with the card ending 4242.</p> </div> <span class="list-end">Tue</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Domain atlas.dev renewed</p> <p class="list-description">Valid until 4 November next year.</p> </div> <span class="list-end">Mon</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Weekly summary</p> <p class="list-description">1.28M requests, 0.02% errors.</p> </div> <span class="list-end">Mon</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Cinder is live in 14 regions</p> <p class="list-description">Deployed from main by Alan.</p> </div> <span class="list-end">Sun</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">New sign-in from Tokyo</p> <p class="list-description">If this was you, there is nothing to do.</p> </div> <span class="list-end">Sat</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Usage at 80% of your plan</p> <p class="list-description">Upgrade or lower traffic before the 30th.</p> </div> <span class="list-end">Fri</span> </a> </li> </ul> </aside> <main class="shell-main"> <button type="button" class="btn btn-sm shell-toggle m-md" commandfor="inbox-list" command="show-modal">Inbox</button> <article class="flex flex-col gap-md max-w(640) p-xl"> <p class="eyebrow">Deployments</p> <h2 class="heading heading-xl">Deploy failed on drift.so</h2> <p class="lead lead-sm">The install step exited with code 1. Nothing was published, and the previous deployment is still serving traffic.</p> <pre class="code-block"><code>npm error code ERESOLVEnpm error ERESOLVE could not resolvenpm error While resolving: drift@2.4.0</code></pre> <p class="m(0) leading-md">The adapter that drift pins was withdrawn from the registry this morning, so the lockfile no longer resolves. Two other projects in this team pin the same version.</p> <p class="m(0) leading-md">Retry the deployment after pinning the dependency, or roll back from the deployments list. The log above is the last twenty lines; the full log is on the deployment page.</p> <div class="flex gap-xs"> <button type="button" class="btn btn-primary">Retry deployment</button> <button type="button" class="btn">View full log</button> </div> </article> </main> <dialog class="dialog dialog-drawer dialog-drawer-start" id="inbox-list" closedby="any" aria-label="Inbox"> <div class="dialog-body flex flex-col gap-md"> <h2 class="heading heading-sm">Inbox</h2> <ul class="list list-interactive"> <li> <a class="list-row" href="#" aria-current="true"> <div class="list-body"> <p class="list-title">Deploy failed on drift.so</p> <p class="list-description">The install step exited with code 1.</p> </div> <span class="list-end">09:41</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Ada invited you to Borealis</p> <p class="list-description">You now have access as an editor.</p> </div> <span class="list-end">09:12</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Your invoice for October</p> <p class="list-description">$48.00, paid with the card ending 4242.</p> </div> <span class="list-end">Tue</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Domain atlas.dev renewed</p> <p class="list-description">Valid until 4 November next year.</p> </div> <span class="list-end">Mon</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Weekly summary</p> <p class="list-description">1.28M requests, 0.02% errors.</p> </div> <span class="list-end">Mon</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Cinder is live in 14 regions</p> <p class="list-description">Deployed from main by Alan.</p> </div> <span class="list-end">Sun</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">New sign-in from Tokyo</p> <p class="list-description">If this was you, there is nothing to do.</p> </div> <span class="list-end">Sat</span> </a> </li> <li> <a class="list-row" href="#"> <div class="list-body"> <p class="list-title">Usage at 80% of your plan</p> <p class="list-description">Upgrade or lower traffic before the 30th.</p> </div> <span class="list-end">Fri</span> </a> </li> </ul> </div> <button type="button" class="btn btn-quiet btn-square btn-sm dialog-close" commandfor="inbox-list" command="close" aria-label="Close the inbox"> <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> <path d="M6 6l12 12M18 6 6 18" /> </svg> </button> </dialog></div>#Accessibility
- Use landmarks:
<aside>or<nav>for the sidebar,<main>for the main region,<header>for a header. Label each<nav>; with the drawer there are two, so their labels must differ. - The drawer holds the same links as the sidebar, in the same order. While the sidebar is shown, the toggle is
display: noneand out of the tab order. - A region that scrolls by itself and holds nothing focusable needs
tabindex="0"and a label, so the keyboard can scroll it. - Heights use
dvh, so a phone's toolbars never cover the foot of the sidebar; the sidebar also pads its foot by the home indicator's inset.
#Classes
| Class | Description |
|---|---|
shell | The frame: a grid at least as tall as the viewport and a size container named shell. It draws nothing |
shell-fixed | The shell is exactly the viewport and each region scrolls by itself, for an inbox, an editor or a chat. With shell |
shell-header | A header across the top of the shell; the sticky columns start --shell-header under it |
shell-sidebar | The column at the start: sticky, as tall as the room left in the viewport, with its own scroll. It leaves the layout below 48rem of shell |
shell-main | The main region: it takes the column that is left and never grows past it |
shell-aside | A column at the end, sticky like the sidebar. It leaves the layout below 64rem of shell |
shell-footer | A footer across the foot of the shell, under the columns and below the fold |
shell-toggle | A control shown only while the sidebar is away, such as the button that opens the same navigation as a drawer |
#Custom properties
| Property | Default | Description |
|---|---|---|
--shell-sidebar | 16rem | The sidebar's width |
--shell-aside | 14rem | The aside's width |
--shell-header | 3.5rem | The room kept for a shell-header above the sticky columns; a navbar's height |
#Related
- NavbarThe bar at the top of a page, which takes its material once content scrolls under it.
- NavA vertical list of destinations for a sidebar.
- DialogA native modal on an overlay sheet, opened and closed without script.
- Skip linkThe first link of a page, shown while it has focus, that jumps past the navigation.
- SurfaceTrays, sheets and wells: the material ladder every component is built on.
- CardA raised sheet whose parts follow the room the card is given.
- ListRows of things with media, words and something at the end.
- Auto gridAs many equal columns as fit, counted by the grid itself.
- DashboardFigures across the top and panels in a grid that reflows without queries.
- DocumentationNavigation, an article at a reading measure, and the contents of the page.
- Holy grailA header, three columns and a footer, with the middle one first in the source.
- Master-detailA list beside what is chosen in it, each scrolling by itself.