Skip to main content
react-md

Layout

If this is a new project, check out the example projects page to be able to clone a template project with everything configured.

When creating an app, a global layout is defined to help the user access common actions or navigate to different pages. Most web applications will use a fixed header, a navigation panel that can be toggled or static, and a main content area. react-md provides components, and hooks to help create these global layouts.

Choosing a Layout Type

To get started, determine the type of layout that makes the most sense for the app. Should there be a fixed header at the top of the page or should it scroll with the rest of the content on the page? Should the navigation always be visible, toggleable, expandable, or resizable? Once a general idea has been formed, choose one of the layouts listed below to get started or build your own.

All layout types will not be shown on this page since there are endless possibilities. Check out the AppBar, Sheet, Dialog, and Navigation components to extend the layout.

Temporary Navigation Layout

A temporary navigation layout is common and always used on smaller viewports for the other layout types. The layout is created by using the useTemporaryLayout hook and an AppBar, Button, Main, Sheet, and some sort of navigation component. The useTemporaryLayout provides props for each component to handle the updating the Sheet's visibility as the pathname changes.

Check out the useTemporaryLayout hook documentation for more configuration options.

The code for an example temporary layout is shown below and can be viewed here.

"use client";

import { AppBar } from "@react-md/core/app-bar/AppBar";
import { AppBarTitle } from "@react-md/core/app-bar/AppBarTitle";
import { Button } from "@react-md/core/button/Button";
import { Main } from "@react-md/core/layout/Main";
import { useTemporaryLayout } from "@react-md/core/layout/useTemporaryLayout";
import { Sheet } from "@react-md/core/sheet/Sheet";
import { usePathname } from "next/navigation.js";
import { type ReactElement, type ReactNode } from "react";

import { MainNavigation } from "./MainNavigation.jsx";

export interface TemporaryLayoutExampleProps {
  children: ReactNode;
}

export function TemporaryLayoutExample(
  props: TemporaryLayoutExampleProps
): ReactElement {
  const { children } = props;

  const pathname = usePathname();
  const { appBarProps, mainProps, temporaryNavProps, navToggleProps } =
    useTemporaryLayout({ pathname });

  return (
    <>
      <AppBar {...appBarProps}>
        <Button {...navToggleProps} />
        <AppBarTitle>Main Title</AppBarTitle>
      </AppBar>
      <Main {...mainProps}>{children}</Main>
      <Sheet {...temporaryNavProps}>
        <MainNavigation />
      </Sheet>
    </>
  );
}

Expandable Navigation Layout

An expandable layout extends the temporary layout by allowing larger viewports like tablets and desktops to be able to view the navigation inline with the main content. This layout can be created using the useExpandableLayout hook, the same components as the temporary layout, and a new LayoutNav component.

Check out the useExpandableLayout hook documentation for more configuration options.

The code for an example expandable layout is shown below and can be viewed here.

"use client";

import { AppBar } from "@react-md/core/app-bar/AppBar";
import { AppBarTitle } from "@react-md/core/app-bar/AppBarTitle";
import { Button } from "@react-md/core/button/Button";
import { LayoutNav } from "@react-md/core/layout/LayoutNav";
import { Main } from "@react-md/core/layout/Main";
import { useExpandableLayout } from "@react-md/core/layout/useExpandableLayout";
import { Sheet } from "@react-md/core/sheet/Sheet";
import { usePathname } from "next/navigation.js";
import { type ReactElement, type ReactNode } from "react";

import { MainNavigation } from "./MainNavigation.jsx";

export interface ExpandableLayoutExampleProps {
  children: ReactNode;
}

