Beginner Tutorial

Dashboard Layout

This tutorial will take you through basic installation and configuration of mui-layout.

Let’s use create-react-app to kickstart the project

npx create-react-app my-layout

when the process is done, install packages

cd my-layout
yarn add @material-ui/core @mui-treasury/layout @mui-treasury/mockup

// note: this tutorial is based on @mui-treasury/layout v3.3.2

Now, when you run yarn start, you will see react logo in the browser.

image

Next, open file /src/App.js and replace with the code below

import React from 'react';
import { Root } from '@mui-treasury/layout';

function App() {
  return <Root>hello</Root>;
}

export default App;

Your page will turn to just Hello text.

mui-layout use react-context at its core. Root is the Provider that render nothing except its children.

By default, Root has ThemeProvider inside to provide default theme from material-ui but you can also add custom theme to Root by doing this

import React from 'react';
import { Root } from '@mui-treasury/layout';
import { createMuiTheme } from '@material-ui/core/styles';const customTheme = createMuiTheme({  palette: { primary: { main: '#ff5252' } },});
function App() {
  return <Root theme={customTheme}>hello</Root>;}

export default App;

Let’s add sidebar to the page. we can configure behavior by passing config object to Root

in this case, we want Sidebar to appear permanent on the left and has width: 256(px)

import React from 'react';
import { Root, Sidebar } from '@mui-treasury/layout';import { NavHeaderMockUp, NavContentMockUp } from '@mui-treasury/mockup/layout';import { createMuiTheme } from '@material-ui/core/styles';

const customTheme = createMuiTheme({
  palette: { primary: { main: '#ff5252' } },
});

const config = {  sidebar: {    anchor: 'left',    width: 256,    variant: 'permanent',  },};
function App() {
  return (
    <Root theme={customTheme} config={config}>      <Sidebar>        <NavHeaderMockUp />        <NavContentMockUp />      </Sidebar>    </Root>  );
}

export default App;

Save and then you should see this in your browser.

image

I feel like this sidebar should be collapsible because I care so much about my users and I want them to be able to see more space in tablet viewport. Here is how to do it.

import { Root, Sidebar, CollapseBtn } from '@mui-treasury/layout';
const config = {
  sidebar: {
    anchor: 'left',
    width: 256,
    variant: 'permanent',
    collapsible: true,    collapsedWidth: 64,  },
};

function App() {
  return (
    <Root theme={customTheme} config={config}>
      {({ sidebarStyles, collapsed }) => (        <Sidebar>          <div className={sidebarStyles.container}>            <NavHeaderMockUp />            <NavContentMockUp />          </div>          <CollapseBtn className={sidebarStyles.collapseBtn}>            {collapsed ? 'Open' : 'Collapse'}          </CollapseBtn>        </Sidebar>      )}    </Root>
  );
}

I know, it changes a lot so let me explain one by one. Inside Root, there is a state called collapsed (a boolean). <Root> can accept function as a child with an object that contains sidebarStyles: string, collapsed: boolean, setCollapsed: Function and a lot more. Another thing, CollapseBtn is used to toggle the state. All you have to do is render it (anywhere) below Root.

@mui-treasury/layout also provide collapse icon to make it easier to use but you need to install icons first.

yarn add @material-ui/icons

then you can use it like this.

import { Root, Sidebar, CollapseBtn, CollapseIcon } from "@mui-treasury/layout";
...
<CollapseBtn className={sidebarStyles.collapseBtn}>
  <CollapseIcon /></CollapseBtn>
...

I want to have fixed Header in my layout. Let’s add header to the config.

import {
  Root,
  Header,  Sidebar,
  CollapseBtn,
  CollapseIcon
} from "@mui-treasury/layout";
import { Toolbar } from "@material-ui/core";
const config = {
  sidebar: { ... },
  header: {    position: "fixed"  }};

function App() {
  return (
    <Root theme={customTheme} config={config}>
      {({ sidebarStyles }) => (
        <>
          <Header>            <Toolbar>Header</Toolbar>          </Header>          <Sidebar>
            <div className={sidebarStyles.container}>
              <NavHeaderMockUp />
              <NavContentMockUp />
            </div>
            <CollapseBtn className={sidebarStyles.collapseBtn}>
              <CollapseIcon />
            </CollapseBtn>
          </Sidebar>
        </>
      )}
    </Root>
  );
}

