Skip to content
Browse documentation
DocsComponents

Layout

The structure for app bars, navigation drawers, and content panels.

Your workspace

A place for everything.

Installation

Terminal
pnpm dlx shadcn@latest add https://react-toolbox.io/r/layout.json

New here? Set up your project first. Styles, fonts, and required components are included.

Usage

Compose Layout with Panel, NavDrawer, and Sidebar. Use pinned on a navigation drawer to make room for it in the layout instead of placing it over content.

Use the Code tab above for a complete example. The import follows your configured UI alias. See Theming to customize colors, spacing, and style slots.

State and callbacks

Layout and Panel structure the page. Your application owns NavDrawer and Sidebar active and pinned props; permanentAt applies the selected responsive breakpoint automatically.

Panel uses document scrolling by default (bodyScroll). Set bodyScroll to false only when the panel needs its own scroll container.

API reference

Generated from the installed TypeScript source. Defaults are the values declared by each function; a dash means no parameter default is declared. Forwarded props can use the receiving component’s default. Callback types show the exact arguments passed to your handler.

Layout

PropertyTypeDefault
classNamesLayoutTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasLayoutTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—

Also inherits ComponentPropsWithRef<'div'>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • appbarAppBar
  • appbarFixed
  • appbarInner
  • appbarLeftIcon
  • bodyScroll
  • clipped
  • layout
  • navDrawerClipped
  • navDrawerDrawer
  • navDrawerPinned
  • navDrawerWrapper
  • panel
  • pinned
  • sidebarClipped
  • sidebarDrawer
  • sidebarPinned
  • sidebarWidth1
  • sidebarWidth10
  • sidebarWidth100
  • sidebarWidth11
  • sidebarWidth12
  • sidebarWidth2
  • sidebarWidth25
  • sidebarWidth3
  • sidebarWidth33
  • sidebarWidth4
  • sidebarWidth5
  • sidebarWidth50
  • sidebarWidth6
  • sidebarWidth66
  • sidebarWidth7
  • sidebarWidth75
  • sidebarWidth8
  • sidebarWidth9
  • sidebarWrapper

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

NavDrawer

PropertyTypeDefault
activeboolean—
delaynumber—
insideTreeboolean—
type'left' | 'right'—
withOverlayboolean—
refRef<HTMLElement>—
clippedboolean—
permanentAtLayoutBreakpoint—
pinnedbooleanfalse
classNamesLayoutTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasLayoutTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—

Callbacks

PropertyTypeDefault
onOverlayClickMouseEventHandler<HTMLDivElement>—
onEscKeyDown(event: KeyboardEvent) => void—

Also inherits Omit<HTMLAttributes<HTMLElement>, 'theme' | 'classNames'>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Additional defaults on inherited props: className = ''.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • appbarAppBar
  • appbarFixed
  • appbarInner
  • appbarLeftIcon
  • bodyScroll
  • clipped
  • layout
  • navDrawerClipped
  • navDrawerDrawer
  • navDrawerPinned
  • navDrawerWrapper
  • panel
  • pinned
  • sidebarClipped
  • sidebarDrawer
  • sidebarPinned
  • sidebarWidth1
  • sidebarWidth10
  • sidebarWidth100
  • sidebarWidth11
  • sidebarWidth12
  • sidebarWidth2
  • sidebarWidth25
  • sidebarWidth3
  • sidebarWidth33
  • sidebarWidth4
  • sidebarWidth5
  • sidebarWidth50
  • sidebarWidth6
  • sidebarWidth66
  • sidebarWidth7
  • sidebarWidth75
  • sidebarWidth8
  • sidebarWidth9
  • sidebarWrapper

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

Sidebar

PropertyTypeDefault
activeboolean—
delaynumber—
insideTreeboolean—
type'left' | 'right'—
withOverlayboolean—
refRef<HTMLElement>—
clippedboolean—
permanentAtLayoutBreakpoint—
pinnedbooleanfalse
classNamesLayoutTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasLayoutTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—
widthSidebarWidth—

Callbacks

PropertyTypeDefault
onOverlayClickMouseEventHandler<HTMLDivElement>—
onEscKeyDown(event: KeyboardEvent) => void—

Also inherits Omit<HTMLAttributes<HTMLElement>, 'theme' | 'classNames'>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Additional defaults on inherited props: className = ''.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • appbarAppBar
  • appbarFixed
  • appbarInner
  • appbarLeftIcon
  • bodyScroll
  • clipped
  • layout
  • navDrawerClipped
  • navDrawerDrawer
  • navDrawerPinned
  • navDrawerWrapper
  • panel
  • pinned
  • sidebarClipped
  • sidebarDrawer
  • sidebarPinned
  • sidebarWidth1
  • sidebarWidth10
  • sidebarWidth100
  • sidebarWidth11
  • sidebarWidth12
  • sidebarWidth2
  • sidebarWidth25
  • sidebarWidth3
  • sidebarWidth33
  • sidebarWidth4
  • sidebarWidth5
  • sidebarWidth50
  • sidebarWidth6
  • sidebarWidth66
  • sidebarWidth7
  • sidebarWidth75
  • sidebarWidth8
  • sidebarWidth9
  • sidebarWrapper

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

