Provide valuable, actionable feedback to your users with HTML5 form validation, via browser default behaviors or custom styles and JavaScript.
For custom React Bootstrap form validation messages, you’ll need to add the novalidate
attribute to your <Form>
or <form>
element
import React, { useState } from 'react';
import { Button, Col, Form, InputGroup, Row } from 'react-bootstrap';
const CustomFormValidation = () => {
const [validated, setValidated] = useState(false);
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
setValidated(true);
};
return (
<Form noValidate validated={validated} onSubmit={handleSubmit}>
<Row className="mb-3">
<Form.Group as={Col} md="4" controlId="validationCustom01">
<Form.Label>First name</Form.Label>
<Form.Control
required
type="text"
placeholder="First name"
defaultValue="Mark"
/>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="4" controlId="validationCustom02">
<Form.Label>Last name</Form.Label>
<Form.Control
required
type="text"
placeholder="Last name"
defaultValue="Otto"
/>
<Form.Control.Feedback>Looks good!</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="4" controlId="validationCustomUsername">
<Form.Label>Username</Form.Label>
<InputGroup hasValidation>
<InputGroup.Text id="inputGroupPrepend">@</InputGroup.Text>
<Form.Control
type="text"
placeholder="Username"
aria-describedby="inputGroupPrepend"
required
/>
<Form.Control.Feedback type="invalid">
Please choose a username.
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
</Row>
<Row className="mb-3">
<Form.Group as={Col} md="6" controlId="validationCustom03">
<Form.Label>City</Form.Label>
<Form.Control type="text" placeholder="City" required />
<Form.Control.Feedback type="invalid">
Please provide a valid city.
</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="3" controlId="validationCustom04">
<Form.Label>State</Form.Label>
<Form.Control type="text" placeholder="State" required />
<Form.Control.Feedback type="invalid">
Please provide a valid state.
</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="3" controlId="validationCustom05">
<Form.Label>Zip</Form.Label>
<Form.Control type="text" placeholder="Zip" required />
<Form.Control.Feedback type="invalid">
Please provide a valid zip.
</Form.Control.Feedback>
</Form.Group>
</Row>
<Form.Group className="mb-3">
<Form.Check
required
label="Agree to terms and conditions"
feedback="You must agree before submitting."
feedbackType="invalid"
/>
</Form.Group>
<Button type="submit">Submit form</Button>
</Form>
);
}
export default CustomFormValidation;
Not interested in custom validation feedback messages or writing JavaScript to change form behaviors? All good, you can use the browser defaults. Try submitting the form below.
import React, { useState } from 'react';
import { Button, Col, Form, InputGroup, Row } from 'react-bootstrap';
const BrowserDefault = () => {
const handleSubmit = (e) => {
e.preventDefault();
};
};
return (
<Form onSubmit={handleSubmit} >
<Row className="mb-3">
<Form.Group as={Col} md="4" controlId="validationCustom01">
<Form.Label>First name</Form.Label>
<Form.Control
required
type="text"
placeholder="First name"
defaultValue="Mark"
/>
</Form.Group>
<Form.Group as={Col} md="4" controlId="validationCustom02">
<Form.Label>Last name</Form.Label>
<Form.Control
required
type="text"
placeholder="Last name"
defaultValue="Otto"
/>
</Form.Group>
<Form.Group as={Col} md="4" controlId="validationCustomUsername">
<Form.Label>Username</Form.Label>
<InputGroup hasValidation>
<InputGroup.Text id="inputGroupPrepend">@</InputGroup.Text>
<Form.Control
type="text"
placeholder="Username"
aria-describedby="inputGroupPrepend"
required
/>
</InputGroup>
</Form.Group>
</Row>
<Row className="mb-3">
<Form.Group as={Col} md="6" controlId="validationCustom03">
<Form.Label>City</Form.Label>
<Form.Control type="text" placeholder="City" required />
</Form.Group>
<Form.Group as={Col} md="3" controlId="validationCustom04">
<Form.Label>State</Form.Label>
<Form.Control type="text" placeholder="State" required />
</Form.Group>
<Form.Group as={Col} md="3" controlId="validationCustom05">
<Form.Label>Zip</Form.Label>
<Form.Control type="text" placeholder="Zip" required />
</Form.Group>
</Row>
<Form.Group className="mb-3">
<Form.Check
required
label="Agree to terms and conditions"
feedback="You must agree before submitting."
feedbackType="invalid"
/>
</Form.Group>
<Button type="submit">Submit form</Button>
</Form>
);
}
export default BrowserDefault;
It's often beneficial (especially in React) to handle form validation via a library like Formik. In those cases, isValid
and isInvalid
props can be added to form controls to manually apply validation styles. Below is a quick example integrating with Formik .
import React, { useState } from 'react';
import { Button, Col, Form, InputGroup, Row } from 'react-bootstrap';
// formik validations
const validate = values => {
const errors = {};
if (!values.firstName) {
errors.firstName = 'Required';
} else if (values.firstName.length > 15) {
errors.firstName = 'Must be 15 characters or less';
}
if (!values.lastName) {
errors.lastName = 'Required';
} else if (values.lastName.length > 20) {
errors.lastName = 'Must be 20 characters or less';
}
if (!values.userName) {
errors.userName = 'Please choose a unique and valid username.';
} else if (values.userName.length > 15) {
errors.userName = 'Must be 10 characters or less';
}
if (!values.city) {
errors.city = 'Please provide a valid city.';
}
if (!values.stateName) {
errors.stateName = 'Please select a valid state.'
}
if (!values.zipCode) {
errors.zipCode = 'Please provide a valid zip.'
}
else if (values.zipCode.length > 6 || values.zipCode.length < 6) {
errors.zipCode = 'Must be 6 digit or less';
}
if (values.terms === false) {
errors.terms = 'Terms must be accepted.'
}
if (!values.email) {
errors.email = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$/i.test(values.email)) {
errors.email = 'Invalid email address';
}
return errors;
};
const ServerRenderedStyles = () => {
// Pass the useFormik() hook initial form values, a validate function that will be called when
// form values change or fields are blurred, and a submit function that will
// be called when the form is submitted
const formik = useFormik({
initialValues: {
firstName: 'Mark',
lastName: 'Otto',
userName: '',
email: '',
city: '',
stateName: '',
zipCode: '',
terms: false,
},
validate,
onSubmit: values => {
alert(JSON.stringify(values, null, 2));
},
});
};
return (
<Form noValidate onSubmit={formik.handleSubmit} >
<Row className="mb-3">
<Form.Group
as={Col} md="4"
className="position-relative"
>
<Form.Label>First name</Form.Label>
<Form.Control
id='firstName'
name="firstName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.firstName}
isValid={formik.values.firstName && formik.values.firstName.length <= 15}
isInvalid={formik.errors.firstName}
/>
<Form.Control.Feedback type='valid' >Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type='invalid' >{formik.errors.firstName}</Form.Control.Feedback>
</Form.Group>
<Form.Group
as={Col}
md="4"
className="position-relative"
>
<Form.Label>Last name</Form.Label>
<Form.Control
id='lastName'
name="lastName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.lastName}
isValid={formik.values.lastName && formik.values.lastName.length <= 20}
isInvalid={formik.errors.lastName}
/>
<Form.Control.Feedback type='valid' >Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type='invalid' >{formik.errors.lastName}</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="4" >
<Form.Label>Username</Form.Label>
<InputGroup hasValidation>
<InputGroup.Text id="inputGroupPrepend">@</InputGroup.Text>
<Form.Control
id='userName'
name="userName"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.userName}
isValid={formik.values.userName && formik.values.userName.length <= 10}
isInvalid={formik.errors.userName}
/>
<Form.Control.Feedback type='valid' >Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type='invalid' >{formik.errors.userName}</Form.Control.Feedback>
</InputGroup>
</Form.Group>
</Row>
<Row className="mb-3">
<Form.Group
as={Col} md="6"
className="position-relative"
>
<Form.Label>City</Form.Label>
<Form.Control
id='city'
name="city"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.city}
isValid={formik.values.city}
isInvalid={formik.errors.city}
/>
<Form.Control.Feedback type='valid' >Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type='invalid' >{formik.errors.city}</Form.Control.Feedback>
</Form.Group>
<Form.Group
as={Col} md="3"
className="position-relative"
>
<Form.Label>State</Form.Label>
<Form.Select
id='stateName'
name="stateName"
type='select'
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.stateName}
isValid={formik.values.stateName}
isInvalid={formik.errors.stateName}
>
<option value=''>select</option>
<option value="state1">State-1</option>
<option value="state2">State-2</option>
<option value="state3">State-3</option>
<option value="more">...</option>
</Form.Select>
<Form.Control.Feedback type='valid' >Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type='invalid' >{formik.errors.stateName}</Form.Control.Feedback>
</Form.Group>
<Form.Group
as={Col} md="3"
className="position-relative"
>
<Form.Label>Zip</Form.Label>
<Form.Control
id='zipCode'
name="zipCode"
type="text"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.zipCode}
isValid={formik.values.zipCode && formik.values.zipCode.length === 6}
isInvalid={formik.errors.zipCode}
/>
<Form.Control.Feedback type='valid' >Looks good!</Form.Control.Feedback>
<Form.Control.Feedback type='invalid' >{formik.errors.zipCode}</Form.Control.Feedback>
</Form.Group>
</Row>
<Row>
<Form.Group as={Col} md="4" >
<Form.Label>Email</Form.Label>
<InputGroup hasValidation>
<Form.Control
id='email'
name="email"
type="email"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.email}
isValid={formik.values.email || formik.values.email === !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,4}$/i}
isInvalid={formik.errors.email}
/>
<Form.Control.Feedback type='invalid' >{formik.errors.email}</Form.Control.Feedback>
</InputGroup>
</Form.Group>
</Row>
<Form.Group className="my-3" >
<Form.Check
required
name="terms"
label="Agree to terms and conditions"
onChange={formik.handleChange}
onBlur={formik.handleBlur}
value={formik.values.terms}
isValid={formik.values.terms}
isInvalid={formik.errors.terms}
feedback={formik.errors.terms}
feedbackType="invalid"
/>
</Form.Group>
<Button type="submit">Submit form</Button>
</Form>
);
}
export default ServerRenderedStyles;
Form validation styles are also available for bootstrap custom form controls.
import React, { useState } from 'react';
import { Button, Form, InputGroup } from 'react-bootstrap';
const SupportedElements = () => {
return (
<Form className="was-validated" >
<Form.Group className="mb-3" >
<Form.Label>Textarea</Form.Label>
<InputGroup>
<Form.Control as="textarea" aria-label="With textarea" placeholder='Required example textarea' defaultValue="" required />
<Form.Control.Feedback type="invalid">
Please enter a message in the textarea.
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
<Form.Group className="mb-3">
<Form.Check
required
label="Check this checkbox"
feedback="You must check this before submitting."
feedbackType="invalid"
/>
</Form.Group>
<Form.Group className="mb-3">
<Form.Check
required
type="radio"
label="Toggle this radio"
name="formHorizontalRadios"
id="formHorizontalRadios1"
/>
<Form.Check
required
type="radio"
label="Or toggle this other radio"
name="formHorizontalRadios"
id="formHorizontalRadios2"
feedback="More example invalid feedback text"
feedbackType='invalid'
/>
</Form.Group>
<Form.Group className='mb-3'>
<Form.Select aria-label="Default select example" required>
<option >Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</Form.Select>
<Form.Control.Feedback type='invalid'>Example invalid select feedback</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="formFile" className="mb-3">
<Form.Control type="file" required />
<Form.Control.Feedback type="invalid">Example invalid form file feedback</Form.Control.Feedback>
</Form.Group>
<Button type='submit' variant='primary' disabled >Submit Form</Button>
</Form>
);
}
export default SupportedElements;
If your form layout allows it, you can use the tooltip
prop to display validation feedback in a styled tooltip.
import React, { useState } from 'react';
import { Button, Col, Form, InputGroup, Row } from 'react-bootstrap';
const TooltipFeedbacks = () => {
const [validated, setValidated] = useState(false);
const handleSubmit = (event) => {
const form = event.currentTarget;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
setValidated(true);
event.preventDefault();
};
};
return (
<Form noValidate validated={validated} onSubmit={handleSubmit}>
<Row className="mb-3">
<Form.Group as={Col} md="4" controlId="validationCustom01" className="position-relative">
<Form.Label>First name</Form.Label>
<Form.Control
required
type="text"
placeholder="First name"
defaultValue="Mark"
/>
<Form.Control.Feedback tooltip >Looks good!</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="4" controlId="validationCustom02" className="position-relative">
<Form.Label>Last name</Form.Label>
<Form.Control
required
type="text"
placeholder="Last name"
defaultValue="Otto"
/>
<Form.Control.Feedback tooltip >Looks good!</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="4" controlId="validationCustomUsername" className="position-relative">
<Form.Label>Username</Form.Label>
<InputGroup hasValidation>
<InputGroup.Text id="inputGroupPrepend">@</InputGroup.Text>
<Form.Control
type="text"
placeholder="Username"
aria-describedby="inputGroupPrepend"
required
/>
<Form.Control.Feedback tooltip type="invalid">
Please choose a username.
</Form.Control.Feedback>
</InputGroup>
</Form.Group>
</Row>
<Row className="mb-3">
<Form.Group as={Col} md="6" controlId="validationCustom03" className="position-relative">
<Form.Label>City</Form.Label>
<Form.Control type="text" placeholder="City" required />
<Form.Control.Feedback tooltip type="invalid">
Please provide a valid city.
</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="3" controlId="validationCustom04" className="position-relative">
<Form.Label>State</Form.Label>
<Form.Control type="text" placeholder="State" required />
<Form.Control.Feedback tooltip type="invalid">
Please provide a valid state.
</Form.Control.Feedback>
</Form.Group>
<Form.Group as={Col} md="3" controlId="validationCustom05" className="position-relative">
<Form.Label>Zip</Form.Label>
<Form.Control type="text" placeholder="Zip" required />
<Form.Control.Feedback tooltip type="invalid">
Please provide a valid zip.
</Form.Control.Feedback>
</Form.Group>
</Row>
<Form.Group className="mb-3">
<Form.Check
required
label="Agree to terms and conditions"
feedback="You must agree before submitting."
feedbackType="invalid"
/>
</Form.Group>
<Button type="submit">Submit form</Button>
</Form>
);
}
export default TooltipFeedbacks;