Coastal Media Brand

Let’s write our very own password validation. It will include features such as toggling password display, matching a confirm password field, and disabling form submission until the password is valid.

Client-side validation is one of the most important features that can be done with JavaScript. In fact, it’s pretty much why JavaScript was invented in the first place..

Password Validation with JavaScript

Now that we know the purpose of JavaScript, let’s look into how we can apply it. Here’s what we’ll be building:

Let’s take a look at the features on our form to get an idea of what we’ll be building today:

  • Password reveal button
  • Password syntax validation
  • Password confirmation
  • Disabled button for invalid form

Like everything related to web design, user experience is an important consideration when building a feature and although there are several discussions around which method is best for password fields, we’ll be sticking with these features.

We use the password reveal button and password confirmation field so the user has the option of seeing what they’ve typed in the field and confirming if it’s correct. The password syntax validation text is listed clearly so the user knows what format the password should be before typing.

Now that we know what we’re working towards, let’s get started!

1. Form Markup with HTML

This tutorial uses the form from a previous tutorial so the base form styling and markup are explained there:

We’ll be adding some new markup elements to this form to recreate the layout in our demo so this is what our markup looks like now:

1
<div class="form-container">
2
  <form id="form">
3
    <div class="input-container">
4
      <input 
5
        type="password" 
6
        id="password" 
7
        aria-describedby="requirements" 
8
        required 
9
      />
10
      <label for="password">Password</label>
11
      <button 
12
        class="show-password" 
13
        id="show-password" 
14
        type="button" 
15
        role="switch" 
16
        aria-checked="false"
17
        aria-label="Show password" 
18
      >
19
        Show
20
      </button>
21
    </div>
22
    
23
    <div class="password-requirements">
24
      <p class="requirement" id="length">Min. 8 characters</p>
25
      <p class="requirement" id="lowercase">Include lowercase letter</p>
26
      <p class="requirement" id="uppercase">Include uppercase letter</p>
27
      <p class="requirement" id="number">Include number</p>
28
      <p class="requirement" id="characters">Include a special character: #.-?!@$%^&*</p>
29
    </div>
30

31
    <div class="input-container">
32
      <input type="password" id="confirm-password" required />
33
      <label for="confirm-password">Confirm password</label>
34
    </div>
35
    
36
    <div class="password-requirements">
37
      <p class="requirement hidden error" id="match">Passwords must match</p>
38
    </div>
39

40
    <div class="submit-container">
41
      <input type="submit" id="submit" disabled/>
42
    </div>
43
  </form>
44
</div>

We use the requirement elements with different ids under the password field to display the different password syntax requirements. We’ll target these elements later in our JavaScript to handle updating the password validity as the user types.

form input requirementsform input requirements

We also have an error requirement under the confirm password field which we’ll display only when the passwords don’t match.

password doesn’t match labelpassword doesn’t match labelpassword doesn’t match label

The submit button is disabled by default and we’ll use an event listener in JavaScript to determine when it should be enabled.

There are also several accessibility considerations to keep in mind with this implementation. We need to make sure screen readers can also detect the updated password and submit fields. In this case, we’re using the following aria attributes to improve the accessibility of our form.

  • aria-describedby: We assign the content of the password requirements field as the description of the input field to allow the information be read out by screen readers when the input is focused on.
  • role="switch": We use this attribute to indicate that the button is a toggle
  • aria-checked: This attribute is used together with the role="switch" attribute to indicate whether the switch element is toggled on or off
  • aria-label: We use the aria-label to provide more descriptive text on our password toggle button for screen readers.

We’ll handle updating these attributes as needed in the JavaScript section. This article also shares more information on accessibility of password fields.

2. Styling Form Elements with CSS

We’ll use our styling to handle the different states of our submit button and password requirements. We’ll also apply some styles to the password toggle button to be displayed when the input field is being hovered or focused on.

1
input[type=submit] {
2
  transition: .25s;
3
  border-radius: 4px;
4
  border: 1px solid rgba(0, 0, 0, 0.12);
5
  padding: 16px;
6
  background-color: white;
7
  text-transform: uppercase;
8
  letter-spacing: 0.08em;
9
  font-size: 14px;
10
}
11

12
input[type=submit]:disabled {
13
  color: #808080;
14
  background-color: #f5f5f5;
15
  cursor: not-allowed;
16
}
17

