Using Material UI in React

A comprehensive guide on how to use Material UI in React for building visually appealing and responsive user interfaces.

Introduction

What is Material UI?

Material UI is a popular, open-source library that provides React components that implement Google's Material Design. It's a collection of React components that follow Google's Material Design guidelines to ensure your app has a consistent look and feel. Material UI offers a wide range of pre-built components like buttons, text fields, cards, dialogs, and more, which can significantly speed up the development process.

Why Use Material UI in React?

Using Material UI in React applications brings several benefits:

  • Consistency: It ensures that your app adheres to Material Design principles, providing a consistent user experience.
  • Speed: You can quickly build out your UI with pre-built components, reducing development time.
  • Accessibility: Material UI components are designed with accessibility in mind, helping you build inclusive applications.
  • Customization: You can easily customize the look and feel of your app to match your brand guidelines.

Setting Up Material UI

Installation

Prerequisites

Before you begin, make sure you have Node.js and npm (Node Package Manager) installed on your machine. You can download and install them from the official Node.js website.

Step-by-Step Installation Guide

  1. Create a React App: If you haven't already created a React app, you can do so using Create React App.
    npx create-react-app my-material-ui-app
    cd my-material-ui-app
    
  2. Install Material UI: Use npm or yarn to install Material UI and its dependencies.
    npm install @mui/material @emotion/react @emotion/styled
    
    or
    yarn add @mui/material @emotion/react @emotion/styled
    

Basic Configuration

Theme Setup

Material UI uses a theming system that allows you to customize the look and feel of your app. Let's set up a basic theme.

  1. Create a Theme File: Create a theme.js (or theme.ts for TypeScript) file in the src directory.
    // src/theme.js
    import { createTheme } from '@mui/material/styles';
    
    const theme = createTheme({
      palette: {
        primary: {
          main: '#1976d2',
        },
        secondary: {
          main: '#dc004e',
        },
      },
    });
    
    export default theme;
    
  2. Set Up Theme Provider: Wrap your application with the ThemeProvider to apply the theme globally.
    // src/index.js
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { ThemeProvider } from '@mui/material/styles';
    import theme from './theme';
    import App from './App';
    
    ReactDOM.render(
      <ThemeProvider theme={theme}>
        <App />
      </ThemeProvider>,
      document.getElementById('root')
    );
    

Customization

You can customize the theme further by modifying the createTheme function. For example, you can add typography styles, spacing, and more.

Core Components

Buttons

Buttons allow users to take actions, and Material UI provides several variations to choose from.

Basic Button

The simplest type of button.

// src/App.js
import React from 'react';
import Button from '@mui/material/Button';

function App() {
  return (
    <div>
      <Button variant="text">Text</Button>
      <Button variant="contained">Contained</Button>
      <Button variant="outlined">Outlined</Button>
    </div>
  );
}

export default App;

The expected output will be three buttons: one text button, one contained button, and one outlined button.

Raised Button

Raised buttons are the default contained buttons and have a raised appearance.

<Button variant="contained">Raised Button</Button>

Floating Action Button

Floating Action Buttons (FABs) are circular buttons used to promote a primary action.

import Fab from '@mui/material/Fab';
import AddIcon from '@mui/icons-material/Add';

function App() {
  return (
    <div>
      <Fab color="primary" aria-label="add">
        <AddIcon />
      </Fab>
    </div>
  );
}

Usage Examples

Buttons can be used to trigger actions like form submissions, route navigation, or more.

Text Fields

Text fields are used to enter and edit text.

Basic Text Field

A standard text field.

import TextField from '@mui/material/TextField';

function App() {
  return (
    <div>
      <TextField label="Basic" variant="outlined" />
    </div>
  );
}

Multi-line Text Field

For entering longer text.

<TextField
  label="Multiline"
  multiline
  rows={4}
  variant="outlined"
/>

Decorated Text Field

Adding additional decorations like icons.

import InputAdornment from '@mui/material/InputAdornment';
import TextField from '@mui/material/TextField';
import AccountCircle from '@mui/icons-material/AccountCircle';

function App() {
  return (
    <div>
      <TextField
        label="With icon"
        variant="outlined"
        InputProps={{
          startAdornment: (
            <InputAdornment position="start">
              <AccountCircle />
            </InputAdornment>
          ),
        }}
      />
    </div>
  );
}

