MaterialUI

Material UI is a popular React UI framework.

Installation

The framework:

// with npm
npm install @material-ui/core
// with yarn
yarn add @material-ui/core

Fonts and icons:

Material-UI relies on certain fonts and icons. They must be added to the HTML file.

Roboto font:

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />

Font icon:

<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" />

SVG Icons:

We must install the @material-ui/icons package if we want to use the prebuilt SVG material icons.

// with npm
npm install @material-ui/icons
// with yarn
yarn add @material-ui/icons

Useful Components

Layout Components

Container

Container centers content horizontally. It is the most basic layout component.

API: https://material-ui.com/api/container/

Example:

import React from 'react';
import CssBaseline from '@material-ui/core/CssBaseline';
import Typography from '@material-ui/core/Typography';
import Container from '@material-ui/core/Container';
export default function SimpleContainer() {
return (
<React.Fragment>
<CssBaseline />
<Container maxWidth="sm">
<Typography component="div" style={{ backgroundColor: '#cfe8fc', height: '100vh' }} />
</Container>
</React.Fragment>
);
}

Table

Table presents data in a tabular format. It comprises a number of smaller components.

API: https://material-ui.com/components/tables/

Example:

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableContainer from '@material-ui/core/TableContainer';
import TableHead from '@material-ui/core/TableHead';
import TableRow from '@material-ui/core/TableRow';
import Paper from '@material-ui/core/Paper';
const useStyles = makeStyles({
table: {
minWidth: 650,
},
});
function createData(name, calories, fat, carbs, protein) {
return { name, calories, fat, carbs, protein };
}
const rows = [
createData('Frozen yoghurt', 159, 6.0, 24, 4.0),
createData('Ice cream sandwich', 237, 9.0, 37, 4.3),
createData('Eclair', 262, 16.0, 24, 6.0),
createData('Cupcake', 305, 3.7, 67, 4.3),
createData('Gingerbread', 356, 16.0, 49, 3.9),
];
export default function SimpleTable() {
const classes = useStyles();
return (
<TableContainer component={Paper}>
<Table className={classes.table} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>Dessert (100g serving)</TableCell>
<TableCell align="right">Calories</TableCell>
<TableCell align="right">Fat&nbsp;(g)</TableCell>
<TableCell align="right">Carbs&nbsp;(g)</TableCell>
<TableCell align="right">Protein&nbsp;(g)</TableCell>
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.name}>
<TableCell component="th" scope="row">
{row.name}
</TableCell>
<TableCell align="right">{row.calories}</TableCell>
<TableCell align="right">{row.fat}</TableCell>
<TableCell align="right">{row.carbs}</TableCell>
<TableCell align="right">{row.protein}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}

Surfaces

App Bar

The app bar displays information and actions related to the current screen. In other words, it is the bar at the top of most Android applications. The content inside this App Bar is actually defined within the ToolBar component.

API:

Example:

// Simple App Bar
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import MenuIcon from '@material-ui/icons/Menu';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
}));
export default function ButtonAppBar() {
const classes = useStyles();
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
News
</Typography>
<Button color="inherit">Login</Button>
</Toolbar>
</AppBar>
</div>
);
}

Information Display

Typography

Essentially, this component displays texts.

API:

Example:

