You Have Been Doing Form Validation Wrong!

Use these 8 best practices to ensure that your web forms are validated

Chameera Dulanga
Bits and Pieces

--

Form validation in JavaScript is like having a guardian to safeguard your web forms. It’s an essential part of modern web development to ensure the data is accurate and nothing harmful sneaks into your system.

However, the effectiveness of form validation depends on following the best practices. Ignoring these best practices can result in performance issues, user experience issues, and security vulnerabilities. So, this article will discuss the importance of form validation, various form validation methods, and the essential best practices you should follow to create secure forms in your applications.

What is Form Validation?

Form validation is a fundamental part of web and mobile app development that ensures the user inputs are correct, safe, and meet predefined criteria before it’s sent to a server, stored in a database, or processed in any way.

Ultimately, it serves three main purposes in application development:

1. Improve Data Quality

Validations act as gatekeepers, verifying that the information users provide aligns with the expected format and content. For example, if a form requests an email address, we can use validations to check if the user entered value is a valid email address.

<form>
<label for="email">Email Address:</label>
<input type="email" id="email" name="email" required>
<button type="submit">Submit</button>
</form>

Furthermore, we can use validations to ensure users only enter data according to a defined pattern. For example, we can use patterns to ensure all the users enter dates and mobile numbers in a unified format.

<form>
<label for="dob">Date of Birth (dd/mm/yyyy):</label>
<input type="text" id="dob" name="dob" pattern="\d{2}/\d{2}/\d{4}" required>
<button type="submit">Submit</button>
</form>

2. Improve Security

Form validation functions as a defence mechanism against potential security threats. If you haven’t correctly validated inputs, attackers can easily manipulate those inputs to perform attacks like SQL injections and XSS.

3. Preventing Errors

Form validation helps users avoid common mistakes. For example, when users attempt to submit a form without providing a required field, they receive immediate feedback, enhancing their overall experience.

Common Form Validation Techniques

When it comes to form validation, there are several techniques to choose from depending on the specific requirements of your web or mobile application. Here’s an overview of some common form validation techniques:

1. Traditional HTML Form Validation

Traditional HTML offers built-in attributes allowing basic form validation without needing JavaScript. These attributes include “required,” “min,” and “max” for input fields. They are simple to use and provide instant feedback to users.

<form>
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<button type="submit">Submit</button>
</form>

2. Client-Side Validations

Client-side validation uses JavaScript to perform more customized and complex form validation in the user’s browser. It allows you to create custom validation functions to check various aspects of user input, such as format, length, or specific requirements.

The below examples show a simple JavaScript validation function to check if a password is at least 8 characters long:

<script>
function validatePassword() {
const passwordInput = document.getElementById("password");
if (passwordInput.value.length < 8) {
alert("Password must be at least 8 characters long.");
return false;
}
return true;
}
</script>

3. Server-Side Validations

Server-side validation is the last line of defense for your web application’s data integrity and security. It takes place on the server after a user submits a form. Its primary role is to ensure that the data received is accurate, adheres to business rules, and remains secure.

The below example shows how to validate the uniqueness of the username using Node.js:

app.post("/submitForm", (req, res) => {
const { username } = req.body;
if (!isUsernameUnique(username)) {
res.status(400).send("Username already exists");
} else {
// Process the data
}
});

The choice of technique depends on the specific needs of your applications. But, it is essential to follow best practices to get the maximum out of any technique.

Best Practices and Tips in Validating Forms in JavaScript

Since you now understand what form validation is and different techniques, let’s see what are the best practices you need to follow:

1. Use a Combination of Client-Side and Server-Side Validation

Client-Side and Server-Side Validation are two essential layers of form validation. Client-side validation occurs on the user’s device, while server-side validation happens on the web server.

Client-side validation enhances the user experience by providing instant feedback on how to correct their inputs. However, client-side validation alone is insufficient for security, as it can be bypassed. Server-side validation acts as the final line of defense, ensuring that only legitimate, safe data is processed and stored in databases.

The below client-side and server-side validation examples show how to check if the username is at least 4 characters long.

// CLIENT SIDE