18
input[type=submit]:not(:disabled):hover {
19
  border-color: transparent;
20
  background-color: #6200ee24;
21
  color: #6200ee;
22
}
23

24
.show-password {
25
  transition: opacity .25s;
26
  position: absolute;
27
  background-color: transparent;
28
  right: 0;
29
  margin: auto;
30
  top: 0;
31
  bottom: 0;
32
  height: fit-content;
33
  border: none;
34
  font-size: 10px;
35
  color: grey;
36
  cursor: pointer;
37
  outline: none;
38
  text-transform: uppercase;
39
}
40

41
.show-password:hover,
42
.show-password:focus {
43
  color: black;
44
}
45

46
.input-container:not(:hover, :focus-within) .show-password {
47
  opacity: 0;
48
}
49

50
.password-requirements {
51
  display: flex;
52
  flex-wrap: wrap;
53
  margin-top: -1rem;
54
  padding: 0 16px;
55
}
56

57
.requirement {
58
  font-size: 14px;
59
  flex: 1 0 50%;
60
  min-width: max-content;
61
  margin: 2px 0;
62
}
63

64
.requirement:before {
65
  content: '2639';
66
  padding-right: 5px;
67
  font-size: 1.6em;
68
  position: relative;
69
  top: .15em;
70
}
71

72
.requirement:not(.valid) {
73
  color: #808080;
74
}
75

76
.requirement.valid {
77
  color: #4CAF50;
78
}
79

80
.requirement.valid:before {
81
  content: '263A';
82
}
83

84
.requirement.error {
85
  color: red;
86
}
87


3. Validation Functionality (JavaScript)

Now we can get down to writing code. Let’s start with the password toggle feature.

How to Build A Password Toggle with JavaScript

First, we’ll get the elements for our password fields and toggle button and store them as global variables.

1
const password = document.getElementById("password");
2
const confirmPassword = document.getElementById("confirm-password");
3
const showPassword = document.getElementById("show-password")

Once we have our elements, we can use event listeners to detect when the toggle has been clicked and update the fields accordingly.

In this case, when the password toggle is switched on, we want to change the input type attribute from password to text as this is what allows the text in the password field to be visible. Alternatively, when the password toggle is switched off, we’ll change the password fields back to type password. We also want to update the show password button text and aria values accordingly. 

1
showPassword.addEventListener('click', (event) => {
2
  if (password.type == 'password') {
3
    password.type = "text"
4
    confirmPassword.type = "text"
5
    showPassword.innerText = 'hide'
6
    showPassword.setAttribute('aria-label', 'hide password')
7
    showPassword.setAttribute('aria-checked', 'true')
8
  } else {
9
    password.type = "password"
10
    confirmPassword.type = "password"
11
    showPassword.innerText = 'show'
12
    showPassword.setAttribute('aria-label', 'show password')
13
    showPassword.setAttribute('aria-checked', 'false')
14
  }
15
})

How to Confirm Password with JavaScript

The next feature we’ll be working on is the password confirmation. With this implementation, we’ll add an event listener to the confirm password field to compare the values of the two fields once a user has finished typing.

To optimise performance, we can choose to either debounce this function or call it on blur.

Debouncing the confirmation function means we’ll be comparing the values when the user stops typing for a certain amount of time while blur means we’ll compare the values once the user removes focus from the confirm password field. Either implementation will suffice.

For this demo, we’ll be calling the function on blur but if you’d rather use the debounce function, this article explains more on how to implement that:

This is what the code looks like:

1
const password = document.getElementById("password");
2
const confirmPassword = document.getElementById("confirm-password");
3
const matchPassword = document.getElementById("match");
4

5
confirmPassword.addEventListener("blur", (event) => {
6
  const value = event.target.value
7
  
8
  if (value.length && value != password.value) {
9
    matchPassword.classList.remove('hidden')
10
  } else {
11
    matchPassword.classList.add('hidden')
12
  }
13
})

If the value of the confirm password field is not empty and is not equal to the password field value on blur, then we display the password match error message.

We can also use a focus event listener to handle hiding the error message when the user starts typing again.

1
confirmPassword.addEventListener("focus", (event) => {
2
  matchPassword.classList.add('hidden')
3
})

How to Validate Password Syntax with JavaScript