// All variations of Typography component
import React from 'react';
import Typography from '@material-ui/core/Typography';
import { makeStyles } from '@material-ui/core/styles';
const useStyles = makeStyles({
root: {
width: '100%',
maxWidth: 500,
},
});
export default function Types() {
const classes = useStyles();
return (
<div className={classes.root}>
<Typography variant="h1" component="h2" gutterBottom>
h1. Heading
</Typography>
<Typography variant="h2" gutterBottom>
h2. Heading
</Typography>
<Typography variant="h3" gutterBottom>
h3. Heading
</Typography>
<Typography variant="h4" gutterBottom>
h4. Heading
</Typography>
<Typography variant="h5" gutterBottom>
h5. Heading
</Typography>
<Typography variant="h6" gutterBottom>
h6. Heading
</Typography>
<Typography variant="subtitle1" gutterBottom>
subtitle1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
</Typography>
<Typography variant="subtitle2" gutterBottom>
subtitle2. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
</Typography>
<Typography variant="body1" gutterBottom>
body1. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
unde suscipit, quam beatae rerum inventore consectetur, neque doloribus, cupiditate numquam
dignissimos laborum fugiat deleniti? Eum quasi quidem quibusdam.
</Typography>
<Typography variant="body2" gutterBottom>
body2. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quos blanditiis tenetur
unde suscipit, quam beatae rerum inventore consectetur, neque doloribus, cupiditate numquam
dignissimos laborum fugiat deleniti? Eum quasi quidem quibusdam.
</Typography>
<Typography variant="button" display="block" gutterBottom>
button text
</Typography>
<Typography variant="caption" display="block" gutterBottom>
caption text
</Typography>
<Typography variant="overline" display="block" gutterBottom>
overline text
</Typography>
</div>
);
}

@material-ui/system

This module provide style functions to building design systems.

Example:

import React from 'react';
import styled, { ThemeProvider } from 'styled-components';
import NoSsr from '@material-ui/core/NoSsr';
import { createMuiTheme } from '@material-ui/core/styles';
import { palette, spacing, typography } from '@material-ui/system';
const Box = styled.div`${palette}${spacing}${typography}`;
// or import Box from '@material-ui/core/Box';
const theme = createMuiTheme();
export default function Demo() {
return (
<NoSsr>
<ThemeProvider theme={theme}>
<Box
color="primary.main"
bgcolor="background.paper"
fontFamily="h6.fontFamily"
fontSize={{ xs: 'h6.fontSize', sm: 'h4.fontSize', md: 'h3.fontSize' }}
p={{ xs: 2, sm: 3, md: 4 }}
>
@material-ui/system
</Box>
</ThemeProvider>
</NoSsr>
);
}

Styling

Material-UI uses a CSS-in-JS solution, which essentially generate CSS file dynamically at run time according to the declaration in the JS script. Under the hood, it uses a library called JSS. Thus, to understand how to style in Material-UI, it is necessary to understand how JSS works.

JSS

JSS uses a "style object" to describe the style of HTML elements. The syntax of JSS can be found here:

https://cssinjs.org/jss-syntax?v=v10.0.0-alpha.9

Usage in React is as follows:

// Source
import React from 'react'
import {render} from 'react-dom'
import {createUseStyles} from 'react-jss'
// Create your Styles. Remember, since React-JSS uses the default preset,
// most plugins are available without further configuration needed.
const useStyles = createUseStyles({
myButton: {
color: 'green',
margin: {
// jss-plugin-expand gives more readable syntax
top: 5, // jss-plugin-default-unit makes this 5px
right: 0,
bottom: 0,
left: '1rem'
},
'& span': {
// jss-plugin-nested applies this to a child span
fontWeight: 'bold' // jss-plugin-camel-case turns this into 'font-weight'
}
},
myLabel: {
fontStyle: 'italic'
}
})
// Define the component using these styles and pass it the 'classes' prop.
// Use this to assign scoped class names.
const Button = ({children}) => {
const classes = useStyles()
return (
<button className={classes.myButton}>
<span className={classes.myLabel}>{children}</span>
</button>
)
}
const App = () => <Button>Submit</Button>
render(<App />, document.getElementById('root'))
<----!>Compiled HTML</----!>
<div id="root">
<button class="Button-myButton-1-25">
<span class="Button-myLabel-1-26">
Submit
</span>
</button>
</div>
# Compiled CSS
.Button-myButton-1-25 {
color: green;
margin: 5px 0 0 1rem;
}
.Button-myButton-1-25 span {
font-weight: bold;
}
.Button-myLabel-1-26 {
font-style: italic;
}

Usage

Quick start example:

import React from 'react';
import ReactDOM from 'react-dom';
import Button from '@material-ui/core/Button';
function App() {
return (
<Button variant="contained" color="primary">
Hello World
</Button>
);
}
ReactDOM.render(<App />, document.querySelector('#app'));

