Advanced Layout
Advanced Layout: anatomy, keyboard behavior, state, and theming in Askr.
Example
import { Block, Grid } from '@askrjs/themes/components';
<Grid columns={{ base: 1, md: 3 }} gap="lg">
<Block style={{ gridColumn: 'span 2' }}><ProjectTimeline /></Block>
<Block><ProjectSummary /></Block>
</Grid>Purpose
This page extends Layout Primitives into more involved shells — persistent sidebars, nested content regions, and multi-panel apps — using the same Block-based primitives plus Sidebar and its parts. As with Layout Primitives, there's no single component to reach for; it's a set of composable pieces and a recommended way to combine them.
Install and import
Sidebar, SidebarContent, SidebarHeader, SidebarFooter, SidebarGroup, SidebarGroupLabel, SidebarGroupContent, SidebarMenu, SidebarMenuItem, SidebarMenuButton, SidebarMenuAction, SidebarMenuBadge, SidebarRail, SidebarScope, SidebarInset, and SidebarTrigger all come from @askrjs/themes/sidebar (also available through the @askrjs/themes/components barrel). Combine them with Block, Header, and Main from that same @askrjs/themes/components barrel for the surrounding shell — there is no separate @askrjs/themes/core subpath; that name doesn't exist in the package.
Live examples
A standard admin layout is SidebarScope wrapping a Sidebar (with SidebarHeader, SidebarContent full of SidebarGroup/SidebarMenu entries, and SidebarFooter) alongside a SidebarInset holding the routed page content, with SidebarTrigger somewhere in the header to toggle it. Set collapsible="icon" on Sidebar when you want it to shrink to an icon rail instead of disappearing entirely on collapse.
Anatomy
Sidebar itself renders as an aside and accepts side ('left' | 'right'), variant ('sidebar' | 'floating' | 'inset'), and collapsible ('offcanvas' | 'icon' | 'none'). Inside it, SidebarGroup clusters related SidebarMenuItems under an optional SidebarGroupLabel, and SidebarMenuButton/SidebarMenuAction are the actual interactive rows and trailing controls within each item.
State model
SidebarScope is a pure styling/CSS-boundary wrapper — it renders a plain part with no state of its own. It does not coordinate open/closed or rail-expanded state across Sidebar and SidebarTrigger; there's no built-in mechanism tracking that. You own collapse state yourself (a state() cell, driven by clicking SidebarTrigger, controlling whatever prop or class toggles the collapsed styling) the same way you would with any other composable primitive here — don't assume wrapping things in SidebarScope gets you that behavior for free. Individual SidebarMenuButtons and SidebarMenuActions take an active?: boolean prop for marking the current route, which is a value you compute from your router, not something the component derives on its own.
Keyboard and accessibility
SidebarMenuButton and SidebarTrigger accept tooltip and tooltipSide props, which matter most in the collapsed icon-rail state where the label text is hidden — always set a tooltip so icon-only buttons still communicate their purpose to sighted users and, indirectly, screen reader users relying on the accessible name. As with any nav structure, keep SidebarMenuButton rendered as real buttons or links rather than divs with click handlers, so keyboard and screen reader navigation work without extra effort.
Styling and tokens
The variant prop's three values — sidebar, floating, inset — control fairly different visual treatments (attached, elevated-and-detached, or content-inset), and switching between them is a token-driven style change rather than a structural one. SidebarMenuButton's size ('default' | 'sm' | 'lg') and variant ('default' | 'outline') follow the same density and variant conventions as Button, so a sidebar built from these components looks native next to the rest of the theme rather than like a separate design language.
API
SidebarProps omits as, width, and shrink from the general BlockElementProps<'aside'> shape and re-adds typed versions of width and shrink, plus collapsible, side, and variant. SidebarButtonProps (used by SidebarMenuButton and SidebarMenuAction) adds active, asChild, size, tooltip, tooltipSide, and variant on top of native button attributes. The remaining Sidebar* parts (SidebarContent, SidebarHeader, SidebarFooter, SidebarGroup, etc.) take SidebarPartProps — just as, asChild, and native div attributes.
Edge cases
A collapsible="none" sidebar ignores SidebarTrigger entirely from a visual standpoint, so don't render a trigger for a sidebar that isn't meant to collapse — it'll be misleading UI. Deeply nested SidebarGroups inside SidebarGroups aren't part of the documented shape; keep groups to one level and use SidebarMenu/SidebarMenuItem for the actual hierarchy of links within a group.
Related pages
Layout Primitives covers the simpler header-and-main shell this page builds on top of. NavigationMenu and Navbar are worth comparing for top-nav-driven apps that don't need a persistent side panel. Item and ItemGroup are a reasonable alternative to SidebarMenu when you need list rows that aren't specifically navigation.