skip to Main Content

I’m trying to make a password validation in javascript, I found several questions here using the same example from W3Schools and I followed all the examples with results but it doesn’t make sure you enter a special character. It does check if you have one and make a green checkmark but it does not require one. I am pretty sure nobody knows there is still a problem everyone is missing. I am sure it is only the html pattern. I don’t know how to force at least 1 special character in the html pattern. here is the pattern I have so far: pattern="(?=.d)(?=.[a-z])(?=.*[A-Z]).{8,}"

var myInput = document.getElementById("password");
var letter = document.getElementById("letter");
var capital = document.getElementById("capital");
var number = document.getElementById("number");
var length = document.getElementById("length");
var special = document.getElementById("special");

// When the user clicks on the password field, show the message box
myInput.onfocus = function() {
    document.getElementById("message").style.display = "block";
}

// When the user clicks outside of the password field, hide the message box
myInput.onblur = function() {
    document.getElementById("message").style.display = "none";
}

// When the user starts to type something inside the password field
myInput.onkeyup = function() {
// Validate lowercase letters
var lowerCaseLetters = /[a-z]/g;
if(myInput.value.match(lowerCaseLetters)) {  
letter.classList.remove("invalid");
letter.classList.add("valid");
} else {
letter.classList.remove("valid");
letter.classList.add("invalid");
}

// Validate capital letters
var upperCaseLetters = /[A-Z]/g;
if(myInput.value.match(upperCaseLetters)) {  
capital.classList.remove("invalid");
capital.classList.add("valid");
} else {
capital.classList.remove("valid");
capital.classList.add("invalid");
}

// Validate numbers
var numbers = /[0-9]/g;
if(myInput.value.match(numbers)) {  
number.classList.remove("invalid");
number.classList.add("valid");
} else {
number.classList.remove("valid");
number.classList.add("invalid");
}

// Validate length
if(myInput.value.length >= 8) {
length.classList.remove("invalid");
length.classList.add("valid");
} else {
length.classList.remove("valid");
length.classList.add("invalid");
}

// Validate special
var specialcharacters = /[`!@#$%^&*()_+-=[]{};':"\|,.<>/?~]/g;
if(myInput.value.match(specialcharacters)) {
special.classList.remove("invalid");
special.classList.add("valid");
} else {
special.classList.remove("valid");
special.classList.add("invalid");
}
}
<style>
#message {
display:none;
background: #EFEFEF;
color: #000;
position: relative;
margin-top: 0px;
text-align:left;
width:100%;
}
#message p {
padding: 2px 35px 2px 60px;
font-size: 18px;
}
/* Add a green text color and a checkmark when the requirements are right */
.valid {
color: green;
}
.valid:before {
position: relative;
left: -20px;
content: "✔";
}
/* Add a red text color and an "x" when the requirements are wrong */
.invalid {
color: red;
}
.invalid:before {
position: relative;
left: -20px;
content: "✖";
color: red;
}
</style>
<form>
<input type="password" name="password" placeholder="Password" id="password" required minlength="8" maxlength="32" pattern="(?=.*d)(?=.*[a-z])(?=.*[A-Z]).{8,}">
</form>

<div id="message">
<div style="padding-top:8px;"></div>
<h2 style="padding-left:40px;font-size:19px;text-decoration:underline;font-weight:650;color:#333;">Password Requirements:</h2>
<p id="letter" class="invalid"><span style="font-weight:600;font-size:17px;">A lowercase letter</span></p>
<p id="capital" class="invalid"><span style="font-weight:600;font-size:17px;">A capital letter</span></p>
<p id="number" class="invalid"><span style="font-weight:600;font-size:17px;">A number</span></p>
<p id="special" class="invalid"><span style="font-weight:600;font-size:17px;">A special character</span></p>
<p id="length" class="invalid"><span style="font-weight:600;font-size:17px;">A minimum of 8 characters</span></p>
</div>

Added (Edited)
I narrowed it down to the html pattern. this pattern almost works: (?=.W)(?=.d)(?=.[ a-z])(?=.[A-Z]).{8,} the (?=.W) forces every other special character except an underscore. It does allow a space which I like. Any idea how I can add an _ to the (?=.W) or another way to do it please?

2

Answers


  1. Chosen as BEST ANSWER

    I figured out the right answer. Change the html regex pattern to:

    pattern="(?=.*[W_])(?=.*d)(?=.*[a-z])(?=.*[A-Z])(?=.*?[0-9]).{8,28}"
    

    this W includes all special characters even the space bar but excluding the underscore. You can block the space bar using javascript return false if you wish:

        function StopSpaces() {
        var key = event.keyCode || event.charCode || event.which ; 
            if(key == 32) {
                return false;}
            else {
        return key; 
        }
        }
    

    add this to the input to activate the prevent spaces function above:

    onKeyDown="return StopSpaces(event)"
    

    No other questions cover this, and there is several on this site using the same code, people probably did not even notice because the javascript works properly and tells you need a special character, but the html skips it unless the html pattern also requires a special character. I am unable to comment on those posts to explain.


  2. You can create an input element for each type of character and then validate against all the input elements with a pattern attribute. As the user type in the password field, the value will be copied to all the other input elements. They are hidden, and have no name attribute (important, so that the field is not included in the submitting of the form). But still, all the required fields need to be valid before the form will be submitted. Now each pattern is simple.

    Like you identified yourself the underscore is included in the word character w and not as a non-word/a special character W. SO, you basically need to add the underscore to the pattern of the "special character" input element.

    document.forms.form01.addEventListener('input', e => {
      let form = e.target.form;
      form.querySelectorAll('input[pattern]')
        .forEach(input => input.value = e.target.value);
    });
    
    document.forms.form01.addEventListener('submit', e => {
      e.preventDefault();
      console.log(...new FormData(e.target));
    });
    input[pattern] {
      display: none;
    }
    
    li:has(input:valid) {
      list-style: "✔";
      color: green;
    }
    
    li:has(input:invalid) {
      list-style: "✖";
      color: red;
    }
    <form name="form01">
      <input type="password" name="password" placeholder="Password" required>
      <h2>Password Requirements:</h2>
      <ul>
        <li><input pattern=".*[a-z]+.*" required>A lowercase letter</li>
        <li><input pattern=".*[A-Z]+.*" required>A capital letter</li>
        <li><input pattern=".*d+.*" required>A number</li>
        <li><input pattern=".*[W_]+.*" required>A special character</li>
        <li><input pattern=".{8,}" required>A minimum of 8 characters</li>
      </ul>
      <button>Submit</button>
    </form>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search