Progress indicators commonly known as spinners, express an unspecified wait time or display the length of a process.
Progress indicators inform users about the status of ongoing processes, such as loading an app, submitting a form, or saving updates.
The animations of the components rely on CSS as much as possible to work even before the JavaScript is loaded.
{{ādemoā: āCircularIndeterminate.jsā}}
{{ādemoā: āCircularColor.jsā}}
{{ādemoā: āCircularSize.jsā}}
{{ādemoā: āCircularDeterminate.jsā}}
{{ādemoā: āCircularIntegration.jsā}}
{{ādemoā: āCircularWithValueLabel.jsā}}
{{ādemoā: āLinearIndeterminate.jsā}}
{{ādemoā: āLinearColor.jsā}}
{{ādemoā: āLinearDeterminate.jsā}}
{{ādemoā: āLinearBuffer.jsā}}
{{ādemoā: āLinearWithValueLabel.jsā}}
The progress components accept a value in the range 0 - 100. This simplifies things for screen-reader users, where these are the default min / max values. Sometimes, however, you might be working with a data source where the values fall outside this range. Hereās how you can easily transform a value in any range to a scale of 0 - 100:
// MIN = Minimum expected value
// MAX = Maximum expected value
// Function to normalise the values (MIN / MAX could be integrated)
const normalise = (value) => ((value - MIN) * 100) / (MAX - MIN);
// Example component that utilizes the `normalise` function at the point of render.
function Progress(props) {
return (
<React.Fragment>
<CircularProgress variant="determinate" value={normalise(props.value)} />
<LinearProgress variant="determinate" value={normalise(props.value)} />
</React.Fragment>
);
}
Here are some examples of customizing the component. You can learn more about this in the overrides documentation page.
import * as React from 'react';
import { styled } from '@mui/material/styles';
import Box from '@mui/material/Box';
import Stack from '@mui/material/Stack';
import CircularProgress, {
circularProgressClasses,
CircularProgressProps,
} from '@mui/material/CircularProgress';
import LinearProgress, { linearProgressClasses } from '@mui/material/LinearProgress';
const BorderLinearProgress = styled(LinearProgress)(({ theme }) => ({
height: 10,
borderRadius: 5,
[`&.${linearProgressClasses.colorPrimary}`]: {
backgroundColor: theme.palette.grey[200],
...theme.applyStyles('dark', {
backgroundColor: theme.palette.grey[800],
}),
},
[`& .${linearProgressClasses.bar}`]: {
borderRadius: 5,
backgroundColor: '#1a90ff',
...theme.applyStyles('dark', {
backgroundColor: '#308fe8',
}),
},
}));
// Inspired by the former Facebook spinners.
function FacebookCircularProgress(props: CircularProgressProps) {
return (
<Box sx={{ position: 'relative' }}>
<CircularProgress
variant="determinate"
sx={(theme) => ({
color: theme.palette.grey[200],
...theme.applyStyles('dark', {
color: theme.palette.grey[800],
}),
})}
size={40}
thickness={4}
{...props}
value={100}
/>
<CircularProgress
variant="indeterminate"
disableShrink
sx={(theme) => ({
color: '#1a90ff',
animationDuration: '550ms',
position: 'absolute',
left: 0,
[`& .${circularProgressClasses.circle}`]: {
strokeLinecap: 'round',
},
...theme.applyStyles('dark', {
color: '#308fe8',
}),
})}
size={40}
thickness={4}
{...props}
/>
</Box>
);
}
// From https://github.com/mui/material-ui/issues/9496#issuecomment-959408221
function GradientCircularProgress() {
return (
<React.Fragment>
<svg width={0} height={0}>
<defs>
<linearGradient id="my_gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stopColor="#e01cd5" />
<stop offset="100%" stopColor="#1CB5E0" />
</linearGradient>
</defs>
</svg>
<CircularProgress sx={{ 'svg circle': { stroke: 'url(#my_gradient)' } }} />
</React.Fragment>
);
}
export default function CustomizedProgressBars() {
return (
<Stack spacing={2} sx={{ flexGrow: 1 }}>
<FacebookCircularProgress />
<GradientCircularProgress />
<br />
<BorderLinearProgress variant="determinate" value={50} />
</Stack>
);
}
There are 3 important limits to know around response time.
The ripple effect of the ButtonBase
component ensures that the user feels that the UI is reacting instantaneously.
Normally, no special feedback is necessary during delays of more than 0.1 but less than 1.0 second.
After 1.0 second, you can display a loader to keep userās flow of thought uninterrupted.
{{ādemoā: āDelayingAppearance.jsā}}
Under heavy load, you might lose the stroke dash animation or see random CircularProgress
ring widths.
You should run processor intensive operations in a web worker or by batch in order not to block the main rendering thread.
When itās not possible, you can leverage the disableShrink
prop to mitigate the issue.
See this issue.
{{ādemoā: āCircularUnderLoad.jsā}}
The LinearProgress
uses a transition on the CSS transform property to provide a smooth update between different values.
The default transition duration is 200ms.
In the event a parent component updates the value
prop too quickly, you will at least experience a 200ms delay between the re-render and the progress bar fully updated.
If you need to perform 30 re-renders per second or more, we recommend disabling the transition:
.MuiLinearProgress-bar {
transition: none;
}