Material Design is a design language developed in 2014 by Google and is widely used in in modern mobile and web applications. Material Design is inspired by the physical world and its properties including how they reflect light and cast shadows.

We can easily add the design principles of Material Design to our mobile or web app with the use of prebuilt components from the Material-UI library.

material-ui-homepage

It’s easy to understand why Material-UI, with over 52,000 stars on Github, is so popular. It is simple to install and setup, offers a large library of pre-designed components and provides the possibility to customize all design aspects of your project in order to meet the specific needs of your business or brand.

What We’re Building

In this step-by-step tutorial you will learn how to setup and use the Material-UI library in a React app. We will start from scratch and build the below React app using components from Material-UI.

You can see a live demo of the React app at: https://boorjeadventures.netlify.app/

react-sample-app

As you can see from the image above, we will create a simple landing page for a travel blog. The app uses several components from the Material UI library, such as Grid, Card and ToolBar which we will learn more about soon. The app consists of three primary sections: the nav bar with logo and menu, the grid of blog posts and a footer not shown in this image.

The tutorial demonstrates how easy it is to create a responsive React app using the using the Material UI library. The goal of the tutorial is to provide you with the essential steps to start using the library in your own React apps.

You can find the source code to the project on Github.

Setting Up The React Project

First we need to create a new React app using Create React App which sets up a development for us using the latest JavaScript features.

npx create-react-app material-ui-tutorial

This command initializes a new React app called material-ui-tutorial. Change into the newly created directory to find the React starter project and start the local web development server.

cd material-ui-tutorial
npm start

Before proceeding to next step, we will clean up the project a bit. Navigate to App.js inside the project and open it in your preferred code editor. Remove everything within the <div className="App"></div> and the unused imports. You should have the following code in your file.

import React from "react";

function App() {
  return <div className="App"></div>;
}

export default App;

The next step is add the Material-UI framework to our React app.

Installing Material-UI & Dependencies

With the React app in place, we need to install Material-UI together with some required dependencies. We will be using npm to install the Material-UI framework and the other required packages. The following command will install Material-UI to the React app:

npm install @material-ui/core

To get the full capabilities and design elements of the framework, we need to install some other packages and add make some configurations.

Roboto Font

Material-UI was designed with the Roboto font in mind but the font is not automatically added by Material-UI. Therefore we need to install this ourselves which can be done using npm:

npm install fontsource-roboto

We also need to include the import in our apps entry point, which is the App.js page created when we ran create-react-app. Again, open App.js and add import "fontsource-roboto" in the top as follows:

import React from "react";
import "fontsource-roboto";

Font Icons

The Material-UI library contains over 1100 official icons where each have five different themes. We can add these to our app using the Icon component, but first need to add the Material icons font. Once again we use npm.

npm install @material-ui/icons

To add an Icon you simply import it from @material-ui/icons and then render the component. The component takes some optional props in which two allows you to specify size and color.

import FavoriteIcon from "@material-ui/icons/Favorite";
<FavoriteIcon fontSize="large" color="primary" />;

You can find a full list of the available icons including the different themes here.

material-ui-icons

Responsive meta tag

Material-UI is developed with a mobile-first approach. This strategy starts by writing code for mobile devices, and then scaling up components for larger screens using CSS media queries. To ensure proper rendering, touch zooming for all devices and a responsive design, we need to add the responsive viewport meta tag to the <head> element.

We will add this directly to index.html which can be found in the public/ folder creating during project creation. Open the file index.html and add the below code within the <head></head> tags.

<meta
  name="viewport"
  content="minimum-scale=1, initial-scale=1, width=device-width"
/>

CSS Baseline

The final configuration step is to add the CssBaseline component from the Material-UI library. The component kickstart a simple and consistent baseline to build upon by adding a collection of HTML element and attribute style-normalizations. It is much like normalize.css which provides better cross-browser consistency in the default styling of HTML elements.

Again inside App.js, we import and add the CssBaseline component. You’re App.js should now be looking like this:

import React from "react";
import CssBaseline from "@material-ui/core/CssBaseline";
import "fontsource-roboto";