Usage Examples

Text fields are commonly used in forms for user input.

Selects

Selects are a powerful way to let users choose one or more options.

Basic Select

A simple dropdown select.

import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';

function App() {
  const [age, setAge] = React.useState('');

  const handleChange = (event) => {
    setAge(event.target.value);
  };

  return (
    <div>
      <Select
        labelId="demo-simple-select-label"
        id="demo-simple-select"
        value={age}
        label="Age"
        onChange={handleChange}
      >
        <MenuItem value={10}>Ten</MenuItem>
        <MenuItem value={20}>Twenty</MenuItem>
        <MenuItem value={30}>Thirty</MenuItem>
      </Select>
    </div>
  );
}

Controlled Select

A select controlled by the state.

<Select
  labelId="demo-simple-select-label"
  id="demo-simple-select"
  value={age}
  label="Age"
  onChange={handleChange}
>
  <MenuItem value={10}>Ten</MenuItem>
  <MenuItem value={20}>Twenty</MenuItem>
  <MenuItem value={30}>Thirty</MenuItem>
</Select>

Grouped Select

Grouping items in the dropdown.

<Select
  labelId="demo-simple-select-label"
  id="demo-simple-select"
  value={age}
  label="Age"
  onChange={handleChange}
>
  <MenuItem value="">
    <em>None</em>
  </MenuItem>
  <ListSubheader>Age</ListSubheader>
  <MenuItem value={10}>Ten</MenuItem>
  <MenuItem value={20}>Twenty</MenuItem>
  <MenuItem value={30}>Thirty</MenuItem>
</Select>

Usage Examples

Selects are used in forms to provide a list of options for the user.

Cards

Cards contain content and actions about a single subject.

Basic Card

A simple card with some text.

import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';

function App() {
  return (
    <Card>
      <CardContent>
        <Typography variant="h5" component="div">
          Basic Card
        </Typography>
        <Typography variant="body2" color="text.secondary">
          This is a basic card.
        </Typography>
      </CardContent>
    </Card>
  );
}

Media Card

A card with media content.

import Card from '@mui/material/Card';
import CardMedia from '@mui/material/CardMedia';
import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';

function App() {
  return (
    <Card sx={{ maxWidth: 345 }}>
      <CardMedia
        component="img"
        height="140"
        image="/static/images/cards/contemplative-reptile.jpg"
        alt="green iguana"
      />
      <CardContent>
        <Typography gutterBottom variant="h5" component="div">
          Lizard
        </Typography>
        <Typography variant="body2" color="text.secondary">
          Lizards are a widespread group of squamate reptiles, with over 6,000 species, ranging across all continents except Antarctica
        </Typography>
      </CardContent>
    </Card>
  );
}

Custom Card

Customizing the card's appearance.

import Card from '@mui/material/Card';
import CardContent from '@mui/material/CardContent';
import Typography from '@mui/material/Typography';

function App() {
  return (
    <Card sx={{ minWidth: 275, backgroundColor: '#f5f5f5' }}>
      <CardContent>
        <Typography variant="h5" component="div">
          Custom Card
        </Typography>
        <Typography variant="body2" color="text.secondary">
          This card has a custom background color.
        </Typography>
      </CardContent>
    </Card>
  );
}

Usage Examples

Cards are used to group related data and actions, providing a clean and organized UI.

Advanced Components

Dialogs

Dialogs inform users about a task and can contain critical information, require decisions, or involve multiple tasks.

Basic Dialog

A simple dialog box.

import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';

function App() {
  const [open, setOpen] = React.useState(false);

  const handleClickOpen = () => {
    setOpen(true);
  };

  const handleClose = () => {
    setOpen(false);
  };

  return (
    <div>
      <Button variant="outlined" onClick={handleClickOpen}>
        Open Dialog
      </Button>
      <Dialog
        open={open}
        onClose={handleClose}
        aria-labelledby="alert-dialog-title"
        aria-describedby="alert-dialog-description"
      >
        <DialogTitle id="alert-dialog-title">
          {"Use Google's location service?"}
        </DialogTitle>
        <DialogContent>
          <DialogContentText id="alert-dialog-description">
            Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.
          </DialogContentText>
        </DialogContent>
        <DialogActions>
          <Button onClick={handleClose}>Disagree</Button>
          <Button onClick={handleClose} autoFocus>
            Agree
          </Button>
        </DialogActions>
      </Dialog>
    </div>
  );
}

