App shell
The frame of a web app: a sidebar, a top bar and a content area that becomes a drawer layout on small screens.
App shell
<div class="mn-shell" style="min-height:26rem;border:1px solid var(--mn-border);border-radius:var(--mn-radius-box);overflow:hidden">
<aside class="mn-shell-side" style="height:auto" aria-label="Workspace"><a class="mn-header-brand" href="#"><svg viewBox="0 0 24 24" aria-hidden="true" fill="currentColor"><path d="M4 16c3-8 6 4 9-4s5 2 7-2" stroke="currentColor" stroke-width="2.6" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>Pace</a>
<nav class="mn-sidebar" aria-label="App"><div class="mn-sidebar-group"><a class="mn-sidebar-link" href="#" aria-current="page"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 20V10M10 20V4M16 20v-7M22 20H2"/></svg> Overview</a><a class="mn-sidebar-link" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9 6h11M9 12h11M9 18h11M4 6h.01M4 12h.01M4 18h.01"/></svg> Activities</a><a class="mn-sidebar-link" href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1Z"/></svg> Settings</a></div></nav>
</aside>
<div class="mn-shell-body">
<header class="mn-shell-top"><button class="mn-btn mn-btn-ghost mn-btn-icon mn-shell-menu" aria-label="Open navigation"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 7h16M4 12h16M4 17h16"/></svg></button><div class="mn-input-group" style="max-width:18rem;flex:1"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><input class="mn-input" placeholder="Search activities" aria-label="Search activities"></div><span class="mn-avatar mn-avatar-sm" style="margin-inline-start:auto">AP</span></header>
<main class="mn-shell-main"><div class="mn-shell-head"><div><h1>This week</h1><p>42.8 km over 5 runs</p></div><button class="mn-btn mn-btn-sm"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg> Log a run</button></div>
<div class="mn-stats"><div class="mn-stat"><div class="mn-stat-label">Distance</div><div class="mn-stat-value">42.8 km</div></div><div class="mn-stat"><div class="mn-stat-label">Avg pace</div><div class="mn-stat-value">5:12</div></div></div></main>
</div>
</div>Installation
Everything ships in one stylesheet. There is nothing to import per component.
<link rel="stylesheet" href="https://mian.ro/dist/mian.css">Prefer to own the files? /r/app-shell.json is a registry item with this component's CSS and example markup, ready to copy into your project with any tool that reads the open registry-item format.
Class reference
| Class / attribute | Description |
|---|---|
| mn-shell | The frame (usually the whole page). |
| mn-shell-side | The sidebar (holds an mn-sidebar). Shown when the shell is at least 60rem wide. |
| mn-shell-body · mn-shell-top · mn-shell-main | Content column, sticky top bar, and main area. |
| mn-shell-menu | The top-bar button that opens the navigation drawer; hidden when the sidebar shows. |
| mn-shell-head | Page title, description and actions at the top of the main area. |
Accessibility
- Use <aside> or <nav aria-label> for the sidebar, <header> for the top bar and <main> for content.
- The drawer on small screens is a <dialog class="mn-drawer"> opened with data-mn-open, so focus is trapped and Escape closes it.
- Mark the current page with aria-current="page" in the sidebar.