Panel

PropertyTypeDefault
bodyScrollbooleantrue
classNamesLayoutTheme

Classes for the component's rendered parts. Applied after legacy theme overrides.

—
themeDeprecated aliasLayoutTheme

Use classNames for style slots; use ThemeProvider for design tokens.

—

Also inherits ComponentPropsWithRef<'div'>, except the omissions and overrides in its exported props type below. Use the supported native aria-*, data-*, event, and element attributes as appropriate.

Additional defaults on inherited props: className = ''.

Style slots

Pass a map of Tailwind classes to classNames. Available keys:

  • appbarAppBar
  • appbarFixed
  • appbarInner
  • appbarLeftIcon
  • bodyScroll
  • clipped
  • layout
  • navDrawerClipped
  • navDrawerDrawer
  • navDrawerPinned
  • navDrawerWrapper
  • panel
  • pinned
  • sidebarClipped
  • sidebarDrawer
  • sidebarPinned
  • sidebarWidth1
  • sidebarWidth10
  • sidebarWidth100
  • sidebarWidth11
  • sidebarWidth12
  • sidebarWidth2
  • sidebarWidth25
  • sidebarWidth3
  • sidebarWidth33
  • sidebarWidth4
  • sidebarWidth5
  • sidebarWidth50
  • sidebarWidth6
  • sidebarWidth66
  • sidebarWidth7
  • sidebarWidth75
  • sidebarWidth8
  • sidebarWidth9
  • sidebarWrapper

theme is the deprecated compatibility alias. When both are provided, classNames wins conflicting utilities within each slot. See Theming for tokens and override rules.

Exported TypeScript types

Expand a type to inspect its full declaration, including generic constraints, union branches, callback arguments, ref handles, and inherited props. Import these types from @/components/ui/material/layout.

LayoutProps
tsx
interface LayoutProps extends ComponentPropsWithRef<'div'> {
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: LayoutTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: LayoutTheme;
}
NavDrawerProps
tsx
interface NavDrawerProps extends Omit<DrawerProps, 'theme' | 'classNames'> {
  clipped?: boolean;
  permanentAt?: LayoutBreakpoint;
  pinned?: boolean;
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: LayoutTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: LayoutTheme;
}
SidebarProps
tsx
interface SidebarProps extends Omit<DrawerProps, 'theme' | 'classNames'> {
  clipped?: boolean;
  permanentAt?: LayoutBreakpoint;
  pinned?: boolean;
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: LayoutTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: LayoutTheme;
  width?: SidebarWidth;
}
PanelProps
tsx
interface PanelProps extends ComponentPropsWithRef<'div'> {
  bodyScroll?: boolean;
  /** Classes for the component's rendered parts. Applied after legacy theme overrides. */
  classNames?: LayoutTheme;
  /** @deprecated Use classNames for style slots; use ThemeProvider for design tokens. */
  theme?: LayoutTheme;
}
LayoutTheme
tsx
type LayoutTheme = Partial<
  Record<
    | 'appbarAppBar'
    | 'appbarFixed'
    | 'appbarInner'
    | 'appbarLeftIcon'
    | 'bodyScroll'
    | 'clipped'
    | 'layout'
    | 'navDrawerClipped'
    | 'navDrawerDrawer'
    | 'navDrawerPinned'
    | 'navDrawerWrapper'
    | 'panel'
    | 'pinned'
    | 'sidebarClipped'
    | 'sidebarDrawer'
    | 'sidebarPinned'
    | 'sidebarWidth1'
    | 'sidebarWidth10'
    | 'sidebarWidth100'
    | 'sidebarWidth11'
    | 'sidebarWidth12'
    | 'sidebarWidth2'
    | 'sidebarWidth25'
    | 'sidebarWidth3'
    | 'sidebarWidth33'
    | 'sidebarWidth4'
    | 'sidebarWidth5'
    | 'sidebarWidth50'
    | 'sidebarWidth6'
    | 'sidebarWidth66'
    | 'sidebarWidth7'
    | 'sidebarWidth75'
    | 'sidebarWidth8'
    | 'sidebarWidth9'
    | 'sidebarWrapper',
    string
  >
>;
LayoutClassNames
tsx
type LayoutClassNames = LayoutTheme;
LayoutBreakpoint
tsx
type LayoutBreakpoint = 'sm' | 'smTablet' | 'md' | 'lg' | 'lgTablet' | 'xl' | 'xxl' | 'xxxl';
SidebarWidth
tsx
type SidebarWidth = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 25 | 33 | 50 | 66 | 75 | 100;

Material guidelines

  • Arrange surfaces and content on an 8px spacing grid, with a 4px subgrid for type and icons. Use 16px outer insets on phones and 24px on larger screens.
  • Reserve at least 48px by 48px for touch interactions. Responsive layouts can reveal persistent navigation as more space becomes available.

Material Design 1: Metrics and keylines