Form Dialog

A dialog with a form.

import Button from '@mui/material/Button';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogTitle from '@mui/material/DialogTitle';
import TextField from '@mui/material/TextField';

function App() {
  const [open, setOpen] = React.useState(false);

  const handleClickOpen = () => {
    setOpen(true);
  };

  const handleClose = () => {
    setOpen(false);
  };

  return (
    <div>
      <Button variant="outlined" onClick={handleClickOpen}>
        Open Form Dialog
      </Button>
      <Dialog open={open} onClose={handleClose}>
        <DialogTitle>Add New Item</DialogTitle>
        <DialogContent>
          <TextField
            autoFocus
            margin="dense"
            id="name"
            label="Name"
            type="email"
            fullWidth
            variant="outlined"
          />
        </DialogContent>
        <DialogActions>
          <Button onClick={handleClose}>Cancel</Button>
          <Button onClick={handleClose}>Add</Button>
        </DialogActions>
      </Dialog>
    </div>
  );
}

Nested Dialog

A dialog that opens another dialog.

// This example is straightforward and follows the previous examples with an additional dialog.

Usage Examples

Dialogs are useful for displaying additional information or options to the user without leaving the current view.

Snackbars

Snackbars provide brief messages about app processes to the user.

Top Center Snackbar

Displays a snackbar at the top center of the screen.

import Button from '@mui/material/Button';
import Snackbar from '@mui/material/Snackbar';
import MuiAlert from '@mui/material/Alert';

function Alert(props) {
  return <MuiAlert elevation={6} variant="filled" {...props} />;
}

function App() {
  const [open, setOpen] = React.useState(false);

  const handleClick = () => {
    setOpen(true);
  };

  const handleClose = (event, reason) => {
    if (reason === 'clickaway') {
      return;
    }

    setOpen(false);
  };

  return (
    <div>
      <Button variant="outlined" onClick={handleClick}>
        Open Top Center Snackbar
      </Button>
      <Snackbar open={open} autoHideDuration={6000} onClose={handleClose} anchorOrigin={{ vertical: 'top', horizontal: 'center' }}>
        <Alert onClose={handleClose} severity="success" sx={{ width: '100%' }}>
          This is a top-center snackbar!
        </Alert>
      </Snackbar>
    </div>
  );
}

Bottom Right Snackbar

Displays a snackbar at the bottom right of the screen.

<Snackbar
  open={open}
  autoHideDuration={6000}
  onClose={handleClose}
  anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}
>
  <Alert onClose={handleClose} severity="info" sx={{ width: '100%' }}>
    This is a bottom-right snackbar!
  </Alert>
</Snackbar>

Usage Examples

Snackbars are ideal for providing real-time feedback to users.

Tooltips

Tooltips display brief descriptive text when the user hovers over, focuses on, or taps an element.

Basic Tooltip

A simple tooltip.

import Tooltip from '@mui/material/Tooltip';
import Button from '@mui/material/Button';

function App() {
  return (
    <Tooltip title="Delete">
      <Button>Button</Button>
    </Tooltip>
  );
}

Usage Examples

Tooltips enhance usability by providing additional context without cluttering the UI.

Menus provide a list of options for users to choose from.

Simple Menu

A basic menu.

import Menu from '@mui/material/Menu';
import MenuItem from '@mui/material/MenuItem';
import Button from '@mui/material/Button';
import { useState } from 'react';

function App() {
  const [anchorEl, setAnchorEl] = useState(null);

  const handleClick = (event) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  return (
    <div>
      <Button onClick={handleClick}>Open Menu</Button>
      <Menu
        id="basic-menu"
        anchorEl={anchorEl}
        open={Boolean(anchorEl)}
        onClose={handleClose}
        MenuListProps={{
          'aria-labelledby': 'basic-button',
        }}
      >
        <MenuItem onClick={handleClose}>Profile</MenuItem>
        <MenuItem onClick={handleClose}>My account</MenuItem>
        <MenuItem onClick={handleClose}>Logout</MenuItem>
      </Menu>
    </div>
  );
}

