curriculum/challenges/english/blocks/lecture-understanding-form-validation/6733aae9d25004f60d1e86f2.md
In a previous lesson, you've learned how to use HTML to restrict the values your users can submit in your form. But sometimes that's not enough. If you want to get more complex, such as displaying your own error messages to the user, you will need to use JavaScript.
Certain HTML elements, such as the textarea and input elements, expose a Constraint Validation API. This API allows you to assert that the user's provided value for that element passes any HTML-level validation you have written, such as minimum length or pattern matching.
But how can you actually use it? Let's say you wanted employees at a company to send feedback messages through a form like this:
:::interactive_editor
<link rel="stylesheet" href="styles.css" />
<form>
<label>Enter your email: </label>
<input required type="email" />
<label>Enter your feedback: </label>
<textarea required placeholder="Your feedback here..."></textarea>
<button type="submit">Submit Feedback</button>
</form>
form {
max-width: 400px;
margin: 20px auto;
display: flex;
flex-direction: column;
gap: 12px;
font-family: Arial, sans-serif;
}
label {
font-weight: 600;
margin-bottom: 4px;
color: #333;
}
input,
textarea {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s, box-shadow 0.2s;
}
input:focus,
textarea:focus {
border-color: #0078d4;
box-shadow: 0 0 3px rgba(0, 120, 212, 0.5);
outline: none;
}
textarea {
resize: vertical;
min-height: 100px;
}
button[type="submit"] {
background-color: #0078d4;
color: #fff;
border: none;
padding: 10px 16px;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
button[type="submit"]:hover {
background-color: #005ea2;
}
:::
We are using the email input which comes with built in validation to check for basic validation like if the input includes the at (@) sign.
But what if the user provides an email address like [email protected]? This would pass the basic validation, but we want to be more specific about accepting emails from those with a company email address.
This is where we can use the pattern attribute to specify that the email address must end in a company email address. Here is what the updated example will look like:
:::interactive_editor
<link rel="stylesheet" href="styles.css" />
<form>
<label>Enter your email: </label>
<input required placeholder="[email protected]" type="email" pattern=".+@sampleCompany\.com" />
<label>Enter your feedback: </label>
<textarea required placeholder="Your feedback here..."></textarea>
<button type="submit">Submit Feedback</button>
</form>
form {
max-width: 400px;
margin: 20px auto;
display: flex;
flex-direction: column;
gap: 12px;
font-family: Arial, sans-serif;
}
label {
font-weight: 600;
margin-bottom: 4px;
color: #333;
}
input,
textarea {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s, box-shadow 0.2s;
}
input:focus,
textarea:focus {
border-color: #0078d4;
box-shadow: 0 0 3px rgba(0, 120, 212, 0.5);
outline: none;
}
textarea {
resize: vertical;
min-height: 100px;
}
button[type="submit"] {
background-color: #0078d4;
color: #fff;
border: none;
padding: 10px 16px;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
button[type="submit"]:hover {
background-color: #005ea2;
}
:::
Now, if you try to submit the feedback, you will see a message saying "Please match the requested format."
Even though the input does have placeholder text showing them the desired format, it would be better to also include a customized error message using JavaScript.
Let's first take a look at the checkValidity() method:
:::interactive_editor
<link rel="stylesheet" href="styles.css" />
<form>
<label>Enter your email: </label>
<input required placeholder="[email protected]" type="email" pattern=".+@sampleCompany\.com" />
<label>Enter your feedback: </label>
<textarea required placeholder="Your feedback here..."></textarea>
<button type="submit">Submit Feedback</button>
</form>
<script src="index.js"></script>
form {
max-width: 400px;
margin: 20px auto;
display: flex;
flex-direction: column;
gap: 12px;
font-family: Arial, sans-serif;
}
label {
font-weight: 600;
margin-bottom: 4px;
color: #333;
}
input,
textarea {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s, box-shadow 0.2s;
}
input:focus,
textarea:focus {
border-color: #0078d4;
box-shadow: 0 0 3px rgba(0, 120, 212, 0.5);
outline: none;
}
textarea {
resize: vertical;
min-height: 100px;
}
button[type="submit"] {
background-color: #0078d4;
color: #fff;
border: none;
padding: 10px 16px;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
button[type="submit"]:hover {
background-color: #005ea2;
}
const input = document.querySelector("input");
input.addEventListener("input", (e) => {
console.log(e.target.checkValidity())
})
:::
In the above example, we've queried our input from the DOM, and added an input event listener.
We know that e.target refers to the element that triggered the event. In this case, our input. But what is the checkValidity() method?
This is part of the Constraint Validation API. The checkValidity() method returns true if the element matches all HTML validation (based on its attributes), and false if it fails.
When we try with an invalid input, we see false gets logged in the console. Now that we know the input is invalid, let's report the invalidity:
:::interactive_editor
<link rel="stylesheet" href="styles.css" />
<form>
<label>Enter your email: </label>
<input required placeholder="[email protected]" type="email" pattern=".+@sampleCompany\.com" />
<label>Enter your feedback: </label>
<textarea required placeholder="Your feedback here..."></textarea>
<button type="submit">Submit Feedback</button>
</form>
<script src="index.js"></script>
form {
max-width: 400px;
margin: 20px auto;
display: flex;
flex-direction: column;
gap: 12px;
font-family: Arial, sans-serif;
}
label {
font-weight: 600;
margin-bottom: 4px;
color: #333;
}
input,
textarea {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s, box-shadow 0.2s;
}
input:focus,
textarea:focus {
border-color: #0078d4;
box-shadow: 0 0 3px rgba(0, 120, 212, 0.5);
outline: none;
}
textarea {
resize: vertical;
min-height: 100px;
}
button[type="submit"] {
background-color: #0078d4;
color: #fff;
border: none;
padding: 10px 16px;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
button[type="submit"]:hover {
background-color: #005ea2;
}
const input = document.querySelector("input");
input.addEventListener("input", (e) => {
if (!e.target.checkValidity()) {
e.target.reportValidity();
}
})
:::
And as a result, you will see the browser's error message "Please match the requested format."
It reports the invalid state immediately, instead of waiting for us to submit the form. But it's still using the default message. This is because the reportValidity method only tells the browser that the input is invalid. The browser still chooses how to display why it's invalid. That's where the setCustomValidity method comes in.
:::interactive_editor
<link rel="stylesheet" href="styles.css" />
<form>
<label>Enter your email: </label>
<input required placeholder="[email protected]" type="email" pattern=".+@sampleCompany\.com" />
<label>Enter your feedback: </label>
<textarea required placeholder="Your feedback here..."></textarea>
<button type="submit">Submit Feedback</button>
</form>
<script src="index.js"></script>
form {
max-width: 400px;
margin: 20px auto;
display: flex;
flex-direction: column;
gap: 12px;
font-family: Arial, sans-serif;
}
label {
font-weight: 600;
margin-bottom: 4px;
color: #333;
}
input,
textarea {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s, box-shadow 0.2s;
}
input:focus,
textarea:focus {
border-color: #0078d4;
box-shadow: 0 0 3px rgba(0, 120, 212, 0.5);
outline: none;
}
textarea {
resize: vertical;
min-height: 100px;
}
button[type="submit"] {
background-color: #0078d4;
color: #fff;
border: none;
padding: 10px 16px;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
button[type="submit"]:hover {
background-color: #005ea2;
}
const input = document.querySelector("input");
input.addEventListener("input", (e) => {
if (!e.target.checkValidity()) {
e.target.setCustomValidity(
"You must use a company email address that ends in @sampleCompany.com"
);
}
});
:::
This method accepts a custom error message, which is displayed to the user. As a result, you will see the custom error message You must use a company email address that ends in @sampleCompany.com.
If you are interested in exploring more about the different types of validity states and why a particular validation has failed, you can log out the validity property like this:
:::interactive_editor
<link rel="stylesheet" href="styles.css" />
<form>
<label>Enter your email: </label>
<input required placeholder="[email protected]" type="email" pattern=".+@sampleCompany\.com" />
<label>Enter your feedback: </label>
<textarea required placeholder="Your feedback here..."></textarea>
<button type="submit">Submit Feedback</button>
</form>
<script src="index.js"></script>
form {
max-width: 400px;
margin: 20px auto;
display: flex;
flex-direction: column;
gap: 12px;
font-family: Arial, sans-serif;
}
label {
font-weight: 600;
margin-bottom: 4px;
color: #333;
}
input,
textarea {
padding: 8px 12px;
border: 1px solid #ccc;
border-radius: 4px;
font-size: 14px;
width: 100%;
box-sizing: border-box;
transition: border-color 0.2s, box-shadow 0.2s;
}
input:focus,
textarea:focus {
border-color: #0078d4;
box-shadow: 0 0 3px rgba(0, 120, 212, 0.5);
outline: none;
}
textarea {
resize: vertical;
min-height: 100px;
}
button[type="submit"] {
background-color: #0078d4;
color: #fff;
border: none;
padding: 10px 16px;
font-size: 14px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s;
}
button[type="submit"]:hover {
background-color: #005ea2;
}
const input = document.querySelector("input");
input.addEventListener("input", (e) => {
console.log(e.target.validity);
})
:::
The validity property is an instance of the ValidityState object. Here is an example of what the object might look like in the browser:
ValidityState {
badInput: false,
customError: false,
patternMismatch: true,
rangeOverflow: false,
rangeUnderflow: false,
stepMismatch: false,
tooLong: false,
tooShort: false,
typeMismatch: true,
valueMissing: false,
valid: true
}
There are several helpful properties which all hold the value of a boolean of true or false.
Some of these helpful properties that you can explore more on your own would be the valueMissing property which is true when a required input field is left empty. Or the patternMismatch which is true if the value doesn't match the specified regular expression pattern.
After this lesson, I encourage you to play around with the examples given in this lesson and explore more about the different validity properties.
Which method of the Constraint Validation API is used to check if an input element meets all its validation constraints?
validateInput()
The lesson demonstrates this method when adding an event listener to the input element.
checkValidity()
isValid()
The lesson demonstrates this method when adding an event listener to the input element.
testConstraints()
The lesson demonstrates this method when adding an event listener to the input element.
2
What is the purpose of the setCustomValidity() method in form validation?
To set custom CSS styles for invalid inputs.
The lesson explains how this method is used to provide more informative feedback to users.
To create custom validation rules.
The lesson explains how this method is used to provide more informative feedback to users.
To display a custom error message for invalid inputs.
To override the default HTML validation.
The lesson explains how this method is used to provide more informative feedback to users.
3
Which property of the validity object becomes true when a required input field is left empty?
isEmpty
The lesson shows this property when logging the validity object for an empty required field.
required
The lesson shows this property when logging the validity object for an empty required field.
valueMissing
invalidValue
The lesson shows this property when logging the validity object for an empty required field.
3