function App() {
  return (
    <div className="App">
      <CssBaseline />
    </div>
  );
}

export default App;

Now we’re ready to start building our React app using Material-UI.

Creating React App Using Material-UI

Adding Material-UI components to our React app is a straightforward process. Simply import the component and add in inside the return statement of the function. But before we jump in to the actual implementation, there are two important features to understand. Customizing the styling of the Material-UI components and creating responsive layouts.

Customizing Material-UI Styling

All components accept a classes prop to customize the styles. There a several ways to generate and apply customized styling to the components. We will be using the Hook API through the function makeStyles which is available through the @material-ui/core which we previously installed.

default-and-styled-button

To create a customized button as above, we need to import makeStyles, create a stylesheet and then add the styling to the className prop of the component.

import React from "react";
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles({
  customButton: {
    background: "linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)",
    border: 0,
    borderRadius: 3,
    boxShadow: "0 3px 5px 2px rgba(255, 105, 135, .3)",
    color: "white",
    height: 48,
    padding: "0 30px",
  },
});

function Hook() {
  const classes = useStyles();
  return (
    <React.Fragment>
      <Button variant="contained">Default</Button>
      <Button className={classes.customButton}>Custom</Button>
    </React.Fragment>
  );
}

Responsive Layouts

Material-UI makes our lives much easier when it comes to creating responsive web design. Responsive layouts in Material Design adapt to any possible screen size creating a great user experience for all devices. The library provides the following helpers to make the UI responsive:

  • Grid: The responsive layout grid adapts to screen size and orientation, ensuring consistency across layouts. The responsive UI in Material Design is based on a 12-column grid layout. Using the component we can easily specify and dynamically change the size and number of the elements on each row as well as setting the spacing in between.
  • Container: The most basic layout element which centers your content horizontally.
  • Material UI Breakpoints: API that enables the use of breakpoints in a wide variety of contexts. It can be used both when creating our stylesheet and together with the grid layout.

Responsive Nav Bar

We will continue in the path of a mobile-first approach just like Material-UI. With this approach, we will start developing the responsive Material UI navbar so that it is adjusted to a mobile screen and then scale it to fit larger screens as well. The navigation bar will be “collapsed” vertically on mobile devices and expanded horizontally on larger screens. Below image provides an overview of how the navigation bar will look in a mobile.

mobile-navigation-bar

Begin by creating a new file called NavBar.js. Inside, we wrap the navigation bar inside a Container component to center the content and set a maximum width using the Material UI breakpoint lg. We will be using a ToolBar for the actual navigation bar which allows for aligning items next to each other with an inline display.

The logo is just plain text which we had using the Typography component. The component takes optional props for making common changes to text, like setting the alignment, variant and the actual component.

To create the menu buttons, we create add a Box component which is basically just a wrapper (create a new <div> element) to group the buttons together. For each menu button, we create a button Link component. In order to keep track of which menu button has been pressed, we will keep the state of the recent one pressed and assigning a default one.

Wrapping all this together in code, gives us the following:

export default function NavBar() {
  const classes = s();
  const [activeBtn, setActiveBtn] = useState("destinations");

  return (
    <Container>
      <Toolbar className={classes.toolbar}>
        <Typography
          component="h2"
          variant="h5"
          color="inherit"
          align="left"
          noWrap
          className={classes.toolbarTitle}
        >
          BOORJE ADVENTURES
        </Typography>
        <Box className={classes.menuButtons}>
          {["destinations", "my gear", "about", "contact"].map(item => (
            <Link
              component="button"
              variant="body2"
              onClick={() => setActiveBtn(item)}
              color={activeBtn === item ? "textPrimary" : "textSecondary"}
              className={classes.item}
              key={item}
            >
              {item.toUpperCase()}
            </Link>
          ))}
        </Box>
      </Toolbar>
    </Container>
  );
}

You can see that I have added the className prop to some of the components. To create the design from the preview and the responsive design, we also need to create a stylesheet for these defined classes.

I won’t be going the through the styling in detail, other than pointing out the use of theme in the makeStyles function. By adding it as a parameter, we have access to the Theme configuration variables of Material UI which includes palette colors, typography, spacing and breakpoints to name a few important useful. By using these, we can ensure we have a consistent layout throughout the application.