A more complex menu with submenus.

<MenuList>
  <MenuItem onClick={handleClose}>Profile</MenuItem>
  <MenuItem onClick={handleClose}>My account</MenuItem>
  <MenuItem onClick={handleClose}>Logout</MenuItem>
</MenuList>

Usage Examples

Menus are useful for navigating and selecting options.

Theming and Customization

Theming with Material UI

Material UI uses a theming system to ensure your app's design is consistent and customizable.

Creating a Theme

Define a theme with specific colors, typography, and spacing.

// src/theme.js
import { createTheme } from '@mui/material/styles';

const theme = createTheme({
  palette: {
    primary: {
      main: '#556cd6',
    },
    secondary: {
      main: '#19857b',
    },
    error: {
      main: red.A400,
    },
    background: {
      default: '#fff',
    },
  },
});

export default theme;

Applying Theme Globally

Apply the theme using ThemeProvider in your application's root component.

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { ThemeProvider } from '@mui/material/styles';
import theme from './theme';
import App from './App';

ReactDOM.render(
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>,
  document.getElementById('root')
);

Theme Customization

Customize your theme further by modifying the createTheme function.

const theme = createTheme({
  palette: {
    primary: {
      main: '#ff5722',
    },
  },
  typography: {
    fontFamily: [
      '-apple-system',
      'BlinkMacSystemFont',
      '"Segoe UI"',
      'Roboto',
      '"Helvetica Neue"',
      'Arial',
      'sans-serif',
      '"Apple Color Emoji"',
      '"Segoe UI Emoji"',
      '"Segoe UI Symbol"',
    ].join(','),
  },
});

Customize Components

Override default styles and apply custom styles using themes.

Override Styles

Override default styles for specific components.

import { createTheme } from '@mui/material/styles';

const theme = createTheme({
  components: {
    MuiButton: {
      styleOverrides: {
        root: {
          background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
          border: 0,
          borderRadius: 3,
          boxShadow: '0 3px 5px 2px rgba(255, 105, 132, .3)',
          color: 'white',
        },
      },
    },
  },
});

Styling with Theme

Use theme properties to style components dynamically.

import { styled } from '@mui/system';

const MyButton = styled(Button)(({ theme }) => ({
  background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
  border: 0,
  borderRadius: 3,
  boxShadow: `0 3px 5px 2px rgba(255, 105, 132, .3)`,
  color: 'white',
  height: 48,
  padding: '0 30px',
}));

function App() {
  return (
    <div>
      <MyButton>My Styled Button</MyButton>
    </div>
  );
}

Usage Examples

Customizing components helps match your app's style guide.

Integrations

Icons

Material UI provides a large collection of icons.

Installation

Install the Material Icons package.

npm install @mui/icons-material

Basic Icon Usage

Use icons easily in your components.

import StarIcon from '@mui/icons-material/Star';
import IconButton from '@mui/material/IconButton';

function App() {
  return (
    <div>
      <IconButton aria-label="delete">
        <StarIcon />
      </IconButton>
    </div>
  );
}

Custom Icons

Add custom icons to your app.

import { SvgIcon } from '@mui/material';

const HomeIcon = () => (
  <SvgIcon>
    <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
  </SvgIcon>
);

function App() {
  return (
    <div>
      <HomeIcon />
    </div>
  );
}

React Router

Integrate Material UI with React Router for routing.

Installation

Install React Router.

npm install react-router-dom

Basic Integration

Set up basic routing.

import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import Button from '@mui/material/Button';

function App() {
  return (
    <Router>
      <div>
        <Button component={Link} to="/home">
          Home
        </Button>
        <Button component={Link} to="/about">
          About
        </Button>
        <Routes>
          <Route path="/home" element={<Home />} />
          <Route path="/about" element={<About />} />
        </Routes>
      </div>
    </Router>
  );
}

Advanced Routing

Use advanced routing features for more complex navigation.

import { Routes, Route, Home, About, NotFound, useNavigate } from 'react-router-dom';
import Button from '@mui/material/Button';

