A sidebar is a CSS layout pattern, not a custom element. At
≥ lg (48em / 768px) the
sidebar sits next to the main content as a persistent
<aside>. Below that the aside is hidden and a hamburger
button opens the same content inside a
<ui-dialog>. CSS handles the
swap; JS just opens the dialog when the button is clicked — no viewport
detection in script.
Resize the window across 48em (768px).
At ≥ 48em the shell shows a persistent
<aside>; below that, the aside disappears and the
hamburger button in the top bar becomes visible. Click it to open the
nav inside a dialog. (The dialog also auto-converts to a bottom-sheet
presentation at ≤ 640px — that's a built-in
<ui-dialog> behavior, see
Dialog §6 Sizing.)
Resize the viewport across 48em (768px) — the aside collapses below 48em and the hamburger button appears in the top bar.
The persistent <aside> and the dialog hold the same
content. For static nav items duplicating the markup is fine. If the list
is dynamic, render once into a <template> and clone
into both, or move the same DOM between them on toggle.
Two-column grid at lg and above; single-column with the
aside hidden below. The hamburger has the inverse visibility — visible
only when the aside is hidden.
Just open the dialog when the button is clicked. No viewport detection,
no matchMedia. The hamburger button is only visible when the
aside is hidden, so a click always means "open the drawer."
A sidebar has no element of its own in the systems this library maps to:
the cross-system reference lists it
under Layout as plain CSS layout, with Bootstrap's Offcanvas as the nearest
packaged equivalent. A <ui-sidebar> here would mostly
forward to <aside> and a media query, and this library uses plain CSS when a wrapper component would add no behavior. This guide documents the pattern so each application can choose its own structure.
<aside> with
aria-label describing what it contains
("Sections", "Navigation", …). Screen readers announce it as a
complementary landmark.<button type="button"> with
an aria-label so its purpose is read by screen readers.<ui-dialog> takes care of focus trap, ESC dismissal,
backdrop click, and returning focus to the trigger on close — see
Dialog.aria-current="page" on
its <a>; the same attribute drives the visual
treatment, so the keyboard / screen-reader signal and the visual
signal can never drift apart.lg threshold this pattern uses.≤ 640px.<aside> that slides out at its own edge instead of collapsing into a dialog.list (hamburger).