Material UI is a Material Design library made for React.
It’s a set of React components that have Material Design styles.
In this article, we’ll look at how to add progress spinner with Material UI.
Interactive Integration
We can add the spinner to buttons and floating action buttons.
For example, we can write:
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import CircularProgress from "@material-ui/core/CircularProgress";
import { pink } from "@material-ui/core/colors";
import Fab from "@material-ui/core/Fab";
import CheckIcon from "@material-ui/icons/Check";
import SaveIcon from "@material-ui/icons/Save";
import clsx from "clsx";
const useStyles = makeStyles(theme => ({
root: {
display: "flex",
alignItems: "center"
},
wrapper: {
margin: theme.spacing(1),
position: "relative"
},
fabProgress: {
color: pink[500],
position: "absolute",
top: -6,
left: -6,
zIndex: 1
}
}));
export default function App() {
const classes = useStyles();
const [loading, setLoading] = React.useState(false);
const [success, setSuccess] = React.useState(false);
const timer = React.useRef();
const buttonClassname = clsx({
[classes.buttonSuccess]: success
});
React.useEffect(() => {
return () => {
clearTimeout(timer.current);
};
}, []);
const handleButtonClick = () => {
if (!loading) {
setSuccess(false);
setLoading(true);
timer.current = setTimeout(() => {
setSuccess(true);
setLoading(false);
}, 1000);
}
};
return (
<div className={classes.root}>
<div className={classes.wrapper}>
<Fab
aria-label="save"
color="primary"
className={buttonClassname}
onClick={handleButtonClick}
>
{success ? <CheckIcon /> : <SaveIcon />}
</Fab>
{loading && (
<CircularProgress size={68} className={classes.fabProgress} />
)}
</div>
</div>
);
}
to add a loading spinner around a floating action button.
We have to set the fabProgress
class to move the spinner so that it wraps around the floating action button.
Also, we have to change the spacing with the wrapper
class to make the button align with the spinner.
When we click on the button, the handleButtonClick
function is run.
This sets the loading
state to true
.
This will trigger the spinner to show.
Then after 1 second, we set the loading
state to false
in the useEffect
callback.
The success
state would be set to true
there and we see the checkmark icon.
Likewise, we can do the same with buttons.
For example, we can write:
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import CircularProgress from "@material-ui/core/CircularProgress";
import { pink } from "@material-ui/core/colors";
import Button from "@material-ui/core/Button";
import clsx from "clsx";
const useStyles = makeStyles(theme => ({
root: {
display: "flex",
alignItems: "center"
},
wrapper: {
margin: theme.spacing(1),
position: "relative"
},
buttonProgress: {
color: pink[500],
position: "absolute",
top: "50%",
left: "50%",
marginTop: -12,
marginLeft: -12
}
}));
export default function App() {
const classes = useStyles();
const [loading, setLoading] = React.useState(false);
const [success, setSuccess] = React.useState(false);
const timer = React.useRef();
const buttonClassname = clsx({
[classes.buttonSuccess]: success
});
React.useEffect(() => {
return () => {
clearTimeout(timer.current);
};
}, []);
const handleButtonClick = () => {
if (!loading) {
setSuccess(false);
setLoading(true);
timer.current = setTimeout(() => {
setSuccess(true);
setLoading(false);
}, 1000);
}
};
return (
<div className={classes.root}>
<div className={classes.wrapper}>
<Button
variant="contained"
color="primary"
className={buttonClassname}
disabled={loading}
onClick={handleButtonClick}
>
save
</Button>
{loading && (
<CircularProgress size={24} className={classes.buttonProgress} />
)}
</div>
</div>
);
}
to add a save button with a spinner in the middle.
The logic is the same as the floating action button.
But we have different styles for the spinner to position it in the button.
Circular Spinner with Label
We can display the progress within the circular spinner.
For example, we can write:
import React from "react";
import CircularProgress from "@material-ui/core/CircularProgress";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
export default function App() {
const [progress, setProgress] = React.useState(10);
React.useEffect(() => {
const timer = setInterval(() => {
setProgress(prevProgress =>
prevProgress >= 100 ? 10 : prevProgress + 10
);
}, 800);
return () => {
clearInterval(timer);
};
}, []);
return (
<div>
<Box position="relative" display="inline-flex">
<CircularProgress variant="static" value={progress} />
<Box
top={0}
left={0}
bottom={0}
right={0}
position="absolute"
display="flex"
alignItems="center"
justifyContent="center"
>
<Typography
variant="caption"
component="div"
color="textSecondary"
>{`${Math.round(progress)}%`}</Typography>
</Box>
</Box>
</div>
);
}
to add a progress spinner with a number of animation inside it to show the progress.
We just put a Box
to show the text.
The Box
has an absolute position and we set alignItems
and justifyContent
to center
to center the text in the spinner.
Conclusion
We can add spinners within buttons or around floating action buttons.
Also, we can display the progress inside the circular progress spinner.