The Material UI CircularProgress component is a quick way to give the user visual feedback while waiting for loading.
It can be challenging to get the centering just right when the CircularProgress is nested in a component. Furthermore, the color prop is limited to MUI theme or color object values. We will explore how to get these details perfect when customizing the component.
Here’s what we will build:

My tutorial is based on this MUI documentation example.
Full code and related links are in the Resources section.
Material UI CircularProgress Size
The MUI CircularProgress component has a built-in size
prop. This prop is a quick way to specify the width and height of the component. Here’s how size: 80
renders in the DOM:

The width and height are critical for centering the indicator inside of a component.
Material UI CircularProgress Centering
The CircularProgress component is centered by setting negative margin top and margin left values. This is a manual process that requires knowledge of the component’s size.
In my example I set the CircularIndicator size to a const so I could use it in a calculation for margin.
const indicatorSize = 80;
<CircularProgress
size={indicatorSize}
sx={{
position: 'absolute',
top: '50%',
left: '50%',
marginTop: `${-indicatorSize/2}px`,
marginLeft: `${-indicatorSize/2}px`
}}
/>
Notice how I had to convert my margin values to string with ‘px’. If I passed just a number value, MUI tries to convert it to a theme margin value. Even a number as high as 40 or 80 gets converted to a theme spacing value.
Since we want the CircularIndicator to be centered, we adjust it ‘backwards’ by half it’s height and width.
Material UI CircularProgress Color
The CircularIndicator has a color prop. However, it only accepts string versions of theme values (i.e. ‘secondary.main’) and values from ‘@mui/material/colors’.
If you want a custom color, use the sx
prop color
value. The color prop is affecting the SVG that’s used to render the circle.
Most likely you won’t want to set background color. This should be transparent because background color is applied to the root which is a span that is rotated to achieve the animation effect.
Resources
Additional Links:
- The Essential Guide to the Material-UI Progress Bar: Color, Percent, and More
- How to Make a MUI Horizontal Line Divider (Custom Thickness and Width)
- The Definitive Tutorial on Styling Material-UI Chips
Full Code:
import * as React from "react"
import { Box, Button, CircularProgress } from "@mui/material";
const indicatorSize = 80;
export default function CustomProgressIndicator() {
const [loading, setLoading] = React.useState(false);
const timer = React.useRef<number>();
const handleClick = () => {
if (!loading) {
setLoading(true);
timer.current = window.setTimeout(() => {
setLoading(false);
}, 2000);
}
};
return (
<Box sx={{ m: 1, position: 'relative', display: 'flex', justifyContent: 'center' }}>
<Button
variant="contained"
disabled={loading}
onClick={handleClick}
sx={{width: 200, height: 100}}
>
Submit Results
</Button>
{loading && (
<CircularProgress
size={indicatorSize}
//color='yellow'
sx={{
position: 'absolute',
top: '50%',
left: '50%',
marginTop: `${-indicatorSize/2}px`,
marginLeft: `${-indicatorSize/2}px`,
color: 'gold'
}}
/>
)}
</Box>
);
}