export function ExpandableLayoutExample(
  props: ExpandableLayoutExampleProps
): ReactElement {
  const { children } = props;

  const pathname = usePathname();
  const {
    temporary,
    persistent,
    temporaryNavProps,
    navToggleProps,
    appBarProps,
    mainProps,
    expandableNavProps,
  } = useExpandableLayout({ pathname });

  return (
    <>
      <AppBar {...appBarProps}>
        <Button {...navToggleProps} />
        <AppBarTitle>Expandable Layout Example</AppBarTitle>
      </AppBar>
      {persistent && (
        <LayoutNav {...expandableNavProps}>
          <MainNavigation />
        </LayoutNav>
      )}
      {temporary && (
        <Sheet {...temporaryNavProps}>
          <MainNavigation />
        </Sheet>
      )}
      <Main {...mainProps}>{children}</Main>
    </>
  );
}

Full Height Navigation Layout

This layout reuses everything from the expandable layout without making the layout expandable and the navigation panel spans the entire height of the screen instead of appearing beneath the fixed app bar.

The diff for creating a full height layout is shown below and can be viewed here.

  const {
    temporary,
    persistent,
    temporaryNavProps,
    navToggleProps,
    appBarProps,
    mainProps,
    expandableNavProps,
- } = useExpandableLayout({ pathname });
+ } = useExpandableLayout({ pathname, fullHeightNav: "static" });

Full Height Expandable Navigation Layout

This layout is the same as the expandable layout except that the navigation panel is the full height instead of appearing beneath the fixed app bar.

The diff for creating a full height expandable layout is shown below and can be viewed here.

  const {
    temporary,
    persistent,
    temporaryNavProps,
    navToggleProps,
    appBarProps,
    mainProps,
    expandableNavProps,
- } = useExpandableLayout({ pathname });
+ } = useExpandableLayout({ pathname, fullHeightNav: true });

Resizable Navigation Layout

A resizable layout extends the expandable layout by allowing the user to manually resize the navigation panel to their desired width by dragging to their desired width. This layout can be created using the useResizableLayout hook, the same components as the expandable layout, and a new LayoutWindowSplitter component.

Check out the useResizableLayout hook documentation for more configuration options.

The code for an example resizable layout is shown below and can be viewed here.

"use client";

import { AppBar } from "@react-md/core/app-bar/AppBar";
import { AppBarTitle } from "@react-md/core/app-bar/AppBarTitle";
import { Button } from "@react-md/core/button/Button";
import { LayoutNav } from "@react-md/core/layout/LayoutNav";
import { LayoutWindowSplitter } from "@react-md/core/layout/LayoutWindowSplitter";
import { Main } from "@react-md/core/layout/Main";
import { useResizableLayout } from "@react-md/core/layout/useResizableLayout";
import { Sheet } from "@react-md/core/sheet/Sheet";
import { usePathname } from "next/navigation.js";
import { type ReactElement, type ReactNode } from "react";

import { MainNavigation } from "./MainNavigation.jsx";

export interface ResizableLayoutExampleProps {
  children: ReactNode;
}

export function ResizableLayoutExample(
  props: ResizableLayoutExampleProps
): ReactElement {
  const { children } = props;

  const pathname = usePathname();
  const {
    temporary,
    persistent,
    appBarProps,
    navToggleProps,
    expandableNavProps,
    mainProps,
    temporaryNavProps,
    windowSplitterProps,
  } = useResizableLayout({ pathname });

  return (
    <>
      <AppBar {...appBarProps}>
        <Button {...navToggleProps} />
        <AppBarTitle>Resizable Layout Example</AppBarTitle>
      </AppBar>
      {persistent && (
        <>
          <LayoutNav {...expandableNavProps}>
            <MainNavigation />
          </LayoutNav>
          <LayoutWindowSplitter {...windowSplitterProps} />
        </>
      )}
      {temporary && (
        <Sheet {...temporaryNavProps}>
          <MainNavigation />
        </Sheet>
      )}
      <Main {...mainProps}>{children}</Main>
    </>
  );
}

Full Height Resizable Navigation Layout

