name: build-app-layout description: Use this skill for any task involving app layouts — building new layouts, adding sidebars or navigation to existing apps, migrating an existing layout to mui-treasury components, or reviewing/improving layout structure. Trigger whenever the user mentions dashboard layout, sidebar navigation, app shell, header/footer/content structure, collapsible sidebar, drawer navigation, layout with sidebar, or asks to "build a layout", "add a sidebar", "set up the app layout", "review the layout". Also trigger when a mockup or design shows an app with sidebar + header + content regions, even if the user doesn't say "layout" explicitly.
Installation
Components are installed via the mui-treasury CLI into src/mui-treasury/:
# Layout core (Root, Header, Content, Footer, EdgeSidebar, InsetSidebar, etc.)
npx mui-treasury@latest add layout-core
# Sidebar primitives (SidebarContainer, SidebarMenuButton, SidebarIcon, etc.)
npx mui-treasury@latest add sidebar
After installation, import from:
@/mui-treasury/layout/layout-core— layout components@/mui-treasury/components/sidebar— sidebar primitives
Recommended Defaults
Use these as starting values unless the user specifies otherwise.
Collapsible EdgeSidebar
collapsedWidth: "52px"SidebarIcon shrinkSize="20px"to center icons in the collapsed sidebarpermanentAutoCollapse="lg"to auto-collapse below thelgbreakpoint<EdgeSidebarCollapser render={<SidebarRail />} />as a click-to-collapse trigger —SidebarRailis a pure visual component,EdgeSidebarCollapserinjects the collapse onClick- Use sidebar primitives for sidebar content — they auto-adapt to collapsed state
- left/right arrow icons for
EdgeSidebarCollapser - down arrow icon for
CollapsibleIcon
EdgeSidebar Content Structure
Place SidebarContainer in the middle of EdgeSidebarContent so it grows to fill available space and becomes the scrollable area for menus. Static-height content (sidebar header/footer) should be siblings of SidebarContainer:
EdgeSidebarContent
├── Sidebar header (static) — e.g. app switcher, logged-in user, logo
├── SidebarContainer (flex: 1, scrollable) — navigation menus
└── Sidebar footer (static) — e.g. user preferences, settings, ads/banner
EdgeSidebarContentusesdisplay: flex; flex-direction: columnby defaultSidebarContainergrows viaflex: 1and handles its own overflow scroll- Sidebar header/footer keep their natural height and never scroll
- Sidebar primitives (
SidebarMenuButton,SidebarIcon, etc.) still work in the header/footer areas because they are descendants ofEdgeSidebar— but collapse-aware CSS variables (--_collapsed/--_uncollapsed) only work insideSidebarContainer
SidebarMenuButton
should use the
componentprop for polymorphism, e.g.<SidebarMenuButton component="a" href="/dashboard">or<SidebarMenuButton component={Link} to="/dashboard">MUST be a child of
SidebarMenuItemwhich is a child ofSidebarMenuList. Never wrapSidebarMenuButtonin a plaindivorBox— the list structure (SidebarMenuList > SidebarMenuItem > SidebarMenuButton) is required for proper spacing, collapse behavior, and accessibilityNever use consecutive
SidebarTextsiblings inside aSidebarMenuButton. For multi-line text, use a singleSidebarTextwrapping the content. For two-line text labels, useSidebarGroupText:// ❌ Wrong — consecutive SidebarText <SidebarMenuButton> <Avatar /> <SidebarText><Typography>siriwatknp</Typography></SidebarText> <SidebarText><Typography>admin@acme.com</Typography></SidebarText> </SidebarMenuButton> // ✅ Correct — single SidebarText with SidebarGroupText for 2 lines <SidebarMenuButton> <Avatar /> <SidebarText> <SidebarGroupText> <Typography variant="body2">siriwatknp</Typography> <Typography variant="caption">admin@acme.com</Typography> </SidebarGroupText> </SidebarText> </SidebarMenuButton>Never place secondary actions (e.g.
IconButton,Badge) insideSidebarMenuButton. UseSidebarMenuActionas a sibling:// ❌ Wrong — actions inside SidebarMenuButton <SidebarMenuItem> <SidebarMenuButton> <Avatar /> <SidebarText>siriwatknp</SidebarText> <Box sx={{ display: "flex", gap: 0.5 }}> <IconButton size="small"><MoreHorizRounded /></IconButton> <IconButton size="small"><NotificationsRounded /></IconButton> </Box> </SidebarMenuButton> </SidebarMenuItem> // ✅ Correct — SidebarMenuAction as sibling <SidebarMenuItem> <SidebarMenuButton> <Avatar /> <SidebarText>siriwatknp</SidebarText> </SidebarMenuButton> <SidebarMenuAction> <IconButton size="small"><MoreHorizRounded /></IconButton> <IconButton size="small"><NotificationsRounded /></IconButton> </SidebarMenuAction> </SidebarMenuItem>Never make
SidebarMenuButtonnon-interactive (e.g.component="div"withcursor: "default"). If the element is not clickable, useSidebarMenuItemdirectly instead:// ❌ Wrong — non-interactive button <SidebarMenuButton component="div" sx={{ cursor: "default", "&:hover": { bgcolor: "transparent" } }}> <Avatar /> <SidebarText>siriwatknp</SidebarText> </SidebarMenuButton> // ✅ Correct — use SidebarMenuItem for non-interactive content <SidebarMenuItem> <Avatar /> <SidebarText>siriwatknp</SidebarText> </SidebarMenuItem>SidebarMenuActionmust only be used alongside aSidebarMenuButtonsibling. If there is noSidebarMenuButton, use a plainIconButtoninstead
Rules of Thumb
Don't use
hoverUncollapsewithEdgeSidebarRail— they are noy designed to work together and can cause janky behaviorDon't use
hoverUncollapsewithSidebarTooltip— tooltips won't show when the sidebar is collapsed, so the hover state becomes inaccessibleIt's recommended to have only one
SidebarContaineras a direct child ofEdgeSidebar— having multiple containers will cause the available space to split evenly, which mostly not the desired behavior.Align icons in the center of the collapsed sidebar with proper
shrinkSizeonSidebarIcon.Align custom elements like avatar in the center of the collapsed sidebar using negative margins with EdgeSidebar variables (see EdgeSidebar Collapsible Variables guide)
On pages that use
EdgeDrawerTriggerbut have no sidebar, add<EdgeSidebar variant={['permanent', { visibility: 'hidden' }]} />to hide the trigger — permanent mode auto-hidesEdgeDrawerTrigger, andvisibility: 'hidden'prevents the sidebar from taking visual spaceTo create a floating sidebar (with margin, border, shadow, rounded corners), never apply these styles directly to
EdgeSidebarContent— it breaks the layout. Instead, makeEdgeSidebarContenttransparent and style a childdiv:<EdgeSidebarContent className="bg-transparent"> <div className="m-2 border shadow-xl rounded-lg bg-background flex flex-col"> {sidebar} </div> </EdgeSidebarContent>
Documentation
Read the relevant page based on your needs:
- Tutorials — Step-by-step lessons to build your first layout. Start here if unfamiliar with the layout system.
- Reference Guides — Complete API for all layout-core components and sidebar primitives with props tables.
- Explanation — Architecture decisions: CSS Grid + CSS variables, how collapse works, EdgeSidebar vs InsetSidebar, term mappings.
How-to Guides
Integration:
- Next.js Integration — Set up layout in App Router with layout.tsx/page.tsx split, MUI Treasury theme
Layout patterns:
- Dashboard Layout — Collapsible left sidebar, drawer on mobile, permanent on desktop
- Chat/Messenger Layout — Permanent sidebar for conversation list, standalone scrollable content, InsetSidebar for details
- Blog/Content Layout — Sticky InsetSidebar for table of contents, no EdgeSidebar
- Shopping Cart / Right Sidebar — Right-side drawer for cart/checkout panel
Sidebar features:
- Header Clipping — Make the header span over the sidebar for full-height sidebar
- Nested Popup Menus (3 Levels) — Multi-level flyout menus when sidebar is collapsed, with collapsible fallback when uncollapsed
- EdgeSidebar Collapsible Variables — Use
--_collapsed/--_uncollapsedCSS variables to style non-mui-treasury elements based on sidebar state
Demos:
- Iframe Preview for Responsive Demos — Configure demos that showcase responsive behavior