import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles(theme => ({
  toolbar: {
    minHeight: 128,
    display: "flex",
    flexDirection: "column",
    justifyContent: "space-between",
    alignItems: "center",
    padding: theme.spacing(3),
    marginBottom: theme.spacing(3),
    [theme.breakpoints.up("md")]: {
      flexDirection: "row",
      justifyContent: "space-between",
      alignItems: "flex-end",
      marginBottom: theme.spacing(9),
    },
  },
  toolbarTitle: {
    letterSpacing: 1.25,
    fontWeight: "bold",
  },
  menuButtons: {
    display: "flex",
    flexDirection: "column",
    [theme.breakpoints.up("md")]: {
      flexDirection: "row",
    },
  },
  item: {
    padding: theme.spacing(1),
    [theme.breakpoints.up("md")]: {
      paddingLeft: theme.spacing(3),
    },
  },
}));

As you can see in the code, we use the theme in several places. To create the responsive and collapsed navigation bar, we add styling using theme.breakpoints.up("md"). Basically what this says is, apply the below styles for this class when the screen size is larger than md (960px).

We also need to import the component into App.js.

import React from "react";
import CssBaseline from "@material-ui/core/CssBaseline";
import Container from "@material-ui/core/Container";
import "fontsource-roboto";

import NavBar from "./NavBar";
function App() {
  return (
    <div className="App">
      <CssBaseline />
      <NavBar>    </div>
  );
}

Creating a Grid Layout

The next step is to create a responsive grid layout for the blog posts. We will be creating one similar to the image provided below.

grid-layout

Recall that the grid in Material Design is based on a 12-column grid layout. There are two types of layout, containers and items, and we will be using both.

We create a new file called Featured.js which will contain the grid layout for our blog posts. Inside we add the below code. Included you can also find the two components MainFeatured and CardPreview that we haven’t created yet, but we will get there after the grid layout.

import React from "react";
import Grid from "@material-ui/core/Grid";

import MainFeatured from "./MainFeatured";
import CardPreview from "./CardPreview";

export default function Featured() {
  return (
    <Grid container spacing={3}>
      <Grid item lg={12}>
        <MainFeatured />
      </Grid>
      <Grid item xs={12} sm={6}>
        <CardPreview url="https://source.unsplash.com/featured/?travel" />
      </Grid>
      <Grid item xs={12} sm={6}>
        <CardPreview url="https://source.unsplash.com/featured/?nature" />
      </Grid>
      <Grid item xs={6} sm={4} md={3}>
        <CardPreview url="https://source.unsplash.com/featured/?city" />
      </Grid>
      <Grid item xs={6} sm={4} md={3}>
        <CardPreview url="https://source.unsplash.com/featured/?forest" />
      </Grid>
      <Grid item xs={6} sm={4} md={3}>
        <CardPreview url="https://source.unsplash.com/featured/?mountains" />
      </Grid>
      <Grid item xs={6} sm={4} md={3}>
        <CardPreview url="https://source.unsplash.com/featured/?island" />
      </Grid>
    </Grid>
  );
}

First we have a Grid component to wrap the items of the grid layout, where we set the spacing and pass in the container prop flex container behavior.

Then we create the grid items and assign a specific width as number of columns for each. We are once again able to use the breakpoints provided by Material Design. By using the breakpoint xs the column width apply att all breakpoints (basically xs and up).

To create a responsive grid layout with different number of columns, we set the column width to different values for different breakpoints as seen above. So we have created one row that always cover the whole width, no matter the screen size. We have a second row with two items covering half the screen at breakpoints of sm and above, but it collapses into two rows where the items take the full screen width for smaller screen size. And for the final items we use three different breakpoints to set the width.

Material-UI Cards

Let’s jump forward to creating the nice looking blog posts for our travel blog. For this, we will be using a few different Material UI-components, but we will focus on the Card component and also see how to add Material-UI Icons. Cards display content and actions on a single topic and they should be easy to scan for relevant and actionable information.