<form id="registration-form">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<button type="submit">Submit</button>
</form>

<script>
const form = document.getElementById("registration-form");

form.addEventListener("submit", async (event) => {
const usernameInput = document.getElementById("username");
if (usernameInput.value.length < 4) {
alert("Username must be at least 4 characters long.");
event.preventDefault();
return;
}
});
</script>

// SERVER SIDE

app.post("/api/validate-username", (req, res) => {
const { username } = req.body;

if (username.length < 4) {
res.json({ isValid: false, message: "Username must be at least 4 characters long." });
} else {
// Process data
}
});

2. Provide Clear and User-Friendly Error Messages

When implementing form validation, it’s not enough to merely validate user inputs; you must communicate validation errors effectively. Clear and user-friendly error messages significantly enhance the overall user experience, helping them to understand what went wrong and how to correct it.

A proper error message should be concise, informative, and guidance-oriented like below:

// HTML Form

<form id="registration-form">
<label for="password">Password:</label>
<input type="password" id="password" name="password" required>
<div class="error-message" id="password-error"></div>
<button type="submit">Submit</button>
</form>

// JS Validation

const form = document.getElementById("registration-form");
const passwordInput = document.getElementById("password");
const passwordError = document.getElementById("password-error");

form.addEventListener("submit", (event) => {
passwordError.textContent = "";
passwordInput.classList.remove("error");

const passwordValue = passwordInput.value;
const requirements = [
{ condition: passwordValue.length >= 8, message: "Password must be at least 8 characters long." },
{ condition: /[A-Z]/.test(passwordValue), message: "Password must contain at least one uppercase letter." },
{ condition: /[a-z]/.test(passwordValue), message: "Password must contain at least one lowercase letter." },
{ condition: /\d/.test(passwordValue), message: "Password must contain at least one digit." },
{ condition: /[!@#$%^&*]/.test(passwordValue), message: "Password must contain at least one special character (!@#$%^&*)." }
];

for (const requirement of requirements) {
if (!requirement.condition) {
passwordError.textContent = requirement.message;
passwordError.style.color = "red";
passwordInput.classList.add("error");
passwordInput.focus();
event.preventDefault();
break;
}
}
});

You can find a working Stackblitz example here.

3. Validate Data Types and Formats

Validating data types and formats involves using regular expressions or other methods to check if user inputs (email addresses, phone numbers, or dates) conform to the predefined format and data type. This best practice is crucial for data accuracy and system security since it prevents data corruption and security vulnerabilities like SQL injection or cross-site scripting.

Here’s an example of how to validate an email address format using JavaScript:

// HTML form 

<form id="registration-form">
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<div class="error-message" id="email-error"></div>
<button type="submit">Submit</button>
</form>

// JS Validation

const form = document.getElementById("registration-form");
const emailInput = document.getElementById("email");
const emailError = document.getElementById("email-error");

form.addEventListener("submit", (event) => {
emailError.textContent = "";
emailInput.classList.remove("error");

const emailValue = emailInput.value;
const emailRegex = /^[a-zA-Z0-9._-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/;

if (!emailRegex.test(emailValue)) {
emailError.textContent = "Please enter a valid email address.";
emailError.style.color = "red";
emailInput.classList.add("error");
emailInput.focus();
event.preventDefault();
}
});

You can find a working Stackblitz example here.

4. Implement Input Sanitization:

Input sanitization is the process of cleaning and validating user-generated content to remove potentially harmful data, such as malicious scripts. Implementing input sanitization is essential for enhancing security and protecting applications from security threats like cross-site scripting (XSS) and SQL injection.

Here’s an example of how to implement input sanitization to protect against XSS attacks using the DOMPurify library in JavaScript:

// HTML form 

<form id="comment-form">
<label for="comment">Comment:</label>
<textarea id="comment" name="comment" required></textarea>
<button type="submit">Submit</button>
</form>

// JS Validation

import * as DOMPurify from 'dompurify';

const form = document.getElementById("comment-form");
const commentInput = document.getElementById("comment");

form.addEventListener("submit", (event) => {
const userInput = commentInput.value;
const sanitizedInput = DOMPurify.sanitize(userInput);

// Replace the original input with sanitized content
commentInput.value = sanitizedInput;
});

You can find a working Stackblitz example here.

5. Utilize Error Classes and Styles

Using error classes and styles enhances the user experience, making it visually clear which inputs need attention. This helps users quickly identify and correct their input mistakes while giving a professional appearance to your application.

The below example shows how to apply error classes when validation detects errors:

<!-- HTML form with error classes and styles -->
<form id="contact-form">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<div class="error-message" id="name-error"></div>

<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<div class="error-message" id="email-error"></div>

<button type="submit">Submit</button>
</form>

<style>
.error-message {
color: red;
font-size: 0.9rem;
}

.error {
border: 1px solid red;
}
</style>

<script>
const form = document.getElementById("contact-form");

form.addEventListener("submit", (event) => {
const nameInput = document.getElementById("name");
const emailInput = document.getElementById("email");
const nameError = document.getElementById("name-error");
const emailError = document.getElementById("email-error");

nameError.textContent = "";
emailError.textContent = "";
nameInput.classList.remove("error");
emailInput.classList.remove("error");

if (nameInput.value.trim() === "") {
nameError.textContent = "Please enter your name.";
nameInput.classList.add("error");
event.preventDefault();
}

const emailValue = emailInput.value.trim();
if (emailValue === "") {
emailError.textContent = "Please enter your email address.";
emailInput.classList.add("error");
event.preventDefault();
} else if (!/^\S+@\S+\.\S+$/.test(emailValue)) {
emailError.textContent = "Please enter a valid email address.";
emailInput.classList.add("error");
event.preventDefault();
}
});
</script>

6. Regularly Update and Review Validation Rules

Regularly updating and reviewing validation rules is essential for maintaining the accuracy and security of your application. It allows you to adapt to changing user needs and security standards, reducing the risk of outdated validation methods failing to protect against emerging threats.

7. Implement Cross-Browser Compatibility

Cross-browser compatibility ensures your form validation code works consistently across various web browsers. Different browsers may interpret HTML, JavaScript, and CSS differently, impacting how your form validation behaves.

Here is how to verify cross-browser compatibility of your validations:

  • Test your validations on multiple browsers, including popular options like Chrome, Firefox, Safari, and Edge.
  • Use standardized HTML, JavaScript, and CSS that adhere to web standards to minimize cross-browser issues.
  • Keep your libraries and frameworks up to date, as they often include fixes for browser compatibility.

8. Validate and Sanitize File Uploads

Similar to sanitizing inputs, it is essential to validate and sanitize all the file uploads in your application. It prevents users from uploading incompatible or malicious files that could compromise your system.

For example, you can define acceptable file formats, types, and sizes in frontend like below. The accept attribute specifies the accepted file types (in this case, only JPEG and PNG images).

<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" accept=".jpg, .jpeg, .png" required>
<button type="submit">Upload File</button>
</form>

Also, you can implement file validations on server-side using middleware like multer:

const express = require('express');
const multer = require('multer');
const upload = multer({ dest: 'uploads/' });

....

app.post('/upload', upload.single('file'), (req, res) => {
// Check if a file was uploaded
if (!req.file) {
return res.status(400).send('No file was uploaded.');
}

// Check if the uploaded file is of an accepted type
const allowedFileTypes = ['.jpg', '.jpeg', '.png'];
const fileExtension = '.' + req.file.originalname.split('.').pop();

if (!allowedFileTypes.includes(fileExtension)) {
return res.status(400).send('Invalid file type. Only .jpg, .jpeg, and .png are allowed.');
}

// Perform additional server-side validation, like scanning for malware or resizing images
// If validation passes, save or process the file

res.status(200).send('File uploaded successfully.');
});

...

Conclusion

Form validation is like a guardian for your web forms, ensuring data is correct and secure. This article discussed 8 essential best practices with examples to help you build a solid input validation mechanism. Following these practices is crucial for a smooth user experience, accurate data, and strong security. I encourage you to apply them in your applications, ensuring a safer and better user journey.

--

--