function App() {
  let navigate = useNavigate();

  const handleButtonClick = () => {
    navigate('/home');
  };

  return (
    <div>
      <Button onClick={handleButtonClick}>Go to Home</Button>
      <Routes>
        <Route path="/home" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </div>
  );
}

Formik

Integrate Formik for form management.

Installation

Install Formik.

npm install formik

Basic Integration

Set up a basic form using Formik and Material UI.

import { Formik, Form, Field, ErrorMessage } from 'formik';
import { TextField } from '@mui/material';

function App() {
  return (
    <Formik
      initialValues={{ name: '' }}
      onSubmit={(values) => {
        alert(JSON.stringify(values, null, 2));
      }}
    >
      {({ handleSubmit }) => (
        <Form onSubmit={handleSubmit}>
          <Field
            component={TextField}
            name="name"
            type="text"
            label="Name"
            fullWidth
            margin="normal"
            variant="outlined"
          />
          <ErrorMessage name="name" component="div" />
          <Button type="submit" variant="contained" color="primary">
            Submit
          </Button>
        </Form>
      )}
    </Formik>
  );
}

Validation

Add validation to your form fields.

import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
import { TextField } from '@mui/material';

const validationSchema = Yup.object({
  name: Yup.string().min(5, 'Must be 5 characters or more').required('Required'),
});

function App() {
  return (
    <Formik
      initialValues={{ name: '' }}
      validationSchema={validationSchema}
      onSubmit={(values) => {
        alert(JSON.stringify(values, null, 2));
      }}
    >
      {({ handleSubmit }) => (
        <Form onSubmit={handleSubmit}>
          <Field
            component={TextField}
            name="name"
            type="text"
            label="Name"
            fullWidth
            margin="normal"
            variant="outlined"
          />
          <ErrorMessage name="name" component="div" />
          <Button type="submit" variant="contained" color="primary">
            Submit
          </Button>
        </Form>
      )}
    </Formik>
  );
}

Best Practices

Accessibility

Ensure your app is accessible to all users.

Keyboard Navigation

Provide keyboard navigation for all buttons and links.

<Button onClick={handleClick} tabIndex={0}>
  Click Me
</Button>

Screen Reader Support

Use ARIA attributes to improve screen reader support.

<Button aria-label="delete" onClick={handleClick}>
  Delete
</Button>

Accessibility Tips

Always test your app with screen readers and keyboard navigation tools to ensure accessibility.

Performance Optimization

Enhance the performance of your app.

Server-Side Rendering

Use server-side rendering for better performance.

// Setup for server-side rendering involves configuring your server to render React apps on the server-side.
// This is more complex and requires setting up a Node.js server with Next.js or another framework.

Lazy Loading

Lazy load components to improve load times.

const About = React.lazy(() => import('./About'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <About />
      </Suspense>
    </div>
  );
}

Code Splitting

Split your code into smaller chunks.

const AnotherComponent = React.lazy(() => import('./AnotherComponent'));

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <AnotherComponent />
      </Suspense>
    </div>
  );
}

Troubleshooting

Common Issues

Problem 1 - Components not rendering correctly

Ensure you have the correct imports and that your components are correctly set up.

Solution

Check your imports and component setup.

// Ensure you have the correct imports
import Button from '@mui/material/Button';

function App() {
  return (
    <div>
      <Button variant="contained">Contained Button</Button>
    </div>
  );
}

Problem 2 - Theme not applied

Ensure your theme is correctly wrapped around your app.

Solution

Wrap your app with ThemeProvider.

import React from 'react';
import ReactDOM from 'react-dom';
import { ThemeProvider } from '@mui/material/styles';
import theme from './theme';
import App from './App';

ReactDOM.render(
  <ThemeProvider theme={theme}>
    <App />
  </ThemeProvider>,
  document.getElementById('root')
);

Conclusion

Summary of Key Points

  • Material UI provides a set of React components following Material Design principles.
  • Customization is extensive, allowing you to match your brand's design.
  • Use dialogs, snackbars, and menus for interactive elements.
  • Enhance accessibility and performance for a better user experience.

Further Resources

Material UI Documentation

Explore the official Material UI documentation for more information and examples.

Community Forums

Join the Material UI community to connect with other developers.

Additional Tutorials

Check out additional tutorials and guides: