Typical material-ui stepper below.
export default function HorizontalLinearStepper() {
const classes = useStyles();
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)) {
// You probably want to guard against something like this,
// it should never occur unless someone's actively trying to break something.
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 className={classes.root}>
<Stepper activeStep={activeStep}>
{steps.map((label, index) => {
const stepProps = {};
const labelProps = {};
if (isStepOptional(index)) {
labelProps.optional = <Typography variant="caption">Optional</Typography>;
}
if (isStepSkipped(index)) {
stepProps.completed = false;
}
return (
<Step key={label} {...stepProps}>
<StepLabel {...labelProps}>{label}</StepLabel>
</Step>
);
})}
</Stepper>
<div>
{activeStep === steps.length ? (
<div>
<Typography className={classes.instructions}>
All steps completed - you're finished
</Typography>
<Button onClick={handleReset} className={classes.button}>
Reset
</Button>
</div>
) : (
<div>
<div className={classes.instructions}>{getStepContent(activeStep)}</div>
<div>
<Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
Back
</Button>
{isStepOptional(activeStep) && (
<Button
variant="contained"
color="primary"
onClick={handleSkip}
className={classes.button}
>
Skip
</Button>
)}
<Button
variant="contained"
color="primary"
onClick={handleNext}
type="submit"
className={classes.button}
>
{activeStep === steps.length - 1 ? 'Finish' : 'Next'}
</Button>
</div>
</div>
)}
</div>
</div>
);
}
Here is function i create to choice step
function getStepContent(step) {
switch (step) {
case 0:
return <Step1/>;
case 1:
return <Step2/>;
case 2:
return 'This is the bit I really care about!';
default:
return 'Unknown step';
}
}
Step1 and Step2 are components that has 2 forms inside build with react-final-form
import React, { Component } from 'react';
import { Form } from 'react-final-form';
import initialValuesCreator from './creationMethods/initialValuesCreator';
import { validationCreator } from './creationMethods/validationSchemaCreator';
class CustomValidationForm extends Component {
render() {
const {
config ,children, submit = () => {}
} = this.props;
return (
<Form
onSubmit={(event) => {
submit(event);
}}
initialValues={initialValuesCreator(config)}
validate={values => validationCreator(values, config)}
render={({handleSubmit}) => (
<form noValidate autoComplete={'off'} onSubmit={handleSubmit}>
{children}
</form>
)}
/>
)
}
}
And here comes the question. Material ui stepper has handleNext function. Its my submit for each step. Each step will be some kind of form with validation. When user is on step1 and he press submit i want to show him input errors (something is required etc) and prevent jumping to next step. Step1 can have multiple small forms so all the form should be validated when handleNext is pressed.