This guide will discuss the step-by-step process of creating and styling a React app with Material UI.
This app will use the character endpoint of the Final Space API, a free RESTful API that provides information about characters, episodes, and locations of the Final Space TV show.
This guide assumes you already know how to install and configure Material UI in a React app. You can read Installing and Using Material UI with React to get started.
You can use a Create React App template to quickly initialize a React project without doing any manual configurations.
In your project's root directory, run the following command.
1npx create-react-app react-material-ui-example
2cd react-material-ui-example
To install Material-UI, run the following command in your React project's root directory.
1npm install @material-ui/core
Add the following code to the <head>
tag of your public/index.html
file.
1<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
Delete App.css
, index.css
, logo.svg
from the src
directory.
Remove index.css
import from the src/index.js
file.
1// src/index.js
2import React from 'react';
3import ReactDOM from 'react-dom';
4import App from './App';
5
6ReactDOM.render(
7 <React.StrictMode>
8 <App />
9 </React.StrictMode>,
10 document.getElementById('root')
11);
Modify your src/App.js
file like this.
1// src/App.js
2import React, { useEffect, useState } from "react";
3
4function App() {
5 return <div></div>;
6}
7
8export default App;
Start the development server by running the following command in the terminal.
1npm start
Navigate to http://localhost:3000; you will see a blank page since your app is currently empty.
First, you need to fetch data from the /character
endpoint of the Final Space API. You can do this by using fetch()
inside the useEffect()
hook and storing the response data inside the state variable. You can also use axios
to make API requests.
By providing an empty array as a second argument to useEffect()
, you can ensure that the request is made only after the initial render.
1function App() {
2 const [data, setData] = useState([]);
3 useEffect(() => {
4 fetch("https://finalspaceapi.com/api/v0/character/?limit=12")
5 .then((res) => res.json())
6 .then((data) => setData(data));
7 }, []);
8
9 return <div></div>;
10}
11
12export default App;
In the above code, you have limited the response from the endpoint by passing the /?limit=12
query in the URL.
Now, you will use the Container
component to add some margins to the app.
Import Container
from the Material-UI library.
1import Container from "@material-ui/core/Container";
Now, use it inside the App()
function.
1return (
2 <div>
3 <Container> </Container>
4 </div>
5);
You will not see any change on your app, but some margins have been added to it, which will be apparent after adding other components inside Container
.
Your app needs a heading; for this, use the Typography
component of the Material-UI library. Import this component in App.js
file.
1import Typography from "@material-ui/core/Typography";
Now, use it inside the Container
component.
1<Container>
2 <Typography color="textPrimary" gutterBottom variant="h2" align="center">
3 React Material UI Example
4 </Typography>
5</Container>
Here is how this will look.
These are the props that are used:
gutterBottom
: Adds margin to the bottom of the component.color="textPrimary"
: Specifies the color of the text. You can use textSeconadry
, primary
, etc. also.align="center"
: Center aligns the component.variant="h2"
: Applies the theme typography styles.There are even more props that you can pass to style the Typography
component. You can read about them here.
Next, you need to decide which data to show in your app; this project will display name
, image
, and status
of the character. You can check out the Character Schema and add additional data to the app.
You will import and use Card
,CardMedia
, and CardContent
components to create cards for each character.
1import Card from "@material-ui/core/Card";
2import CardContent from "@material-ui/core/CardContent";
3import CardMedia from "@material-ui/core/CardMedia";
CardContent
is used to show information, and CardMedia
is used to display an image inside the Card
component.
The source of the image goes in the image
prop of the CardMedia
component.
Use the .map()
method on the data
variable to create individual cards for characters. Add the following code after the <Typography>
component.
1{
2 data.map((character) => (
3 <Card
4 style={{
5 maxWidth: 345,
6 boxShadow: "0 5px 8px 0 rgba(0, 0, 0, 0.3)",
7 backgroundColor: "#fafafa",
8 }}
9 >
10 <CardMedia style={{ height: "300px" }} image={character.img_url} />
11 </Card>
12 ))
13}
Here is how your app will look.
In the above code, you have used inline styling to style the Card
and CardImage
components; it works but makes your code look messy.
Luckily, Material-UI provides a solution for this: makeStyles
. Using makeStyles
, you can add CSS in JS without making your code look messy.
First, you need to import makeStyles
in your app.
1import { makeStyles } from "@material-ui/core/styles";
Next, pass all the CSS you need in your app as an object to makeStyles
and store it inside a variable, useStyles
. This code comes before the App()
function. You can create nested objects to style different components.
Here, card
is for styling the Card
component and media
is for styling the CardImage
component.
1const useStyles = makeStyles({
2 card: {
3 maxWidth: 345,
4 boxShadow: "0 5px 8px 0 rgba(0, 0, 0, 0.3)",
5 backgroundColor: "#fafafa",
6 },
7 media: {
8 height: 300,
9 },
10});
11
12function App() {
13 ...
14}
15export default App;
To use this inside App()
function, initialize a variable before the return
statement.
1const classes = useStyles();
And that's it. You can now pass this classes
and the nested object inside it as the className
to style the component.
1{
2 data.map((character) => (
3 <Card className={classes.card}>
4 <CardMedia className={classes.media} image={character.img_url} />
5 </Card>
6 ))
7}
Navigate to http://localhost:3000; you will notice that your app looks just the same as before.
The next step is to add the name
and status
of the character using the CardContent
and Typography
component.
Add the following code inside the Card
component.
1<Card className={classes.card}>
2 <CardMedia className={classes.media} image={character.img_url} />
3 <CardContent>
4 <Typography color="primary" variant="h5">
5 {character.name}
6 </Typography>
7 <Typography color="textSecondary" variant="subtitle2">
8 {character.status}
9 </Typography>
10 </CardContent>
11</Card>
Here is how this will look.
As you can see, here you have used the Typography
component three times, and all of them look entirely different. So the output can change significantly based on what values are passed to a component's prop.
This column of cards doesn't look right. To fix this, you will use the Grid
component to change the app's layout.
First, import the Grid
component in your App.js
file.
1import Grid from "@material-ui/core/Grid";
Next, wrap all the cards inside a Grid
component. You can use two types of layout with Grid,
i.e., item
and container
. Here you will use the container
layout.
1<Grid container spacing={3}>
2 {data.map((character) => (
3 <Card className={classes.card}>
4 <CardMedia className={classes.media} image={character.img_url} />
5 <CardContent>
6 <Typography color="primary" variant="h5">
7 {character.name}
8 </Typography>
9 <Typography color="textSecondary" variant="subtitle2">
10 {character.status}
11 </Typography>
12 </CardContent>
13 </Card>
14 ))}
15</Grid>
Next, wrap each individual card inside the Grid
component with the item
layout.
1{
2 data.map((character) => (
3 <Grid item xs={12} sm={4} key={character.id}>
4 <Card className={classes.card}>
5 <CardMedia className={classes.media} image={character.img_url} />
6 <CardContent>
7 <Typography color="primary" variant="h5">
8 {character.name}
9 </Typography>
10 <Typography color="textSecondary" variant="subtitle2">
11 {character.status}
12 </Typography>
13 </CardContent>
14 </Card>
15 </Grid>
16 ));
17}
When mapping over an array in React, you need to pass a key prop to distinguish each child element. Here, the id
of the character is passed to the key
prop.
In the above code, xs
and sm
grid breakpoints are set as 12
and 4
, respectively. If you are not familiar with grid breakpoints, you can read more about them here.
Here is how your app will look.
Here is the complete code for this app.
1import React, { useEffect, useState } from "react";
2import Container from "@material-ui/core/Container";
3import Card from "@material-ui/core/Card";
4import Typography from "@material-ui/core/Typography";
5import CardContent from "@material-ui/core/CardContent";
6import CardMedia from "@material-ui/core/CardMedia";
7import { makeStyles } from "@material-ui/core/styles";
8import Grid from "@material-ui/core/Grid";
9
10const useStyles = makeStyles({
11 card: {
12 maxWidth: 345,
13 boxShadow: "0 5px 8px 0 rgba(0, 0, 0, 0.3)",
14 backgroundColor: "#fafafa",
15 },
16 media: {
17 height: 300,
18 },
19});
20
21function App() {
22
23 const [data, setData] = useState([]);
24
25 useEffect(() => {
26 fetch("https://finalspaceapi.com/api/v0/character/?limit=12")
27 .then((res) => res.json())
28 .then((data) => setData(data));
29 }, []);
30
31 const classes = useStyles();
32
33 return (
34 <div>
35 <Container>
36 <Typography
37 color="textPrimary"
38 gutterBottom
39 variant="h2"
40 align="center"
41 >
42 React Material UI Example{" "}
43 </Typography>
44 <Grid container spacing={3}>
45 {data.map((character) => (
46 <Grid item xs={12} sm={4} key={character.id}>
47 <Card className={classes.card}>
48 <CardMedia
49 className={classes.media}
50 image={character.img_url}
51 />
52 <CardContent>
53 <Typography color="primary" variant="h5">
54 {character.name}
55 </Typography>
56 <Typography color="textSecondary" variant="subtitle2">
57 {character.status}
58 </Typography>
59 </CardContent>
60 </Card>
61 </Grid>
62 ))}
63 </Grid>
64 </Container>
65 </div>
66 );
67}
68
69export default App;
You can explore this React app here.
This guide demonstrated the step-by-step process of creating and styling a React app with Material UI. You should try to customize this app further with different Material UI components and layouts.
Here are some additional resources that can be helpful.
Happy coding!