Next, we want to handle validating the password as the user types it in. The password has to meet the following requirements:

  1. A minimum of 8 characters
  2. At least one uppercase letter
  3. At least one lowercase letter
  4. At least one number
  5. At least one special character from this list: #.-?!@$%^&*

We’ll need to define functions to handle each of these requirements, but first let’s define our general function to determine what happens when the requirement is valid or not.

If the requirement is valid, we add a class valid to the requirement element display, and if it’s invalid, we remove the class. We’ll also need to target the specific requirement element using their id. This is what our function looks like:

1
const updateRequirement = (id, valid) => {
2
  const requirement = document.getElementById(id);
3

4
  if (valid) {
5
    requirement.classList.add("valid");
6
  } else {
7
    requirement.classList.remove("valid"); 
8
  }
9
};

Now that we have our function to update the requirement, we’ll need to call this function for every requirement when our user types. Each requirement has a JavaScript function to check the condition:

To verify the minimum number of characters, we’ll check if the password length is greater than 8

To check if the password contains a lowercase letter, we’ll use the regex syntax:

Let’s quickly break down the regex expression here as we’ll be using this for the other syntax validations:

  • //: The slash is used to wrap a regex expression, similar to how a curly bracket is used to wrap a JavaScript function.
  • []: The square bracket is used as an “any” condition for regex, this means it will return true if the value being tested contains any of the characters in the square bracket.
  • a-z: This expression returns a match for any characters between lowercase a and lowercase z.
  • .test(): This method is used to match the value being tested to the regex expression.

To check if the password contains an uppercase letter:

To check if the password contains a number:

  • d: This is a regex character used to match any digit between 0-9. We could get the same result by using [0-9].

To check if the password contains special characters:

1
/[#.?!@$%^&*-]/.test(value)

We’ve gotten the conditions for all our password requirements so we can pass them into an input event listener on the password field to handle updating the corresponding requirement with its condition. This is what the code looks like:

1
const password = document.getElementById("password");
2

3
password.addEventListener("input", (event) => {
4
  const value = event.target.value;
5
  
6
  updateRequirement('length', value.length >= 8)
7
  updateRequirement('lowercase', /[a-z]/.test(value))
8
  updateRequirement('uppercase', /[A-Z]/.test(value))
9
  updateRequirement('number', /d/.test(value))
10
  updateRequirement('characters', /[#.?!@$%^&*-]/.test(value))
11
});

This is what our password validation form looks like now:

How to Disable a Submit Button with JavaScript

The last feature to implement is disabling the form button and preventing submission until the form is valid. In this case, our form is considered valid when the input in the password field meets all requirements and the confirm password input is the same as the password input.

Let’s handle confirming that the password meets all requirements. We can achieve this by combining the syntax logic into one function:

1
value.length >= 8 && 
2
    /[a-z]/.test(value) && 
3
    /[A-Z]/.test(value) && 
4
    /d/.test(value) && 
5
    /[#.?!@$%^&*-]/.test(value)

Fun fact, we can get the same logic above using just one line of regex:

/^(?=.*d)(?=.*[a-z])(?=.*[A-Z])(?=.*[a-zA-Z]).{8,}$/

That’s quite the expression!

Next we update our function to also check if the password fields match and if everything is in order, then we enable the submit button. This is what our function looks like:

1
const handleFormValidation = () => {
2
  const value = password.value;
3
  const confirmValue = confirmPassword.value;
4

5
  if (
6
    value.length >= 8 &&
7
    /[a-z]/.test(value) &&
8
    /[A-Z]/.test(value) &&
9
    /d/.test(value) &&
10
    /[#.?!@$%^&*-]/.test(value) &&
11
    value == confirmValue
12
  ) {
13
    submit.removeAttribute("disabled");
14
    return true;
15
  }
16

17
  submit.setAttribute("disabled", true);
18
  return false;
19
};

Finally, we use the change and submit event listeners on the form to detect if the form is valid before allowing the information be submitted.

1
form.addEventListener("change", () => {
2
  handleFormValidation();
3
});
4

5
form.addEventListener("submit", (event) => {
6
  event.preventDefault();
7
  const validForm = handleFormValidation();
8

9
  if (!validForm) {
10
    return false;
11
  }
12

13
  alert("Form submitted");
14
});

Conclusion

And we’re done! Let’s take a look at the final product again after all that code:

Web Design Myrtle Beach

Coastal Media Brand