Recommended resources
The freely available resources this lesson will direct you to.
Hello! Welcome back to your front-end development course.
In our last lesson, we learned how to capture user data from forms using the submit and input events. Now that we can read the data, the next critical step is to ensure it's correct.
Today, we'll focus on the learning outcome: Perform basic validation on form inputs using conditional logic to check for empty fields or correct formats.
From your perspective as a product designer, you know that form validation is a cornerstone of a good user experience. It prevents user frustration, guides them to provide correct information, and ensures the integrity of the data being collected. We'll move beyond just capturing data and start building the logic that makes a form feel intelligent and helpful.
We will cover:
- The basic approach to validation using
if-elsestatements. - A more robust, scalable, and data-driven pattern for handling multiple validation rules.
- How to check for common requirements: empty fields, minimum length, and specific formats like email.
1. The Core Idea: Validation with Conditional Logic
At its heart, form validation is a series of checks. "Is this field empty? Does this email look valid? Is this password long enough?" In programming, these questions are answered with conditional logic, most commonly if-else statements.
Let's look at a very direct way to implement this.
This article from GeeksforGeeks demonstrates a straightforward approach to form validation. We'll look at their first example to understand the basic concept.
Please read the section 'Approach 1: Using Conditional Logic'. Focus on the validateForm() function in the JavaScript block. Notice how it uses a series of if statements to check each input one by one and sets a flag isValid to false if a check fails.
This if-else chain works, but you can probably see the drawbacks. As your forms get more complex, this function would become very long and repetitive. If you wanted to use the same validation logic on another form, you'd have to copy and paste a lot of code.
We can do better by creating a more systematic and reusable solution.
2. A Better Way: Data-Driven Validation
Instead of a long series of hard-coded if statements, let's think about this more like a system. We can define our validation rules as a set of data (an array of objects) and then write a single, smart function that applies these rules to any input.
This approach has two key parts:
- Using HTML attributes to define validation requirements directly on the inputs.
- Writing JavaScript that reads these attributes and applies the corresponding logic.
Step 1: The HTML Foundation
HTML5 provides built-in attributes for form validation. These are great for semantics and provide a fallback if JavaScript fails.
Using HTML form validation and the Constraint Validation API
The MDN Web Docs are the definitive guide for web standards. Let's read their introduction to HTML's validation-related attributes, which will be the foundation for our JavaScript logic.
Please read the section 'Intrinsic and basic constraints', focusing on the table under 'Validation-related attributes'. Pay attention to attributes like required, minlength, maxlength, and pattern. We will be building a JavaScript system that leverages these exact attributes.
Step 2: A Reusable JavaScript Validator
Now, let's see how to build a JavaScript system that reads those HTML attributes and validates the form. The following video introduces a powerful pattern where validation rules are defined in an array. This makes the code incredibly organized and easy to extend.
We'll watch it in segments to break down the key ideas.
First, let's see how to structure our validation rules as an array of objects. Each object will define the attribute to look for (e.g., required), a function to check if the input is valid, and a function to generate an error message.
The BEST way to do form validation in JavaScript
This video from the 'Code With Bubb' channel demonstrates an excellent, reusable approach to form validation. We'll start with the core concept: defining validation rules in a data structure.
Watch from 00:32:10 to 00:35:02. The key takeaway is the structure of the validationOptions array. Notice how each rule is an object with three properties: attribute, isValid, and errorMessage. This is the heart of our new validation system.
Now that we have a structure for our rules, how do we apply them? The next segment shows how to loop through our validationOptions array and check an input against each rule.
The BEST way to do form validation in JavaScript
Let's continue with the same video to see how these rules are put into action.
Watch from 00:35:02 to 00:37:30. Focus on how the code loops through validationOptions and for each input, checks if it has the attribute (e.g., required) and then runs the corresponding is_valid function.
3. Expanding the Validator with More Rules
The beauty of this data-driven pattern is how easy it is to add new validation rules without changing the core validation logic. You just add a new object to the validationOptions array.
Let's see how to add rules for more complex scenarios.
Checking for Minimum Length (minlength)
This is a common requirement for usernames or passwords.
The BEST way to do form validation in JavaScript
Let's add a 'minlength' check to our system. Notice how a new object is simply added to the array.
Watch from 00:41:18 to 00:44:24. The key part is the new object added for the minlength attribute. See how the isValid function now compares input.value.length to the value of the minlength attribute on the element.
Checking for a Specific Format (pattern)
The pattern attribute uses a regular expression (regex) to check for complex formats, like an email address. You don't need to be a regex expert, but it's good to know how to use one for validation.
The BEST way to do form validation in JavaScript
Now for email validation. This segment shows how to integrate the pattern attribute.
Watch from 00:46:32 to 00:49:56. Observe how the pattern rule is added. The isValid function creates a new RegExp() from the input's pattern attribute and uses the .test() method to check the input's value against it.
Checking for Matching Fields (Confirm Password)
Sometimes, validation depends on another field, like ensuring a "confirm password" field matches the original password. This requires custom logic.
The BEST way to do form validation in JavaScript
Finally, let's look at a more advanced custom rule for matching two fields.
Watch from 00:49:56 to 00:54:00. Here, a custom attribute match is created. The isValid function for this rule is more complex: it has to find the other input element and compare their values. This demonstrates the flexibility of the system.
4. Your Turn: Build a Validator
Now it's time to apply these concepts. Below is a sign-up form. Your task is to write the JavaScript validation logic using the data-driven pattern we've just learned.
Your Goal:
Create a validationOptions array and a function that checks the form inputs against these rules when the form is submitted. For now, just log the errors to the console.
The Rules to Implement:
- Username: Is required and must be at least 3 characters.
- Email: Is required and must be a valid email format.
- Password: Is required and must be at least 8 characters.
- Confirm Password: Is required and must match the password field.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Validation Practice</title>
<style>
body { font-family: sans-serif; display: flex; justify-content: center; padding-top: 40px; background-color: #f4f4f9; }
.form-container { background: #fff; padding: 2rem; border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); width: 400px; }
h2 { margin-top: 0; text-align: center; }
.form-group { margin-bottom: 1.5rem; }
label { display: block; margin-bottom: 0.5rem; font-weight: bold; }
input { width: 100%; padding: 0.75rem; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; }
button { width: 100%; padding: 0.75rem; border: none; border-radius: 4px; background-color: #007bff; color: white; font-size: 1rem; cursor: pointer; }
/* We will use these error styles in the next lesson! */
.error-message { color: #e74c3c; font-size: 0.875rem; margin-top: 0.25rem; display: none; }
input.invalid { border-color: #e74c3c; }
</style>
</head>
<body>
<div class="form-container">
<h2>Create Account</h2>
<form id="signup-form" novalidate>
<div class="form-group">
<label for="username">Username</label>
<!-- Validation: required, minlength 3 -->
<input type="text" id="username" name="username" required minlength="3">
<div class="error-message"></div>
</div>
<div class="form-group">
<label for="email">Email</label>
<!-- Validation: required, email format -->
<input type="email" id="email" name="email" required>
<div class="error-message"></div>
</div>
<div class="form-group">
<label for="password">Password</label>
<!-- Validation: required, minlength 8 -->
<input type="password" id="password" name="password" required minlength="8">
<div class="error-message"></div>
</div>
<div class="form-group">
<label for="password-confirm">Confirm Password</label>
<!-- Validation: required, must match password -->
<input type="password" id="password-confirm" name="password-confirm" required data-match="password">
<div class="error-message"></div>
</div>
<button type="submit">Sign Up</button>
</form>
</div>
<script>
// Note: The 'novalidate' attribute on the form prevents default browser validation popups.
const form = document.querySelector('#signup-form');
// --- YOUR TASK ---
// 1. Define the `validationOptions` array. It should contain objects for:
// - 'required'
// - 'minlength'
// - 'email' (Note: the input type="email" handles the pattern, so we check for validity.typeMismatch)
// - 'data-match' (our custom attribute for password confirmation)
// 2. Create a function `validateInput(inputElement)` that:
// - Loops through `validationOptions`.
// - For each option, checks if the input has the attribute.
// - If it does, run the `isValid` function for that option.
// - If `isValid` returns false, log the error message from `errorMessage` and stop.
// - If the loop completes with no errors, the input is valid!
// 3. Add a 'submit' event listener to the form.
// - Inside, call `event.preventDefault()`.
// - Get all the inputs from the form.
// - Loop through each input and call your `validateInput` function on it.
// YOUR CODE HERE
</script>
</body>
</html>
Click here for a complete solution to guide you
const form = document.querySelector('#signup-form');
// Helper function to get the input's label text for error messages
const getLabelText = (input) => {
// Find the label associated with the input
return input.previousElementSibling.textContent;
}
// 1. Define the validationOptions array
const validationOptions = [
{
attribute: 'required',
isValid: input => input.value.trim() !== '',
errorMessage: (input, label) => `${getLabelText(input)} is required.`,
},
{
attribute: 'minlength',
isValid: input => input.value.length >= parseInt(input.minLength, 10),
errorMessage: (input, label) => `${getLabelText(input)} must be at least ${input.minLength} characters.`,
},
{
attribute: 'type',
// For type="email", the browser sets a `typeMismatch` flag if the format is wrong.
isValid: input => input.type !== 'email' || !input.validity.typeMismatch,
errorMessage: (input, label) => `Please enter a valid ${getLabelText(input).toLowerCase()}.`,
},
{
attribute: 'data-match',
isValid: input => {
const matchInputId = input.dataset.match;
const matchInput = document.querySelector(`#${matchInputId}`);
return input.value === matchInput.value;
},
errorMessage: (input, label) => `${getLabelText(input)} must match the password.`,
}
];
// 2. Create a function to validate a single input
const validateSingleInput = (input) => {
let isValid = true;
for (const option of validationOptions) {
// Check if the input has the attribute OR if it's the email type check
if (input.hasAttribute(option.attribute) || (option.attribute === 'type' && input.type === 'email')) {
if (!option.isValid(input)) {
// For now, we just log the error. In the next lesson, we'll display it.
console.error(option.errorMessage(input));
isValid = false;
break; // Stop at the first error
}
}
}
return isValid;
};
// 3. Add the submit event listener
form.addEventListener('submit', (event) => {
event.preventDefault();
console.log('--- Running Validation ---');
const inputs = form.querySelectorAll('input');
let isFormValid = true;
for (const input of inputs) {
const isInputValid = validateSingleInput(input);
if (!isInputValid) {
isFormValid = false;
}
}
if (isFormValid) {
console.log('Form is valid! Submitting...');
// In a real app, you would now send the data to a server.
} else {
console.log('Form has errors.');
}
});
Conclusion
Excellent work! You've tackled one of the most important aspects of front-end development. Building robust, user-friendly forms is a skill that directly bridges design and engineering.
Key Takeaways:
- Form validation is essential for good UX and data integrity.
- Simple validation can be done with
if-elsechains, but this approach doesn't scale well. - A data-driven approach, where validation rules are defined in an array or object, creates a system that is clean, reusable, and easy to maintain.
- We can leverage standard HTML5 attributes like
requiredandminlengthas the foundation for our JavaScript validation logic. - Custom logic, like matching password fields, can be easily integrated into this system.
In this lesson, we focused on the logic of validation and logged errors to the console. In our next lesson, we'll complete the user experience loop by learning how to provide visual feedback for form validation by dynamically adding and removing CSS classes to display error messages or input styles.