Create-React-App example:

/public/index.html and /public/manifest.json

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width" />
<meta name="theme-color" content="#000000" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>My page</title>
<!-- Fonts to support Material Design -->
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
// This is manifest.json
{
"short_name": "Your Orders",
"name": "Your Orders",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

/src/index.js and Theme Provider

import React from 'react';
import ReactDOM from 'react-dom';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ThemeProvider } from '@material-ui/core/styles';
import App from './App';
import theme from './theme';
// Note the use of ThemeProvider and CssBaseline
// The rest is simply React
ReactDOM.render(
<ThemeProvider theme={theme}>
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
<CssBaseline />
<App />
</ThemeProvider>,
document.querySelector('#root'),
);
import { red } from '@material-ui/core/colors';
import { createMuiTheme } from '@material-ui/core/styles';
// A custom theme for this app
const theme = createMuiTheme({
palette: {
primary: {
main: '#556cd6',
},
secondary: {
main: '#19857b',
},
error: {
main: red.A400,
},
background: {
default: '#fff',
},
},
});
export default theme;

/src/App.js and other components

// This is /src/App.js
import React from 'react';
// These are components retrieved from the material-ui library
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography';
import Box from '@material-ui/core/Box';
import Link from '@material-ui/core/Link';
// ProTip is a component developed in this project
import ProTip from './ProTip';
// Copyright is a new React component that uses the components from Material UI
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
// Export a component App as the default
export default function App() {
return (
<Container maxWidth="sm">
<Box my={4}>
<Typography variant="h4" component="h1" gutterBottom>
Create React App v4-beta example
</Typography>
<ProTip />
<Copyright />
</Box>
</Container>
);
}
// /src/ProTip.js
// This is a component developed in this project.
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Link from '@material-ui/core/Link';
import SvgIcon from '@material-ui/core/SvgIcon';
import Typography from '@material-ui/core/Typography';
function LightBulbIcon(props) {
return (
<SvgIcon {...props}>
<path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z" />
</SvgIcon>
);
}
// Restyling the component
const useStyles = makeStyles((theme) => ({
root: {
margin: theme.spacing(6, 0, 3),
},
lightBulb: {
verticalAlign: 'middle',
marginRight: theme.spacing(1),
},
}));
export default function ProTip() {
const classes = useStyles();
return (
<Typography className={classes.root} color="textSecondary">
<LightBulbIcon className={classes.lightBulb} />
Pro tip: See more{' '}
<Link href="https://material-ui.com/getting-started/templates/">templates</Link> on the
Material-UI documentation.
</Typography>
);
}

Miscs.

Some important globals to care about:

Note that when we use create-react-app to build a React app, we will have an /public/index.html file. In this file, we can make whatever modification to the <head> of HTML.

Responsive Meta Tag

Material-UI is developed mobile-first, and then scale up components as necessary using CSS media queries. Therefore, to ensure proper rendering and touch zooming for all devices, add the following responsive viewport meta tag to the <head> element:

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

Generating dynamic meta tags on Server

<!DOCTYPE html>
<html lang="en">
<head>
<meta property="og:title" content="__OG_TITLE__" />
<meta property="og:description" content="__OG_DESCRIPTION__" />
</head>
</html>

Then, on the server, regardless of the backend you use, you can read index.html into memory and replace __OG_TITLE__, __OG_DESCRIPTION__, and any other placeholders with values depending on the current URL. Make sure to sanitize and escape the interpolated values so that they are safe to embed into HTML!

Injecting Data from the Server into the Page

<!doctype html>
<html lang="en">
<head>
<script>
window.SERVER_DATA = __SERVER_DATA__;
</script>

Then, on the server, you can replace __SERVER_DATA__ with a JSON of real data right before sending the response. The client code can then read window.SERVER_DATA to use it. Make sure to sanitize the JSON before sending it to the client as it makes your app vulnerable to XSS attacks.