Enforcing secure passwords is an essential part on any login system. The first step in this process is ensuring that users select a password which matches a set of criteria. Here is a fairly common set of requirements when setting a password:
- Minimum length of 8 characters
- Contains a lowercase letter
- Contains an uppercase letter
- Contains a number or special character
Unfortunately, all these restrictions can put a bit of a damper on the user experience. This is especially true if the user is not warned about the requirements before submitting a form. One solution I’ve seen to this problem is checking the password validity inline as the user types. This makes it easy for the user to quickly see if their password fits the requirements before submitting the form.
In this tutorial, we will be building a password validator using JavaScript. The validator will check the password as the user types and compare it to the list of requirements. It will also provide a visual representation of which requirements have already been met.
Set up the Form
The first thing we need to do is create a form with a password field, label and list of helper items. Open up a new HTML file and enter the following code inside the body
.
<form>
<label for="password">Password</label>
<input class="password" name="password" type="text" autofocus />
<ul class="helper-text">
<li class="length">Must be at least 8 characters long</li>
<li class="lowercase">Must contain a lowercase letter</li>
<li class="uppercase">Must contain an uppercase letter</li>
<li class="special">Must contain a number or special character</li>
</ul>
</form>
The list of helper items will help the user understand the password requirements. Each item’s color will change to green as the item is validated.
Evaluate the Password with JavaScript
Now that we’ve create the form, it’s time to move on to the fun part – JavaScript. The first thing we’ll do is create an immediately-invoked function expression (IFFE). The name might sound overly-complex, but it’s really just a way of isolating any variables that we create to this specific scope and keep them out of the global namespace.
(function(){
})();
If you want to learn more about IFFE, Check out the following link: Immediately-Invoked Function Expression
Some Variables
Next we will set up a few variables to help us identify different parts of the form. The first variable references the password input field and the second is an object which references each of our helper text items. Place the following code inside the immediately-invoked function expression.
var password = document.querySelector('.password');
var helperText = {
charLength: document.querySelector('.helper-text .length'),
lowercase: document.querySelector('.helper-text .lowercase'),
uppercase: document.querySelector('.helper-text .uppercase'),
special: document.querySelector('.helper-text .special')
};
Validation Object
Our password will need to pass a few test to be considered valid. The object below contains a method for each of the requirements mentioned above. Most of the methods use regular expressions to test the password, which means altering a requirement or adding a new one could be done easily. Add the following code just below the variables we created in the previous step.
var pattern = {
charLength: function() {
if( password.value.length >= 8 ) {
return true;
}
},
lowercase: function() {
var regex = /^(?=.*[a-z]).+$/;
if( regex.test(password.value) ) {
return true;
}
},
uppercase: function() {
var regex = /^(?=.*[A-Z]).+$/;
if( regex.test(password.value) ) {
return true;
}
},
special: function() {
var regex = /^(?=.*[0-9_\W]).+$/;
if( regex.test(password.value) ) {
return true;
}
}
};
Helper Functions
Let’s create a few functions to save us from writing repeat code later. If you’re familiar with jQuery, some of these functions may look familiar. Add the following code at the bottom of your JavaScript file (just before the IFFE closure).
function patternTest(pattern, response) {
if(pattern) {
addClass(response, 'valid');
} else {
removeClass(response, 'valid');
}
}
function addClass(el, className) {
if (el.classList) {
el.classList.add(className);
} else {
el.className += ' ' + className;
}
}
function removeClass(el, className) {
if (el.classList) {
el.classList.remove(className);
} else {
el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
}
}
function hasClass(el, className) {
if (el.classList) {
console.log(el.classList);
return el.classList.contains(className);
} else {
new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
}
}
Tying It All Together
Now that we’ve laid the foundation, we can start tying everything together. The password string will be evaluated after each key press so the user can quickly see the result. Let’s create an event listener to capture keyboard events inside the password field. Add the following code to the JavaScript file.
password.addEventListener('keyup', function (){
});
Next we will use the patternTest()
function we created earlier to test each requirement in the pattern object. Each of these tests will evaluate if the password matches the given requirement and add class="valid"
to the appropriate helper text item. The following code should be added within the addEventListener()
function from above.
patternTest( pattern.charLength(), helperText.charLength );
patternTest( pattern.lowercase(), helperText.lowercase );
patternTest( pattern.uppercase(), helperText.uppercase );
patternTest( pattern.special(), helperText.special );
Validation Response
The last thing we need to do is check if all the requirements have been met. If they have we will add class="valid"
to the HTML form. If your form has a submit button, this would also be a good place to change the button state from disabled to active. Add the following to the end of the addEventListener()
function.
if( hasClass(helperText.charLength, 'valid') &&
hasClass(helperText.lowercase, 'valid') &&
hasClass(helperText.uppercase, 'valid') &&
hasClass(helperText.special, 'valid')
) {
addClass(password.parentElement, 'valid');
}
else {
removeClass(password.parentElement, 'valid');
}
Final Thoughts
In this tutorial we took a look at one way to manage password validation based on a list of formatting requirements. The solution focused on creating a better user experience by providing the requirements upfront and evaluating them in real-time. The finished code and demo for this project can be found on CodePen.