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?
I figured it out. Change the html regex pattern to:
pattern="(?=.*[\W_])(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*?[0-9]).{8,32}"
the \W includes all special characters excluding the underscore so I added _ after \W
If the checkmark or X do not show up properly (without color), use another font, Arial works great.
Here is a php code you can use to verify it matches the pattern which will make sure the form is not altered to change the pattern:
$pattern = '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,32}$/';
if (!preg_match($pattern, $_POST['password'])) {
$msg = 'Please do not edit the code!'; // Error Message
$success = 0; // Form has error(s)!
}
Also, add maximum to minimum in the javascript code like this:
// Validate length
if(myInput.value.length >= 8 && myInput.value.length <= 32) {
And, change the html requirements:
<p id="length" class="invalid"><span style="font-weight:600;font-size:17px;">Between 8 and 32 characters</span></p>