Nav layouts
tier 1 — the frameWays to arrange a sidebar that has outgrown one list. They share the nav's classes, so an app can move between them without restyling a single link. On a phone the bottom bar takes the sidebar's place.
Choose by how many pages, and how they split.
| Layout | Use when |
|---|---|
| Text-only links | Every page should stay in view, and the icons have become noise |
| Accordion groups | The pages fall into groups and a reader works in one at a time |
| Accordion with a filter | There are too many pages to scan, and readers know what they are looking for |
| Area rail | The app splits into a handful of areas that each deserve their own nav |
| Areas in the topbar | The same split, keeping the sidebar at its usual width |
| Bottom bar | On a phone, for the few places or actions used most |
Text-only links
The ordinary nav with the icons left off, so the section labels do the grouping. No new class and no script. Do not collapse it: the collapsed rail shows only icons, and a link without one becomes a blank box.
<aside class="sidebar" style="height:520px">
<div class="brand">
<div class="brand-logo" style="background:var(--brand)"></div>
<div class="brand-text">
<strong>Dispatch Console</strong>
<span class="brand-sub">Northwind Retail</span>
</div>
</div>
<nav class="nav">
<div class="nav-scroll">
<div class="nav-section">
<span class="nav-section-label">Orders</span>
<a class="nav-link active" href="#" aria-current="page"><span>Queue</span><span class="nav-count">3</span></a>
<a class="nav-link" href="#"><span>On hold</span></a>
<a class="nav-link" href="#"><span>Returns</span></a>
<a class="nav-link" href="#"><span>Decided</span></a>
</div>
<div class="nav-section">
<span class="nav-section-label">Stock</span>
<a class="nav-link" href="#"><span>Items</span></a>
<a class="nav-link" href="#"><span>Locations</span></a>
<a class="nav-link" href="#"><span>Transfers</span></a>
<a class="nav-link" href="#"><span>Stock counts</span></a>
</div>
<div class="nav-section">
<span class="nav-section-label">Shipping</span>
<a class="nav-link" href="#"><span>Carriers</span></a>
<a class="nav-link" href="#"><span>Labels</span></a>
<a class="nav-link" href="#"><span>Pickups</span></a>
</div>
<div class="nav-section">
<span class="nav-section-label">Administration</span>
<a class="nav-link" href="#"><span>Users</span></a>
<a class="nav-link" href="#"><span>Roles</span></a>
<a class="nav-link" href="#"><span>Audit log</span></a>
</div>
</div>
<div class="nav-tools">
<a class="nav-link nav-link-tool" href="#"><i class="ri-book-2-line"></i><span>Documentation</span><i class="ri-external-link-line nav-link-ext"></i></a>
</div>
</nav>
</aside>
Accordion groups
Every group a .nav-group, each sharing one name, so opening a group
closes the one that was open. That is the platform's exclusive <details>
and needs no script. Put open on the group holding the current page, and keep
each name unique to one nav.
<aside class="sidebar" style="height:520px">
<div class="brand">
<div class="brand-logo" style="background:var(--brand)"></div>
<div class="brand-text">
<strong>Dispatch Console</strong>
<span class="brand-sub">Northwind Retail</span>
</div>
</div>
<nav class="nav">
<div class="nav-scroll">
<details class="nav-group" name="dispatch-nav" open>
<summary><i class="ri-inbox-line"></i><span>Orders</span></summary>
<a class="nav-link active" href="#" aria-current="page"><span>Queue</span><span class="nav-count">3</span></a>
<a class="nav-link" href="#"><span>On hold</span></a>
<a class="nav-link" href="#"><span>Returns</span></a>
<a class="nav-link" href="#"><span>Decided</span></a>
</details>
<details class="nav-group" name="dispatch-nav">
<summary><i class="ri-archive-stack-line"></i><span>Stock</span></summary>
<a class="nav-link" href="#"><span>Items</span></a>
<a class="nav-link" href="#"><span>Locations</span></a>
<a class="nav-link" href="#"><span>Transfers</span></a>
<a class="nav-link" href="#"><span>Stock counts</span></a>
</details>
<details class="nav-group" name="dispatch-nav">
<summary><i class="ri-truck-line"></i><span>Shipping</span></summary>
<a class="nav-link" href="#"><span>Carriers</span></a>
<a class="nav-link" href="#"><span>Labels</span></a>
<a class="nav-link" href="#"><span>Pickups</span></a>
</details>
<details class="nav-group" name="dispatch-nav">
<summary><i class="ri-bar-chart-2-line"></i><span>Reports</span></summary>
<a class="nav-link" href="#"><span>Throughput</span></a>
<a class="nav-link" href="#"><span>Exceptions</span></a>
<a class="nav-link" href="#"><span>Exports</span></a>
</details>
<details class="nav-group" name="dispatch-nav">
<summary><i class="ri-settings-3-line"></i><span>Administration</span></summary>
<a class="nav-link" href="#"><span>Users</span></a>
<a class="nav-link" href="#"><span>Roles</span></a>
<a class="nav-link" href="#"><span>API keys</span></a>
<a class="nav-link" href="#"><span>Audit log</span></a>
</details>
</div>
<div class="nav-tools">
<a class="nav-link nav-link-tool" href="#"><i class="ri-book-2-line"></i><span>Documentation</span><i class="ri-external-link-line nav-link-ext"></i></a>
</div>
</nav>
</aside>
Accordion with a filter
Live — type shelf, refund or print.
.nav-filter above .nav-scroll, with data-nav-filter on
its input. A link stays when every word typed is in its label or its
data-keywords, which is where the words a reader would type but the label does not
say belong. Closed groups show their matches without opening, Enter follows the first match,
and Escape or following a link clears the filter. .nav-filter-empty shows when
nothing is left.
<aside class="sidebar" style="height:520px">
<div class="brand">
<div class="brand-logo" style="background:var(--brand)"></div>
<div class="brand-text">
<strong>Dispatch Console</strong>
<span class="brand-sub">Northwind Retail</span>
</div>
</div>
<nav class="nav">
<div class="nav-filter">
<i class="ri-filter-3-line" aria-hidden="true"></i>
<input class="nav-filter-input" type="search" placeholder="Filter pages" aria-label="Filter pages" data-nav-filter>
</div>
<div class="nav-scroll">
<details class="nav-group" name="dispatch-filtered-nav" open>
<summary><i class="ri-inbox-line"></i><span>Orders</span></summary>
<a class="nav-link active" href="#" aria-current="page" data-keywords="pending waiting approve"><span>Queue</span><span class="nav-count">3</span></a>
<a class="nav-link" href="#" data-keywords="blocked paused address rejected"><span>On hold</span></a>
<a class="nav-link" href="#" data-keywords="refund"><span>Returns</span></a>
<a class="nav-link" href="#" data-keywords="history approved rejected"><span>Decided</span></a>
</details>
<details class="nav-group" name="dispatch-filtered-nav">
<summary><i class="ri-archive-stack-line"></i><span>Stock</span></summary>
<a class="nav-link" href="#" data-keywords="sku product"><span>Items</span></a>
<a class="nav-link" href="#" data-keywords="shelf bin warehouse"><span>Locations</span></a>
<a class="nav-link" href="#" data-keywords="move rebalance"><span>Transfers</span></a>
<a class="nav-link" href="#" data-keywords="inventory audit cycle"><span>Stock counts</span></a>
</details>
<details class="nav-group" name="dispatch-filtered-nav">
<summary><i class="ri-truck-line"></i><span>Shipping</span></summary>
<a class="nav-link" href="#" data-keywords="courier delivery"><span>Carriers</span></a>
<a class="nav-link" href="#" data-keywords="print barcode"><span>Labels</span></a>
<a class="nav-link" href="#" data-keywords="collection schedule"><span>Pickups</span></a>
</details>
<details class="nav-group" name="dispatch-filtered-nav">
<summary><i class="ri-bar-chart-2-line"></i><span>Reports</span></summary>
<a class="nav-link" href="#" data-keywords="per hour kpi"><span>Throughput</span></a>
<a class="nav-link" href="#" data-keywords="failed late error"><span>Exceptions</span></a>
<a class="nav-link" href="#" data-keywords="csv download"><span>Exports</span></a>
</details>
<details class="nav-group" name="dispatch-filtered-nav">
<summary><i class="ri-settings-3-line"></i><span>Administration</span></summary>
<a class="nav-link" href="#" data-keywords="people accounts invite"><span>Users</span></a>
<a class="nav-link" href="#" data-keywords="permissions access"><span>Roles</span></a>
<a class="nav-link" href="#" data-keywords="token integration"><span>API keys</span></a>
<a class="nav-link" href="#" data-keywords="history who changed"><span>Audit log</span></a>
</details>
<p class="nav-filter-empty">No page matches.</p>
</div>
<div class="nav-tools">
<a class="nav-link nav-link-tool" href="#"><i class="ri-book-2-line"></i><span>Documentation</span><i class="ri-external-link-line nav-link-ext"></i></a>
</div>
</nav>
</aside>
Area rail
Live — click an area. .sidebar--areas puts a
.nav-areas rail beside one .nav panel per area; each panel is an
ordinary nav under a .nav-area-title. A .nav-area button with
data-nav-area and aria-controls swaps panels in place. An app that
decides the area from the address leaves data-nav-area off and renders the
panel itself, or the two will disagree about which panel is showing.
<aside class="sidebar sidebar--areas" style="height:520px">
<div class="nav-areas">
<div class="brand">
<div class="brand-logo" style="background:var(--brand)"></div>
<div class="brand-text">
<strong>Dispatch Console</strong>
<span class="brand-sub">Northwind Retail</span>
</div>
</div>
<nav class="nav-areas-list" aria-label="Areas">
<button class="nav-area" type="button" aria-controls="dispatch-area-orders" aria-expanded="true" data-nav-area><i class="ri-inbox-line"></i><span>Orders</span></button>
<button class="nav-area" type="button" aria-controls="dispatch-area-stock" aria-expanded="false" data-nav-area><i class="ri-archive-stack-line"></i><span>Stock</span></button>
<button class="nav-area" type="button" aria-controls="dispatch-area-shipping" aria-expanded="false" data-nav-area><i class="ri-truck-line"></i><span>Shipping</span></button>
<button class="nav-area" type="button" aria-controls="dispatch-area-admin" aria-expanded="false" data-nav-area><i class="ri-settings-3-line"></i><span>Admin</span></button>
</nav>
</div>
<nav class="nav" id="dispatch-area-orders" aria-label="Orders">
<div class="nav-area-title">Orders</div>
<div class="nav-scroll">
<a class="nav-link active" href="#" aria-current="page"><span>Queue</span><span class="nav-count">3</span></a>
<a class="nav-link" href="#"><span>On hold</span></a>
<a class="nav-link" href="#"><span>Returns</span></a>
<div class="nav-section">
<span class="nav-section-label">History</span>
<a class="nav-link" href="#"><span>Decided</span></a>
<a class="nav-link" href="#"><span>Exports</span></a>
</div>
</div>
<div class="nav-tools">
<a class="nav-link nav-link-tool" href="#"><i class="ri-book-2-line"></i><span>Documentation</span><i class="ri-external-link-line nav-link-ext"></i></a>
</div>
</nav>
<nav class="nav" id="dispatch-area-stock" aria-label="Stock" hidden>
<div class="nav-area-title">Stock</div>
<div class="nav-scroll">
<a class="nav-link" href="#"><span>Items</span></a>
<a class="nav-link" href="#"><span>Locations</span></a>
<div class="nav-section">
<span class="nav-section-label">Movements</span>
<a class="nav-link" href="#"><span>Transfers</span></a>
<a class="nav-link" href="#"><span>Stock counts</span></a>
</div>
</div>
</nav>
<nav class="nav" id="dispatch-area-shipping" aria-label="Shipping" hidden>
<div class="nav-area-title">Shipping</div>
<div class="nav-scroll">
<a class="nav-link" href="#"><span>Carriers</span></a>
<a class="nav-link" href="#"><span>Labels</span></a>
<a class="nav-link" href="#"><span>Pickups</span></a>
</div>
</nav>
<nav class="nav" id="dispatch-area-admin" aria-label="Administration" hidden>
<div class="nav-area-title">Administration</div>
<div class="nav-scroll">
<a class="nav-link" href="#"><span>Users</span></a>
<a class="nav-link" href="#"><span>Roles</span></a>
<a class="nav-link" href="#"><span>API keys</span></a>
<a class="nav-link" href="#"><span>Audit log</span></a>
</div>
</nav>
</aside>
Collapsed area rail
.collapsed keeps the rail and drops the panel, so the collapsed width is the
rail's own, --nav-areas-width. With no panel to swap, each area is a
link to its first page, marked current with .active as
ActiveLink writes it. Use this form whenever the sidebar can collapse, and under
.layout--responsive, which collapses it below 900px.
<aside class="sidebar sidebar--areas collapsed" style="height:360px">
<div class="nav-areas">
<div class="brand">
<div class="brand-logo" style="background:var(--brand)"></div>
<div class="brand-text">
<strong>Dispatch Console</strong>
<span class="brand-sub">Northwind Retail</span>
</div>
</div>
<nav class="nav-areas-list" aria-label="Areas">
<a class="nav-area active" href="#" aria-current="page"><i class="ri-inbox-line"></i><span>Orders</span></a>
<a class="nav-area" href="#"><i class="ri-archive-stack-line"></i><span>Stock</span></a>
<a class="nav-area" href="#"><i class="ri-truck-line"></i><span>Shipping</span></a>
<a class="nav-area" href="#"><i class="ri-settings-3-line"></i><span>Admin</span></a>
</nav>
</div>
<nav class="nav" aria-label="Orders">
<div class="nav-area-title">Orders</div>
<div class="nav-scroll">
<a class="nav-link active" href="#" aria-current="page"><span>Queue</span><span class="nav-count">3</span></a>
<a class="nav-link" href="#"><span>On hold</span></a>
<a class="nav-link" href="#"><span>Returns</span></a>
</div>
</nav>
</aside>
Areas in the topbar
.topbar-nav holds one .topbar-nav-link per area, and the sidebar
lists only the current area's pages. They are links, not tabs: an area
has an address. Give each link the address its area's pages share, and
ActiveLink's prefix match marks it current on every page inside. The row scrolls
sideways rather than wrapping when the header is narrow.
<div class="layout" style="height:460px; overflow:hidden">
<aside class="sidebar">
<div class="brand">
<div class="brand-logo" style="background:var(--brand)"></div>
<div class="brand-text">
<strong>Dispatch Console</strong>
<span class="brand-sub">Northwind Retail</span>
</div>
</div>
<nav class="nav" aria-label="Stock">
<div class="nav-scroll">
<a class="nav-link active" href="#" aria-current="page"><i class="ri-price-tag-3-line"></i><span>Items</span></a>
<a class="nav-link" href="#"><i class="ri-map-pin-line"></i><span>Locations</span></a>
<div class="nav-section">
<span class="nav-section-label">Movements</span>
<a class="nav-link" href="#"><i class="ri-arrow-left-right-line"></i><span>Transfers</span></a>
<a class="nav-link" href="#"><i class="ri-list-check-3"></i><span>Stock counts</span></a>
</div>
</div>
</nav>
</aside>
<div class="content">
<header class="topbar">
<nav class="topbar-nav" aria-label="Areas">
<a class="topbar-nav-link" href="#">Orders</a>
<a class="topbar-nav-link active" href="#" aria-current="page">Stock</a>
<a class="topbar-nav-link" href="#">Shipping</a>
<a class="topbar-nav-link" href="#">Reports</a>
<a class="topbar-nav-link" href="#">Administration</a>
</nav>
<div class="topbar-spacer"></div>
<button class="topbar-btn" aria-label="Help" data-tip="What is this console?"><i class="ri-question-line"></i></button>
</header>
<div class="page">
<h1>Items</h1>
<p class="lede">Everything the warehouse can hold, where it sits, and how many are on the shelf.</p>
</div>
</div>
</div>