import "./formik-demo.css";
import React from "react";
import { render } from "react-dom";
import { Formik, Field } from "formik";
import Yup from "yup";
import classNames from "classnames";
// Input feedback
const InputFeedback = ({ error }) =>
error ? <div className={classNames("input-feedback")}>{error}</div> : null;
// Checkbox input
const Checkbox = ({
field: { name, value, onChange, onBlur },
form: { errors, touched, setFieldValue },
id,
label,
className,
...props
}) => {
return (
<div>
<input
name={name}
id={id}
type="checkbox"
value={value}
checked={value}
onChange={onChange}
onBlur={onBlur}
className={classNames("radio-button")}
/>
<label htmlFor={id}>{label}</label>
{touched[name] && <InputFeedback error={errors[name]} />}
</div>
);
};
// Checkbox group
class CheckboxGroup extends React.Component {
constructor(props) {
super(props);
}
handleChange = event => {
const target = event.currentTarget;
let valueArray = [...this.props.value] || [];
if (target.checked) {
valueArray.push(target.id);
} else {
valueArray.splice(valueArray.indexOf(target.id), 1);
}
this.props.onChange(this.props.id, valueArray);
};
handleBlur = () => {
// take care of touched
this.props.onBlur(this.props.id, true);
};
render() {
const { value, error, touched, label, className, children } = this.props;
const classes = classNames(
"input-field",
{
"is-success": value || (!error && touched), // handle prefilled or user-filled
"is-error": !!error && touched
},
className
);
return (
<div className={classes}>
<fieldset>
<legend>{label}</legend>
{React.Children.map(children, child => {
return React.cloneElement(child, {
field: {
value: value.includes(child.props.id),
onChange: this.handleChange,
onBlur: this.handleBlur
}
});
})}
{touched && <InputFeedback error={error} />}
</fieldset>
</div>
);
}
}
// Radio input
const RadioButton = ({
field: { name, value, onChange, onBlur },
id,
label,
className,
...props
}) => {
return (
<div>
<input
name={name}
id={id}
type="radio"
value={id} // could be something else for output?
checked={id === value}
onChange={onChange}
onBlur={onBlur}
className={classNames("radio-button")}
{...props}
/>
<label htmlFor={id}>{label}</label>
</div>
);
};
// Radio group
const RadioButtonGroup = ({
value,
error,
touched,
id,
label,
className,
children
}) => {
const classes = classNames(
"input-field",
{
"is-success": value || (!error && touched), // handle prefilled or user-filled
"is-error": !!error && touched
},
className
);
return (
<div className={classes}>
<fieldset>
<legend>{label}</legend>
{children}
{touched && <InputFeedback error={error} />}
</fieldset>
</div>
);
};
const App = () => (
<div className="app">
<h1>Radio & checkbox inputs with Formik</h1>
<Formik
initialValues={{
radioGroup: "",
checkboxGroup: [],
singleCheckbox: false
}}
validationSchema={Yup.object().shape({
radioGroup: Yup.string().required("A radio option is required"),
checkboxGroup: Yup.array().required(
"At least one checkbox is required"
),
singleCheckbox: Yup.bool().oneOf([true], "Must agree to something")
})}
onSubmit={(values, actions) => {
setTimeout(() => {
console.log(JSON.stringify(values, null, 2));
actions.setSubmitting(false);
}, 500);
}}
render={({
handleSubmit,
setFieldValue,
setFieldTouched,
values,
errors,
touched,
isSubmitting
}) => (
<form onSubmit={handleSubmit}>
<h2>Single checkbox</h2>
<Field
component={Checkbox}
name="singleCheckbox"
id="singleCheckbox"
label="Agree to something"
/>
<h2>Checkbox group</h2>
<CheckboxGroup
id="checkboxGroup"
label="Which of these?"
value={values.checkboxGroup}
error={errors.checkboxGroup}
touched={touched.checkboxGroup}
onChange={setFieldValue}
onBlur={setFieldTouched}
>
<Field
component={Checkbox}
name="checkboxGroup"
id="checkbox1"
label="Option 1"
/>
<Field
component={Checkbox}
name="checkboxGroup"
id="checkbox2"
label="Option 2"
/>
<Field
component={Checkbox}
name="checkboxGroup"
id="checkbox3"
label="Option 3"
/>
</CheckboxGroup>
<h2>Radio group</h2>
<RadioButtonGroup
id="radioGroup"
label="One of these please"
value={values.radioGroup}
error={errors.radioGroup}
touched={touched.radioGroup}
>
<Field
component={RadioButton}
name="radioGroup"
id="radioOption1"
label="Choose this option"
/>
<Field
component={RadioButton}
name="radioGroup"
id="radioOption2"
label="Or choose this one"
/>
</RadioButtonGroup>
<h2>Single radio</h2>
<p>Is that a valid use case?</p>
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</form>
)}
/>
</div>
);
render(<App />, document.getElementById("root"));
Created
October 15, 2018 01:31
-
-
Save mrtony/c1ba5f8ec4122d2866b292fc36152d34 to your computer and use it in GitHub Desktop.
React formik yup checkbox, radio button validation
Thanks @mrtony.
Here is working demo: https://codesandbox.io/s/react-formik-yup-checkbox-radio-inputs-8q322
this helped me a lot with the group radio button validation. Thanks
yup
Amazing, this should be in the React Bootstrap documentation! Their docs have nothing about Radio validation.
wow!
Great example. Helped me a lot . Thanks
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is a very useful example. Thanks.
Was struggling to handle "radio" button validation with Formik and Yup.