Card is a surface, like a wrapper, to which we can add content using different sub components. We will be using the components:

  • CardHeader which contains a title, date and a button
  • CardMedia to add an image
  • CardContent to add a short description
  • CardActions to add like and share button

We will once again create a new file for our custom component. Create a new file called CardPreview.js and add the following code:

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Card from "@material-ui/core/Card";
import CardHeader from "@material-ui/core/CardHeader";
import CardMedia from "@material-ui/core/CardMedia";
import CardContent from "@material-ui/core/CardContent";
import CardActions from "@material-ui/core/CardActions";
import IconButton from "@material-ui/core/IconButton";
import Typography from "@material-ui/core/Typography";
import FavoriteIcon from "@material-ui/icons/Favorite";
import ShareIcon from "@material-ui/icons/Share";
import MoreVertIcon from "@material-ui/icons/MoreVert";

const useStyles = makeStyles(() => ({
  root: { maxWidth: 365 },
  media: {
    height: 0,
    paddingTop: "56.25%",
  },
}));

export default function CardPreview(props) {
  const classes = useStyles();

  return (
    <Card className={classes.root}>
      <CardHeader
        action={
          <IconButton aria-label="settings">
            <MoreVertIcon />
          </IconButton>
        }
        title="Lorem Ipsum"
        subheader={
          new Date(+new Date() - Math.floor(Math.random() * 10000000000))
            .toISOString()
            .split("T")[0]
        }
      />
      <CardMedia
        className={classes.media}
        image={props.url}
        title="Lorem Ipsum"
      />
      <CardContent>
        <Typography variant="body2" color="textSecondary" component="p">
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
          eiusmod tempor incididunt ut labore et dolore magna aliqua. Tincidunt
          lobortis feugiat vivamus at augue.
        </Typography>
      </CardContent>
      <CardActions disableSpacing>
        <IconButton aria-label="add to favorites">
          <FavoriteIcon />
        </IconButton>
        <IconButton aria-label="share">
          <ShareIcon />
        </IconButton>
      </CardActions>
    </Card>
  );
}

We use the different card components to create a good looking card for our blog posts which will definitely capture our readers interest. We also add different Material-UI icons wrapped within the IconButton component.

The final piece of the puzzle is to create the hero section at the top. With the the other topics covered so far, this is not something new or hard to implement. Create a new file called MainFeatured.js and add the below code to it.

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Grid from "@material-ui/core/Grid";

const useStyles = makeStyles(theme => ({
  mainFeatured: {
    height: 300,
    backgroundColor: theme.palette.grey[800],
    color: theme.palette.common.white,
    marginBottom: theme.spacing(4),
    backgroundImage: "url(https://source.unsplash.com/17_tB-oI0ao/6016x4016)",
    backgroundSize: "cover",
    backgroundRepeat: "no-repeat",
    backgroundPosition: "center",
  },
  mainFeaturedContent: {
    position: "relative",
    padding: theme.spacing(3),
    [theme.breakpoints.up("md")]: {
      padding: theme.spacing(6),
      paddingRight: 0,
    },
  },
}));

export default function MainFeatured() {
  const classes = useStyles();

  return (
    <Grid container className={classes.mainFeatured}>
      <Grid item md={6} className={classes.mainFeaturedContent}>
        <Typography component="h1" variant="h5" color="inherit" gutterBottom>
          Travelling the globe
        </Typography>
        <Typography variant="body1" color="inherit" paragraph>
          Join my adventures through my travel reports where i share my
          experiences through pictures and well documented posts.
        </Typography>
      </Grid>
    </Grid>
  );
}

We basically create a grid layout with one item which covers the whole grid for screens smaller than the breakpoint md and only half the grid for larger screen. Then we also add some styling in order to have the image cover the whole grid.

Wrapping up

In this tutorial we have seen how to setup and use Material-UI in a React app and gone step-by-step implemented a real-world sample application from scratch. It is very easy to create responsive mobile and web apps with good UI thanks to the components from Material-UI that are developed using Google’s Material Design principles.

If you got lost somewhere during the tutorial, you can find the source code below.

View source

Hopefully you are now ready to start exploring the library and all the awesome features your self. Thanks for reading!