Just like the expandable layout version, the resizable layout can become full height by providing fullHeightNav: true or fullHeightNav: "static". The diff for creating a full height static resizable layout is shown below and can be viewed here.

  const {
    temporary,
    persistent,
    appBarProps,
    navToggleProps,
    expandableNavProps,
    mainProps,
    temporaryNavProps,
    windowSplitterProps,
- } = useResizableLayout({ pathname });
+ } = useResizableLayout({ pathname, fullHeightNav: "static" });

Creating the MainNavigation

Now that a layout has been setup, it's time to create the MainNavigation component which is usually one of:

The easiest way to get started is by using the Navigation component which is the default navigation type shown in the demos on this page. The Navigation component accepts a list of items and data containing the pathname and linkComponent. The Home, Page 1, and Page 2 routes in the demos are created by:

import { Navigation } from "@react-md/core/navigation/Navigation";
import { type NavigationItem } from "@react-md/core/navigation/types";
import { useNavigationExpansion } from "@react-md/core/navigation/useNavigationExpansion";
import FavoriteIcon from "@react-md/material-icons/FavoriteIcon";
import HomeIcon from "@react-md/material-icons/HomeIcon";
import StarIcon from "@react-md/material-icons/StarIcon";
import Link from "next/link.js";
import { usePathname } from "next/navigation.js";
import { type ReactElement } from "react";

const items: readonly NavigationItem[] = [
  {
    type: "route",
    href: "/",
    children: "Home",
    beforeAddon: <HomeIcon />,
  },
  {
    type: "route",
    href: "/page-1",
    children: "Page 1",
    beforeAddon: <StarIcon />,
  },
  {
    type: "route",
    href: "/page-2",
    children: "Page 2",
    beforeAddon: <FavoriteIcon />,
  },
];

export function MainNavigation(): ReactElement {
  const pathname = usePathname();
  const { data } = useNavigationExpansion({
    pathname,
    linkComponent: Link,
  });

  return <Navigation items={items} data={data} />;
}

See the Navigation component documentation for additional features, styling, and customization.

Tree Component

Before considering the use of a Tree for site navigation, it is important to understand:

  • The Tree implementation requires complex functionality that is not needed for typical site navigation
  • The Navigation component can be used instead for expandable groups of links

A Tree can be used for site navigation with the useLayoutTree hook using the TreeData data structure. Each item should have an itemId that matches the href for the route and a parentId of a parent route or null. When the itemId matches the current pathname, it will gain the active styles.

A tree layout can be viewed here.

import { useLayoutTree } from "@react-md/core/layout/useLayoutTree";
import { Tree } from "@react-md/core/tree/Tree";
import { type TreeData } from "@react-md/core/tree/types";
import FavoriteIcon from "@react-md/material-icons/FavoriteIcon";
import HomeIcon from "@react-md/material-icons/HomeIcon";
import StarIcon from "@react-md/material-icons/StarIcon";
import Link from "next/link.js";
import { usePathname } from "next/navigation.js";
import { type ReactElement } from "react";

const navItems: TreeData = {
  "/": {
    parentId: null,
    itemId: "/",
    href: "/",
    children: "Home",
    leftAddon: <HomeIcon />,
  },
  "/page-1": {
    itemId: "/page-1",
    parentId: null,
    href: "/page-1",
    children: "Page 1",
    leftAddon: <StarIcon />,
  },
  "/page-1/child-page-1": {
    itemId: "/page-1/child-page-1",
    parentId: "/page-1",
    href: "/page-1/child-page-1",
    children: "Child Page 1",
  },
  "/page-2": {
    itemId: "/page-2",
    parentId: null,
    href: "/page-2",
    children: "Page 2",
    leftAddon: <FavoriteIcon />,
  },
};

export function MainNavigation(): ReactElement {
  const pathname = usePathname();
  const tree = useLayoutTree({
    navItems,
    pathname,
  });

  return <Tree aria-label="Navigation" {...tree} linkComponent={Link} />;
}

See the Tree component documentation for additional features, styling, and customization.