SidebarLayoutcomponent
SidebarLayout({ sidebar, children, right = false }: SidebarLayoutProps): ReactElement| Param | Type | |
|---|---|---|
props | SidebarLayoutProps | Props for <SidebarLayout> — the sidebar column content, main children, and a right placement flag. required |
.sidebar | ReactNode | Content rendered in the fixed-width side column. required |
.right | boolean | Render the sidebar on the right rather than the left. |
| Return | |
|---|---|
ReactElement |
Layout with a fixed-width side column (typically navigation) next to a scrollable main content column.
- The sidebar is rendered as
<nav>— it almost always contains the page's primary navigation. - On narrow viewports the sidebar becomes an off-canvas drawer toggled by a single menu button that switches between a burger and a close icon.
- While the drawer is open an overlay dims the rest of the page; clicking the overlay closes the drawer.
- Inside a
<Navigation>the drawer closes itself whenever the route changes (e.g. tapping a sidebar link). - The scrollable content column is kept alive across navigation via
<RouteCache>, so returning to a recently-visited page restores its scroll position and state; the sidebar stays mounted throughout.
A full-viewport layout with a fixed-width side column next to a scrollable main content column. The sidebar renders as a <nav> landmark — it almost always holds the primary navigation. On narrow viewports it collapses to an off-canvas drawer toggled by a single burger/close button.
Things to know:
- Pass
rightto place the sidebar on the right rather than the left. - The sidebar renders as
<nav>, so it is a navigation landmark without extra markup — drop a<Menu>inside it. - While the drawer is open an overlay dims the page; clicking the overlay closes it.
- Under
prefers-reduced-motion: reducethe drawer snaps open/closed instead of sliding off-canvas; the overlay keeps its dimming fade, which is opacity-only and therefore reduced-motion-safe. - Inside a
<Navigation>context the drawer closes itself whenever the route changes (e.g. tapping a sidebar link). - The layout owns scroll, padding, and safe-area insets so individual pages don't have to.
Usage
import { SidebarLayout, Menu, MenuItem, Router } from "shelving/ui";
function AppShell() {
const nav = (
<Menu>
<MenuItem href="/dashboard">Dashboard</MenuItem>
<MenuItem href="/users">Users</MenuItem>
<MenuItem href="/settings">Settings</MenuItem>
</Menu>
);
return (
<SidebarLayout sidebar={nav}>
<Router routes={ROUTES}/>
</SidebarLayout>
);
}Layouts compose naturally as <Router> route values — wrap a group of routes in a shared layout, then route further inside it.
Styling
| Variable | Styles | Default |
|---|---|---|
--sidebar-layout-width | Width of the side column (and drawer) | 17.5rem |
--sidebar-layout-background | Page background while the layout is mounted (also fills the content column) | var(--tint-100) (white) |
--sidebar-layout-color | Text colour for the layout (set on body, inherited by the content column) | var(--tint-00) (black) |
--sidebar-layout-sidebar-background | Sidebar column fill | var(--tint-90) (one shade darker than the page) |
--sidebar-layout-sidebar-color | Sidebar column text colour | var(--tint-00) (black) |
--sidebar-layout-border | Divider between sidebar and content | var(--stroke-normal) solid var(--tint-80) |
The sidebar and content columns own their own scroll behaviour directly (this layout no longer composes a shared .layout class).
Global tokens it reads — --tint-00 / --tint-80 / --tint-90 / --tint-100, plus --space-normal, --stroke-normal, --duration-normal, and --color-shadow.