AppSidebarMenu
A slide-in drawer for filters, details, or mobile navigation — behavior borrowed from Offcanvas.
<app-sidebar-menu id="filters" title="Filters" side="end">…</app-sidebar-menu>A sidebar menu is a panel that slides in from an edge — a filter tray, a details pane, a mobile navigation drawer. <app-sidebar-menu> renders Bootstrap's offcanvas, so the backdrop, slide animation, background scroll-lock, Escape-to-close and focus trap all come for free — none of it is hand-rolled.
Its look comes entirely from the shared @webority/theme, so the Razor <app-sidebar-menu> and the React <AppSidebarMenu> render identically. It's an overlay: open it from a trigger. In Razor that's any element carrying data-bs-toggle="offcanvas" data-bs-target="#id".
Playground
Every attribute, live. Each change re-renders the real tag helper on the server, so the markup underneath is the exact call that produced the drawer above it.
backdrop also accepts "static" (a dimmed backdrop that ignores clicks — Escape or the × still close it). The Razor tag helper's Backdrop is bool only, so that middle state has no Razor equivalent today.A basic drawer
A header (icon + title + close), a body, and an optional footer for actions. The trigger points at the panel's id.
Show code
<app-button data-bs-toggle="offcanvas" data-bs-target="#scFilterDrawer">Open filters</app-button>
<app-sidebar-menu id="scFilterDrawer" title="Filters" title-icon="settings" side="end">
<p class="wui-text-sm">Drawer body — forms, filters, details.</p>
<div class="d-flex gap-2 justify-content-end mt-3">
<app-button variant="ghost" data-bs-dismiss="offcanvas">Reset</app-button>
<app-button variant="primary" data-bs-dismiss="offcanvas">Apply</app-button>
</div>
</app-sidebar-menu>
<app-sidebar-menu> instead of a hand-rolled drawer so you never re-implement — or get wrong — that accessibility wiring.Sides
side picks the edge it slides from. end suits filters and details beside the content; start suits a navigation drawer.
Show code
<app-sidebar-menu id="scNavDrawer" title="Menu" title-icon="menu" side="start">…</app-sidebar-menu> <app-sidebar-menu id="scFilterDrawer" title="Filters" title-icon="settings" side="end">…</app-sidebar-menu>
Width & max width
width sets the panel's target size; max-width caps it so a wide fixed width still fits a small viewport (default 92vw). On a phone (below 576px) a side panel opens at the full screen width.
Show code
<app-sidebar-menu id="scWideDrawer" title="Details" title-icon="info" width="640px" max-width="90vw">…</app-sidebar-menu>
When to use
Use it when
- A filter or details panel that slides in beside the current content (side="end").
- A navigation drawer, especially the collapsed mobile menu (side="start").
- You want a panel that behaves accessibly below a breakpoint and inline above it.
Reach for something else when
- It's a self-contained task or form in a centred card. → AppModal
- It's a yes/no confirmation. → AppConfirmDialog
- It's a small menu of actions behind one trigger. → AppDropdown
- It's a transient message. → a toast
Best practices
Every option
The whole surface of the component, one cell per value — every side, the header/footer slots, and every behavior flag.
side — all six values
side="left"
side="right"
side="start"
side="end"
side="top"
side="bottom"
titleIcon / title-icon
title-icon="settings"
(no title-icon)
header / app-sidebar-header — a custom node replaces the default title bar
<app-sidebar-header>…</app-sidebar-header>
close-button="false" (no title, no default header)
footer / app-sidebar-footer
<app-sidebar-footer>…</app-sidebar-footer>
(no app-sidebar-footer)
backdrop — true (default) · false · "static" (React) / true (default) · false (Razor is bool-only)
backdrop (default true)
backdrop="false"
scroll
scroll (default false — page locked)
scroll="true"
keyboard & closeButton / close-button
keyboard="false"
close-button="false"
width & maxWidth / max-width
width="640px"
width="640px" max-width="90vw"
responsive — inline at/above the breakpoint
responsive="lg"
Attributes
| Attribute | Type | Default | Description |
|---|---|---|---|
| id | string | — | The panel id a trigger points at with data-bs-target. |
| title | string | — | Default header title. |
| side | left | right | start | end | top | bottom | right | Edge the panel slides from — right/end for filters/details, left/start for navigation. |
| (content) | markup | — | The panel body — forms, filters, details, and any footer actions. |
| title-icon | string | — | Bootstrap Icons glyph beside the title (React titleIcon). |
| <app-sidebar-header> | markup | — | Custom header child that replaces the default title bar entirely (React header). |
| <app-sidebar-footer> | markup | — | Sticky action bar child at the bottom of the panel (React footer). |
| aria-label | string | — | Accessible name for the dialog (React ariaLabel), defaulting to the title. |
| width | string | — | Panel width, e.g. "420px" (React width). |
| max-width | string | 92vw | Caps the panel width, e.g. "600px" (React maxWidth). |
| backdrop | bool | true | Show the dimming backdrop (React backdrop, default true). Razor is bool-only — React's backdrop="static" (dimmed, click-through-proof) has no Razor equivalent. |
| scroll | bool | false | Allow the page behind to scroll (React scroll). |
| keyboard | bool | true | Close on Escape (React keyboard, default true). |
| close-button | bool | true | Render the header close button (React closeButton, default true). |
| responsive | string | — | Breakpoint below which it behaves as an offcanvas, e.g. "lg" (React responsive). |
| body-class-name | string | — | Classes on the scrollable body region (React bodyClassName). |