Skip to content

Instantly share code, notes, and snippets.

@summersab
Last active June 8, 2022 15:58
Show Gist options
  • Save summersab/9213ee0ef0ea63930e4404632045546f to your computer and use it in GitHub Desktop.
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)
<!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