Skip to Content
Lesson 5

Form Validation and User Input

Workplace Context

In a typical software engineering role, especially in web development, ensuring data integrity and a smooth user experience is paramount.

Imagine you’re tasked with developing the checkout process for a new e-commerce platform. This involves multiple input fields: shipping address, billing information, payment details (credit card numbers, expiry dates, CVV), and contact information. Each piece of data must be accurate not only for successful order processing and shipping but also to prevent fraud and build user trust.

Implementing robust form validation — checking for required fields, correct formats (like email or credit card numbers), valid dates, and logical consistency — becomes a critical responsibility. Effective client-side validation provides immediate feedback, guiding users to correct errors quickly, reducing frustration, and minimizing unnecessary requests to the server, ultimately leading to higher conversion rates and a more professional application.


Learning Objectives

By the end of this lesson, you will be able to:

  • Understand the importance of form validation.
  • Implement client-side validation using built-in HTML5 attributes.
  • Use CSS to provide visual feedback for form validation states.
  • Enhance form validation with JavaScript and the Constraint Validation API.
  • Customize validation messages and logic.
  • Handle form submissions and prevent default browser actions.
  • Create a sign-up form with real-time validation.
  • Build a custom validation function for a contact form.

This lesson focuses on client-side validation techniques.


Introduction to Form Validation

Form validation is the process of ensuring that user input submitted through web forms is accurate, complete, and in the correct format. It’s a critical aspect of web development for several reasons:

  • Data Integrity: Ensures that the data collected is reliable and useful for your application.
  • User Experience (UX): Provides immediate feedback to users, helping them correct errors easily and reducing frustration.
  • Security: Acts as a first line of defense against common web vulnerabilities, although it should always be complemented by server-side validation.

There are two main types of validation:

  1. Client-Side Validation: Performed in the user’s browser before data is sent to the server. It’s fast and provides instant feedback.
  2. Server-Side Validation: Performed on the server after data has been submitted. It’s essential for security as client-side validation can be bypassed.

This lesson focuses on client-side validation techniques.


Built-in HTML5 Form Validation

HTML5 introduced several attributes that allow you to perform basic form validation without writing any JavaScript. These attributes are simple to use and provide a good baseline for validating user input.

Key HTML5 Validation Attributes:

  • required: Specifies that an input field must be filled out before submitting the form.
    <label for="username">Username:</label> <input type="text" id="username" name="username" required>
  • type: Defines the expected data type. Browsers can validate some types automatically.
    • email: Checks for a valid email format.
      <label for="email">Email:</label> <input type="email" id="email" name="email" required>
    • number: Expects a numerical value. Can be used with min, max, and step.
      <label for="quantity">Quantity (1-10):</label> <input type="number" id="quantity" name="quantity" min="1" max="10" step="1" required>
    • url: Checks for a valid URL format.
      <label for="website">Website:</label> <input type="url" id="website" name="website">
  • minlength and maxlength: Specify the minimum and maximum number of characters allowed for text-based inputs (text, password, textarea, etc.).
    <label for="password">Password (min 8 characters):</label> <input type="password" id="password" name="password" minlength="8" required>
  • min and max: Define the minimum and maximum acceptable values for numerical input types (number, range, date, etc.).
    <label for="age">Age (must be 18 or older):</label> <input type="number" id="age" name="age" min="18" required>
  • pattern: Allows you to specify a regular expression that the input value must match. This is powerful for custom validation rules.
    <label for="zipcode">Zip Code (5 digits):</label> <input type="text" id="zipcode" name="zipcode" pattern="\\d{5}" title="Please enter a 5-digit zip code" required>

Styling with CSS Pseudo-classes

CSS provides pseudo-classes to style form elements based on their validation state, enhancing user feedback.

  • :valid: Styles an input element when its value is valid according to its constraints.
  • :invalid: Styles an input element when its value is invalid.
  • :required: Styles an input element that has the required attribute.
  • :optional: Styles an input element that does not have the required attribute.
  • :user-invalid (and :user-valid): Similar to :invalid and :valid but only apply after the user has interacted with the field. This can prevent showing errors before the user has had a chance to input data.
input:required { border-left: 5px solid orange; } input:invalid { border-left: 5px solid red; background-color: #ffe0e0; } input:valid { border-left: 5px solid green; } input:focus:invalid { outline: none; /* Avoid double indication of error */ } /* Styling error messages (often shown via JavaScript) */ .error-message { color: red; font-size: 0.9em; margin-top: 5px; }

JavaScript Form Validation

While HTML5 validation is convenient, JavaScript offers more control and flexibility for complex validation scenarios and custom user feedback.

The Constraint Validation API

The Constraint Validation API is a set of JavaScript properties and methods available on form elements that allow you to check and report validation status.

Key Properties (on an input element, e.g., inputElement.validity):

  • inputElement.validity: Returns a ValidityState object with boolean properties indicating the validation status:
    • valueMissing: true if a required field is empty.
    • typeMismatch: true if the value doesn’t match the type (e.g., invalid email).
    • patternMismatch: true if the value doesn’t match the pattern attribute.
    • tooLong: true if the value exceeds maxlength.
    • tooShort: true if the value is less than minlength.
    • rangeUnderflow: true if the value is less than min.
    • rangeOverflow: true if the value is greater than max.
    • stepMismatch: true if the value doesn’t fit the step attribute.
    • badInput: true if the user entered input that the browser cannot convert (e.g., text in a number field).
    • customError: true if a custom validation message has been set via setCustomValidity().
    • valid: true if all constraints are met.
  • inputElement.validationMessage: Returns a localized browser-generated message describing why the input is invalid.
  • inputElement.willValidate: true if the element is a candidate for constraint validation.

Key Methods:

  • inputElement.checkValidity(): Returns true if the element’s value is valid, false otherwise. If invalid, it also fires an invalid event on the element.
  • inputElement.reportValidity(): Checks validity and, if invalid, reports the error to the user (typically by displaying the browser’s default error message bubble). Returns true if valid, false otherwise.
  • inputElement.setCustomValidity(message): Allows you to set a custom error message.
    • If message is a non-empty string, the element is considered invalid, and this message will be displayed.
    • If message is an empty string (""), any custom error is cleared, and the element’s validity is re-evaluated based on its built-in constraints.

Implementing Custom Error Messages

You can override the browser’s default error messages to provide more specific or user-friendly feedback.

<form id="customValidationForm"> <label for="customEmail">Email:</label> <input type="email" id="customEmail" name="customEmail" required> <span class="error-message" id="customEmailError"></span> <button type="submit">Submit</button> </form> <script> const customEmailInput = document.getElementById('customEmail'); const customEmailError = document.getElementById('customEmailError'); const customForm = document.getElementById('customValidationForm'); customEmailInput.addEventListener('input', function(event) { if (customEmailInput.validity.typeMismatch) { customEmailInput.setCustomValidity('Please enter a valid email address, for example, name@example.com.'); } else if (customEmailInput.validity.valueMissing) { customEmailInput.setCustomValidity('We need your email address to contact you!'); } else { customEmailInput.setCustomValidity(''); // Clear custom error if valid } // Display the custom message or clear it customEmailError.textContent = customEmailInput.validationMessage; }); // Optional: Prevent form submission if you want to handle it entirely with JS // customForm.addEventListener('submit', function(event) { // if (!customForm.checkValidity()) { // event.preventDefault(); // // You might want to focus on the first invalid field or show a summary // } // }); </script>

Real-time Validation

Providing feedback as the user types (or when they move away from a field) can significantly improve the user experience. This is typically done by listening to input or blur events.

// (Continuing from the previous example) customEmailInput.addEventListener('blur', function(event) { // Validate on blur // The 'input' event listener already handles setting custom validity // So here we just ensure the message is displayed if not already if (!customEmailInput.validity.valid) { customEmailError.textContent = customEmailInput.validationMessage; } else { customEmailError.textContent = ''; } });

Handling Form Submission

By default, when a form is submitted, the browser attempts to send its data to the URL specified in the action attribute (or the current page if action is omitted) using the method specified in the method attribute (defaulting to GET).

Preventing Default Submission

Often, you’ll want to handle form submission with JavaScript, especially in Single Page Applications (SPAs) or when you need to perform actions like sending data via AJAX. You can prevent the default submission behavior using event.preventDefault().

<form id="myForm"> <label for="name">Name:</label> <input type="text" id="name" name="name" required> <button type="submit">Submit</button> </form> <script> const myForm = document.getElementById('myForm'); const nameInput = document.getElementById('name'); myForm.addEventListener('submit', function(event) { event.preventDefault(); // Stop the default form submission if (!nameInput.validity.valid) { alert('Please enter your name.'); nameInput.focus(); return; // Stop further processing if invalid } // If valid, process the form data const formData = new FormData(myForm); const nameValue = formData.get('name'); alert('Form submitted! Name: ' + nameValue); // Here you would typically send data to a server using fetch() or XMLHttpRequest // e.g., fetch('/submit-form', { method: 'POST', body: formData }); myForm.reset(); // Optionally reset the form }); </script>

Activity 1: Creating a Signup Form with Real-Time Validation

We will now build portions of a simple signup form with fields for username, email, and password, implementing real-time validation, which looks like this:

In the Example:

  1. The HTML sets up a basic form with novalidate to disable default browser error bubbles, allowing us to use custom messages in <span> elements.
  2. Inputs have required and other HTML5 validation attributes (minlength, pattern, type="email").
  3. The validateField JavaScript function is a generic helper. It:
    • Clears previous errors and styling.
    • Sets custom validity messages (if a field is empty and required, or if a custom validation function is provided).
    • Calls checkValidity() to trigger built-in HTML5 checks and the Constraint API.
    • Updates the error message <span> and applies .valid or .invalid classes.
  4. Specific validation functions (validateUsername, validateEmail, etc.) use setCustomValidity based on the input’s validity state or custom logic (like checking if passwords match).
  5. Event listeners on input for each field call validateField for real-time feedback.
  6. The submit event listener re-validates all fields and, if everything is valid, shows a success message and resets the form. Otherwise, it alerts the user to fix errors.

Take some time to build the basic HTML structure for the form, and then add the JavaScript to implement the real-time validation.

If you would like to use the same look and feel for your form, you can copy the CSS from the example and paste it into your code:

body { font-family: sans-serif; /* display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f4f4f4; */ } .container-signup-form { background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 0 10px rgba(0,0,0,0.1); width: 350px; margin: 20px auto; } .form-group-signup { margin-bottom: 15px; } .form-group-signup label { display: block; margin-bottom: 5px; font-weight: bold; } .form-group-signup input[type="text"], .form-group-signup input[type="email"], .form-group-signup input[type="password"] { width: calc(100% - 22px); padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; } .form-group-signup input.invalid { border-color: red; background-color: #ffe0e0;} .form-group-signup input.valid { border-color: green; } .error-message-signup { color: red; font-size: 0.8em; margin-top: 3px; display: block; min-height: 1em; } .signup-button { background-color: #007bff; color: white; padding: 10px 15px; border: none; border-radius: 4px; cursor: pointer; width: 100%; font-size: 16px; } .signup-button:hover { background-color: #0056b3; } .container-signup-form h2 { text-align: center; color: #333; }

Knowledge Check

Which HTML5 attribute is used to specify that an input field must be filled out before submitting the form?

  • Select an answer to view feedback.

What is the purpose of event.preventDefault() when handling form submissions?

  • Select an answer to view feedback.

Which property of an input element's validity object (inputElement.validity) is true if the input value doesn't match the pattern attribute?

  • Select an answer to view feedback.

When using CSS for form validation feedback, which pseudo-class styles an input element whose value is currently invalid according to its constraints?

  • Select an answer to view feedback.

To provide custom validation messages using the Constraint Validation API, which method do you call on an input element?

  • Select an answer to view feedback.

Summary

  • Client-side validation improves user experience and data quality but is not a substitute for server-side validation.
  • HTML5 provides powerful built-in attributes for common validation tasks.
  • CSS pseudo-classes help in styling forms based on their validation state.
  • The JavaScript Constraint Validation API offers fine-grained control over validation logic and error reporting.
  • event.preventDefault() is crucial for handling form submissions with JavaScript.
  • Real-time validation provides immediate feedback, guiding users to fill forms correctly.

By combining these techniques, you can create robust, user-friendly forms that effectively capture valid user input.


References

The code examples provided in this lesson primarily use the built-in HTML5 validation attributes and the standard JavaScript Constraint Validation API, all of which are well-documented in the MDN resources listed above.


Additional Resources

  • Regular Expressions for Validation:
  • Vanilla JavaScript Validation Libraries:
    • PristineJS: A lightweight, dependency-free vanilla JavaScript library for form validation that can simplify handling common and custom validation rules.