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 steppers with Material UI.
Stepper
A stepper lets us show the steps that a user has to go through to complete a process.
To use it, we can use the Stepper
component add the stepper:
import React from "react";
import Stepper from "@material-ui/core/Stepper";
import Step from "@material-ui/core/Step";
import StepLabel from "@material-ui/core/StepLabel";
import Button from "@material-ui/core/Button";
function getSteps() {
return ["step 1", "step 2", "step 3"];
}
function getStepContent(step) {
switch (step) {
case 0:
return "do step 1";
case 1:
return "do step 2";
case 2:
return "do steo 3";
default:
return "unknown step";
}
}
export default function App() {
const [activeStep, setActiveStep] = React.useState(0);
const [skipped, setSkipped] = React.useState(new Set());
const steps = getSteps();
const isStepOptional = step => {
return step === 1;
};
const isStepSkipped = step => {
return skipped.has(step);
};
const handleNext = () => {
let newSkipped = skipped;
if (isStepSkipped(activeStep)) {
newSkipped = new Set(newSkipped.values());
newSkipped.delete(activeStep);
}
setActiveStep(prevActiveStep => prevActiveStep + 1);
setSkipped(newSkipped);
};
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1);
};
const handleSkip = () => {
if (!isStepOptional(activeStep)) {
throw new Error("You can't skip a step that isn't optional.");
}
setActiveStep(prevActiveStep => prevActiveStep + 1);
setSkipped(prevSkipped => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
};
const handleReset = () => {
setActiveStep(0);
};
return (
<div>
<Stepper activeStep={activeStep}>
{steps.map((label, index) => {
const stepProps = {};
const labelProps = {};
if (isStepOptional(index)) {
labelProps.optional = "optional";
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label} {...stepProps}>
<StepLabel {...labelProps}>{label}</StepLabel>
</Step>
);
})}
</Stepper>
<div>
{activeStep === steps.length ? (
<div>
All steps completed
<Button onClick={handleReset}>Reset</Button>
</div>
) : (
<div>
{getStepContent(activeStep)}
<div>
<Button disabled={activeStep === 0} onClick={handleBack}>
Back
</Button>
{isStepOptional(activeStep) && (
<Button
variant="contained"
color="primary"
onClick={handleSkip}
>
Skip
</Button>
)}
<Button variant="contained" color="primary" onClick={handleNext}>
{activeStep === steps.length - 1 ? "Finish" : "Next"}
</Button>
</div>
</div>
)}
</div>
</div>
);
}
We create the step headings with the getSteps
function.
The content of each step is in the getStepContent
function.
When we click the Next button, handleNext
is called.
Then we add the steps that are added to the skipped
state.
handleBack
is run when the back button is clicked.
We just set the activeStep
to the previous step.
The handleSkip
function is called when the skip button is clicked.
We check if an active step is optional.
If it’s optional, then we let them skip it and add it to the skipped
set.
In the JSX code, we use the Stepper
component with the Step
prop to add the steps.
Then we add the content for the step and the buttons below it.
The content is shown according to the activeStep
value.
Alternative Label
We can change the step labels to what we want with the StepLabel
component.
For instance, we can write:
import React from "react";
import Stepper from "@material-ui/core/Stepper";
import Step from "@material-ui/core/Step";
import StepLabel from "@material-ui/core/StepLabel";
import Button from "@material-ui/core/Button";
function getSteps() {
return ["step 1", "step 2", "step 3"];
}
function getStepContent(step) {
switch (step) {
case 0:
return "do step 1";
case 1:
return "do step 2";
case 2:
return "do steo 3";
default:
return "unknown step";
}
}
export default function App() {
const [activeStep, setActiveStep] = React.useState(0);
const steps = getSteps();
const handleNext = () => {
setActiveStep(prevActiveStep => prevActiveStep + 1);
};
const handleBack = () => {
setActiveStep(prevActiveStep => prevActiveStep - 1);
};
const handleReset = () => {
setActiveStep(0);
};
return (
<div>
<Stepper activeStep={activeStep} alternativeLabel>
{steps.map(label => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<div>
{activeStep === steps.length ? (
<div>
All steps completed
<Button onClick={handleReset}>Reset</Button>
</div>
) : (
<div>
{getStepContent(activeStep)}
<div>
<Button disabled={activeStep === 0} onClick={handleBack}>
Back
</Button>
<Button variant="contained" color="primary" onClick={handleNext}>
{activeStep === steps.length - 1 ? "Finish" : "Next"}
</Button>
</div>
</div>
)}
</div>
</div>
);
}
We added the alternativeLabel
prop to let us override the label.
Then in the render children prop, we return our own Step
component with the StepLabel
to display the step number.
Conclusion
We can add a stepper with the Stepper
component.
We can make steps optional and customize the labels.
The content can be displayed below it.