How to validate and sanitize user input in JavaScript

What’s the best way to validate user inputs in JavaScript or Node.JS?

There’s a couple validator modules that I like to use

There are a lot of input validation libraries out there. But to me, the 2 listed above provide the easiest API.

If I’m looking for a sanitizing library, I’ll go with DOMPurify library or validator.js.

Now, don’t mix sanitizing with validating.


const isNotSame = validating !== sanitizing; // true

They’re not the same at all.

What is input validation

Input validation is like running tests about the data the user is filling out in a form.

If they’re is an email field, you want to make sure that it’s not empty, and that it follows a specific email format pattern.

If the form has a name field, you want to make sure that it’s not empty, it’s a string, and that it meets a minimum length requirement.

These tests are helpful to let the user know that the data they’ve entered is correct or incorrect.

If it’s incorrect you can send them a message to correct it.

Validating user input values can happen on the client side for a better user experience, and it should happen in the back-end side as well.

People can bypass the client-side code and send wrongly formatted data to the back-end. So validate in the back-end code as well.

What is output sanitizing

Sanitizing data is best done before displaying the data to the user screen.

It cleanses the original data to prevent it from exploiting any security holes in your application.

I don’t recommend doing input sanitizing because you may risk altering the data in ways that make it unusable.

Validating input: Okay solution

validator.js is a great and easy input validation module to use.

It can be used in Node.js and client-side JavaScript.


import validator from 'validator'; // 62.8k size

const data = {
  name: 'Ruben',
  about: 'I like long walks in the beach.',
  email: 'test@mail.com',
};

// Check if name or about field is empty
if (validator.isEmpty(data.name) || validator.isEmpty(data.about)) {
  console.log('Name or about field is empty')
}

// Check if email format is correct
if (!validator.isEmail(data.email)) {
  console.log('Email format is incorrect')
}

The caveat with this library is that it only validates strings.

If you don’t know your input is going to be a string value than I’d suggest to convert it into a string with a template literal such as backtick quotes.


const age = 20;

console.log(typeof `${age}`); // string

If you don’t support ES6 features, than try this method:


const age = 20;

console.log(age + ''); // '20'

This module is 62.8K and can be reduced to 16.2k if it’s gzipped.

You can also just import modules you need instead of the whole library.


import isEmpty from 'validator/lib/isEmpty'; // 2.2k
import isEmail from 'validator/lib/isEmail'; // 6.9k

In my opinion, I believe validator.js is really nice, but there is better.

Validating input: Best solution

Yup is a light weight JavaScript schema builder. Yup also parses data, and validates it.

Building a schema is extremely simple. Let’s build a schema for the data object that was used above.

First we’re going to create a variable called schema and begin defining the keys of our object.


const schema = yup.object().shape();

Now I will pass my object inside the yup.object().shape() function.


const schema = yup.object()
  .shape({
    name: yup.string().required().min(1, 'Please enter a name'),
    about: yup.string()
      .min(10, 'Enter more than 9 characters')
      .max(160, 'Cannot be more than 160 characters'),
    email: yup.string().email('Please enter a valid email address'),
  });

What I like about Yup is that you can enter custom messages for every test.

Here’s how to test your Yup schema:


const data = {
  name: 'Ruben',
  about: 'I like long walks in the beach.',
  email: 'test@mail.com',
};

schema.validate(data)
  .then(data => console.log(data))
  .catch(err => console.log(err));

It is an asynchronous process, but they have function utilities to make synchronous. I’d recommend doing asynchronous as much as possible.

Output sanitizing: Okay solution

Most template languages (Pug, JSX, etc) have output sanitizing built in by default.

But if you don’t you can use validator.js to clean up a dirty string.


const dirty = `I love to do evil <img src="http://unsplash.it/100/100?random" onload="alert('you got hacked');" />`;

const clean = validator.escape(dirty);

validator.escape() will convert HTML tags into HTML entities.

Output sanitizing: Better solution

I like to use DOMPurify as my main option to sanitize data. I believe it does a much better job.

If you grab the same variable, dirty, and cleanse it with DOMPurify the output would look like


import DOMPurify from 'dompurify';

const clean = DOMPurify.sanitize(dirty);

// I love to do evil <img src="http://unsplash.it/100/100?random">

It leaves the the HTML element, img, but it removes any funky HTML attributes.

Let’s dirty up the string a bit more and see what happens.


const dirty = `I love to do evil <img src="http://unsplash.it/100/100?random" onload="alert('you got hacked');" /> <script>alert("YOU GOT HACKED!");`;

const clean = DOMPurify.sanitize(dirty);

// I love to do evil <img src="http://unsplash.it/100/100?random">

DOMPurify removes any script HTML elements and its content.

If you must do input sanitizing

Again, sanitizing really depends on the context of the data. There are cases where sanitizing input is a must.

To sanitize the users input data you can still use validator.js as I demonstrated above.

Validator.js is supported with both client-side and back-end code.

If you want to make DOMPurify work with Node.js, you’ll have to install an extra NPM module to make it work.

You can check if DOMPurify is supported in your environment by running this if conditional.


if (DOMPurify.isSupported) {
  // ...DO some stuff
}

Here’s the full code to making DOMPurify work in Node.js. Make sure to install jsdom.


npm i -S jsdom dompurify

import createDOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';

import createDOMPurify from 'dompurify';
import { JSDOM } from 'jsdom';

const dirty = `I love to do evil <img src="http://unsplash.it/100/100?random" onload="alert('you got hacked');" /> <script>alert('you got hacked!')</script>`
const windowEmulator = new JSDOM('').window;
const DOMPurify = createDOMPurify(windowEmulator);

if (DOMPurify.isSupported) {
  const clean = DOMPurify.sanitize(dirty)
  console.log(clean);

// I love to do evil <img src="http://unsplash.it/100/100?random">
}

I like to tweet about JavaScript and post helpful code snippets. Follow me there if you would like some too!