Save and then see the result in your browser.

gif

Well, it looks good but I prefer to have my Header stay on top of Sidebar. just add clipped to the config and save.

const config = {
  sidebar: { ... },
  header: {
    position: "fixed",
    clipped: true  }
};

Now the problem arise because the content in Sidebar is overlapped by Header.

image

Here is an easy fix that mui-layout provide by adding offsetHeight: unit to config.

const config = {
  sidebar: { ... },
  header: {
    position: "fixed",
    offsetHeight: 64, // 64 is the height of header    clipped: true
  }
};

Let’s add Content and Footer to the page and see how they appear.

import {
  Root,
  Header,
  Sidebar,
  CollapseBtn,
  CollapseIcon,
  Content,  Footer,} from '@mui-treasury/layout';
import {
  NavHeaderMockUp,
  NavContentMockUp,
  ContentMockUp,  FooterMockUp,} from '@mui-treasury/mockup/layout';

function App() {
  return (
    <Root theme={customTheme} config={config}>
      {({ sidebarStyles }) => (
        <>
          <Header>
            <Toolbar>Header</Toolbar>
          </Header>
          <Sidebar>
            <div className={sidebarStyles.container}>
              <NavHeaderMockUp />
              <NavContentMockUp />
            </div>
            <CollapseBtn className={sidebarStyles.collapseBtn}>
              <CollapseIcon />
            </CollapseBtn>
          </Sidebar>
          <Content>            <ContentMockUp />          </Content>          <Footer>            <FooterMockUp />          </Footer>        </>
      )}
    </Root>
  );
}

There is only one property that can be configurable in Content and Footer which is persistentBehavior but The Sidebar variant must be persistent. Let’s change sidebar to persistent and see how it looks like. When you set sidebar to persistent, you need a trigger(SidebarTrigger) to control sidebar state.

import {
  Root,
  Header,
  Sidebar,
  CollapseBtn,
  CollapseIcon,
  SidebarTrigger,  SidebarTriggerIcon,  Content,
  Footer
} from "@mui-treasury/layout";

const config = {
  sidebar: {
    anchor: "left",
    width: 256,
    variant: "persistent",    collapsible: true,
    collapsedWidth: 64
  },
  header: {...}
};

...
  <Header>
    <Toolbar>
      <SidebarTrigger className={headerStyles.leftTrigger}>        {/* headerStyles is from Root function as a child */}        <SidebarTriggerIcon />      </SidebarTrigger>      Header
    </Toolbar>
  </Header>
...

Now you will see menu bar in header and when you click on it, sidebar will open without affecting Content and Footer. However, if you want Content and Footer to move with Sidebar, you can insert persistentBehavior: 'fit' | 'flexible' | 'none' to config like this.

const config = {
  sidebar: { ... },
  secondarySidebar: {},
  header: { ... },
  content: {    persistentBehavior: "fit"  },  footer: {    persistentBehavior: "flexible"  }};

Explanation: fit will have width within viewport and pushed by sidebar, flexible will fix the element width and pushed by sidebar none means no affect

I want to show something cool that mui-layout gives you. Let change Header position to relative and scroll the page.

Okay, I’ll wait you…

I assume you changed it. Pretty cool, right? The Sidebar stick to the relative Header when you scroll down the page. This feature is called Header Magnet. If you don’t like it you can disable by adding this line in config.

const config = {
  heightAdjustmentDisabled: true,  sidebar: {...},
  header: {...},
  content: {...},
  footer: {...}
};

One last thing in this tutorial is that Header can also have persistentBehavior but its position need to be static, relative or absolute and unclipped.

const config = {
  sidebar: { ... },
  secondarySidebar: {},
  header: {
    position: "relative",
    offsetHeight: 64,
    clipped: false,    persistentBehavior: "fit"  },
  content: { ... },
  footer: { ... }
};

Congratulations! you have completed this tutorial.

Thanks for stopping by, feel free to comment or open issue in github.