Last active
June 8, 2022 15:58
-
-
Save summersab/9213ee0ef0ea63930e4404632045546f to your computer and use it in GitHub Desktop.
A pretty and dynamic password requirements tooltip and validator (pure HTML and JS)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<!-- inspired by https://myloan.fremontbank.com/ --> | |
<html> | |
<head> | |
<style> | |
#password-validator { | |
position: absolute; | |
z-index: 50; | |
margin-top: 20px; | |
display: none; | |
transition: 0; | |
} | |
.fade-out { | |
opacity: 0; | |
pointer-events: none; | |
} | |
#password-validator.fade-out { | |
transition: opacity 1s; | |
} | |
.arrow { | |
height: 25px; | |
left: 50%; | |
overflow: hidden; | |
position: absolute; | |
top: -25px; | |
-webkit-transform: (-50%); | |
-ms-transform: translateX(-50%); | |
transform: translateX(-50%); | |
width: 50px; | |
} | |
.arrow::after { | |
background: #FFFFFF; | |
box-shadow: 1px 1px 14px 0px rgb(0 0 0 / 20%); | |
content: ""; | |
height: 20px; | |
left: 50%; | |
position: absolute; | |
-webkit-transform: translateX(-50%) translateY(75%) rotate(45deg); | |
-ms-transform: translateX(-50%) translateY(75%) rotate(45deg); | |
transform: translateX(-50%) translateY(75%) rotate(45deg); | |
width: 20px; | |
} | |
.inputValidationIndicator { | |
border-top-left-radius: 10px; | |
border-top-right-radius: 10px; | |
border-bottom-left-radius: 10px; | |
border-bottom-right-radius: 10px; | |
padding-top: 15px; | |
padding-right: 14px; | |
padding-bottom: 10px; | |
padding-left: 14px; | |
background-color: #FFFFFF; | |
box-shadow: 1px 1px 14px 0px rgb(0 0 0 / 20%); | |
font-size: 11px; | |
line-height: 15px; | |
} | |
.header { | |
font-size: 12px; | |
font-weight: 400; | |
margin-bottom: 15px; | |
padding-left: 4px; | |
} | |
.conditionList { | |
padding-left: 0px; | |
} | |
.conditionWrapper { | |
padding-top: 3px; | |
padding-right: 0px; | |
padding-bottom: 3px; | |
padding-left: 4px; | |
list-style-type: none; | |
margin-bottom: 4px; | |
color: red; | |
} | |
</style> | |
</head> | |
<body> | |
<form> | |
<label for="password">Password:</label><br> | |
<input type="password" name="password"><br> | |
<div id="password-validator"> | |
<div class="arrow"></div> | |
<div class="inputValidationIndicator"> | |
<h2 class="header">Your password must include:</h2> | |
<ul class="conditionList"> | |
<li class="conditionWrapper length"><span class="condition"> or more characters</span></li> | |
<li class="conditionWrapper uppercase"><span class="condition">an uppercase letter</span></li> | |
<li class="conditionWrapper lowercase"><span class="condition">a lowercase letter</span></li> | |
<li class="conditionWrapper number"><span class="condition">a number</span></li> | |
<li class="conditionWrapper special"><span class="condition">a special character (! # $ ? % @)</span></li> | |
</ul> | |
</div> | |
</div> | |
<br> | |
<input type="submit" value="Submit"> | |
</form> | |
<script> | |
const conditions = { | |
"length": 12, | |
"uppercase": true, | |
"lowercase": true, | |
"number": false, | |
"special": false, | |
}; | |
var validations = { | |
}; | |
const pwInput = document.querySelector('input[type=password]'); | |
const validator = document.querySelector('#password-validator'); | |
const submit = document.querySelector('input[type=submit]'); | |
var valid = false; | |
window.onload = function(){ | |
submit.disabled = true; | |
Object.keys(conditions).forEach(key => { | |
var element = validator.querySelector('.conditionWrapper.' + key); | |
if (conditions[key] == false) { | |
element.style.display = 'none'; | |
} | |
else { | |
validations[key] = false; | |
} | |
if (key == 'length') { | |
element.textContent = conditions.length + element.textContent; | |
} | |
}); | |
}; | |
pwInput.addEventListener('focusin', function() { | |
if (valid == false) { | |
const cssObj = window.getComputedStyle(pwInput, null); | |
validator.style.width = cssObj.width; | |
validator.style.display = "block"; | |
} | |
}); | |
pwInput.addEventListener('focusout', function() { | |
validator.style.display = "none"; | |
}); | |
pwInput.addEventListener('keyup', function() { | |
var validationsMet = true; | |
Object.keys(validations).forEach(key => { | |
var element = validator.querySelector('.conditionWrapper.' + key); | |
switch(key) { | |
case 'length': | |
if (pwInput.value.length >= conditions.length) { | |
validations[key] = true; | |
} | |
else { | |
validations[key] = false; | |
} | |
break; | |
case 'uppercase': | |
if (pwInput.value.search(/.*[A-Z].*/) == 0) { | |
validations[key] = true; | |
} | |
else { | |
validations[key] = false; | |
} | |
break; | |
case 'lowercase': | |
if (pwInput.value.search(/.*[a-z].*/) == 0) { | |
validations[key] = true; | |
} | |
else { | |
validations[key] = false; | |
} | |
break; | |
case 'number': | |
if (pwInput.value.search(/.*[0-9].*/) == 0) { | |
validations[key] = true; | |
} | |
else { | |
validations[key] = false; | |
} | |
break; | |
case 'special': | |
if (pwInput.value.search(/.*[^a-zA-Z0-9].*/) == 0) { | |
validations[key] = true; | |
} | |
else { | |
validations[key] = false; | |
} | |
break; | |
} | |
if (validations[key] == false) { | |
element.style.color = 'red'; | |
validationsMet = false; | |
} | |
else { | |
element.style.color = 'green'; | |
} | |
}); | |
valid = validationsMet; | |
if (valid) { | |
submit.disabled = false; | |
validator.classList.toggle('fade-out', true); | |
} | |
else { | |
submit.disabled = true; | |
validator.classList.toggle('fade-out', false); | |
validator.style.display = "block"; | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment