Build a Live Password Strength Checker with JavaScript
Challenge Goal
Build a live password strength checker that evaluates a password while the user types. You will practice JavaScript event handling, regular expressions, DOM manipulation, conditional logic, and accessible UI feedback.
The finished component should check several password requirements, calculate a strength score, display a visual strength meter, and tell the user whether the current password is Weak, Medium, or Strong.
What You Will Build
Create a password input with a strength meter underneath it. Every time the user types or removes a character, JavaScript should immediately evaluate the password and update the meter.
For example:
abcshould be considered Weak.abcdef12may be considered Medium.Abcdef12!should be considered Strong because it satisfies all required criteria.
Requirements
Your password checker must:
- Listen for the
inputevent on a password field. - Check whether the password contains at least 8 characters.
- Check whether it contains both lowercase and uppercase letters.
- Check whether it contains at least one number.
- Check whether it contains at least one special character such as
!@#$%^&*. - Give one point for every requirement that passes.
- Display Weak, Medium, or Strong based on the score.
- Update the visual meter immediately while the user types.
- Reset the meter when the password field is empty.
- Provide accessible text feedback using an
aria-liveregion.
Input and Output
Input
A password string entered into an HTML password field.
Output
The page should update the strength meter and text label according to the number of requirements satisfied.
- Empty password: No strength rating and 0% meter width.
- Score 1: Weak and 25% meter width.
- Score 2 or 3: Medium and 50% or 75% meter width.
- Score 4: Strong and 100% meter width.
Constraints
- Use only HTML, CSS, and vanilla JavaScript.
- Do not use third-party password-strength libraries.
- The minimum password length is 8 characters.
- Use regular expressions or equivalent JavaScript checks for the criteria.
- Do not send or store the entered password anywhere.
- The solution should work in modern versions of Chrome, Firefox, Edge, and Safari.
Strength Rules
Give the password one point for each condition it satisfies:
- At least 8 characters.
- Contains both uppercase and lowercase letters.
- Contains at least one number.
- Contains at least one special character.
Map the final score to a strength level:
- 0: No rating when the field is empty, otherwise Weak.
- 1: Weak.
- 2-3: Medium.
- 4: Strong.
Hints
- Use
password.length >= 8for the length requirement. - Use
/[a-z]/and/[A-Z]/to check lowercase and uppercase characters. - Use
/\d/to detect a number. - Use a regular expression such as
/[!@#$%^&*]/to detect an allowed special character. - Store the results in an array and use
filter(Boolean).lengthto count how many tests passed. - Keep password evaluation separate from DOM updates so the logic is easier to understand and test.
Starter Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Password Strength Checker</title>
<style>
.meter {
width: 100%;
max-width: 400px;
height: 10px;
margin-top: 10px;
background: #e5e7eb;
border-radius: 5px;
overflow: hidden;
}
.strength-bar {
width: 0;
height: 100%;
transition: width 0.25s ease;
}
.strength-weak {
background: #dc2626;
}
.strength-medium {
background: #d97706;
}
.strength-strong {
background: #16a34a;
}
</style>
</head>
<body>
<label for="password">Password:</label>
<input
type="password"
id="password"
autocomplete="new-password"
aria-describedby="strengthText"
>
<div class="meter" aria-hidden="true">
<div id="strengthBar" class="strength-bar"></div>
</div>
<p id="strengthText" aria-live="polite">Strength: Not rated</p>
<script>
const passwordInput = document.getElementById('password');
const strengthBar = document.getElementById('strengthBar');
const strengthText = document.getElementById('strengthText');
function evaluatePassword(password) {
// Return the number of requirements that pass.
}
function updateStrength(password, score) {
// Update the meter and text feedback.
}
passwordInput.addEventListener('input', () => {
const password = passwordInput.value;
const score = evaluatePassword(password);
updateStrength(password, score);
});
</script>
</body>
</html>
Solution Walkthrough
1. Read the Password
The input event runs whenever the value changes. This makes it suitable for real-time feedback because the checker responds immediately as the user types.
2. Test Each Requirement
The evaluatePassword() function performs four independent checks. Each result is stored as a Boolean value.
const checks = [
password.length >= 8,
/[a-z]/.test(password) && /[A-Z]/.test(password),
/\d/.test(password),
/[!@#$%^&*]/.test(password)
];
3. Calculate the Score
Filtering the array for truthy values gives the number of requirements that passed.
return checks.filter(Boolean).length;
4. Convert the Score into Feedback
The score determines the label, meter width, and CSS class. A score of 4 is required for Strong so the displayed rating remains consistent with the challenge requirements.
5. Handle an Empty Password
An empty field should reset the meter instead of displaying Weak. This gives users a cleaner initial state.
6. Keep the Feedback Accessible
The visual meter is decorative, while the text element uses aria-live="polite" so compatible screen readers can announce changes without interrupting the user.
Final Solution
const passwordInput = document.getElementById('password');
const strengthBar = document.getElementById('strengthBar');
const strengthText = document.getElementById('strengthText');
function evaluatePassword(password) {
const checks = [
password.length >= 8,
/[a-z]/.test(password) && /[A-Z]/.test(password),
/\d/.test(password),
/[!@#$%^&*]/.test(password)
];
return checks.filter(Boolean).length;
}
function updateStrength(password, score) {
if (password.length === 0) {
strengthBar.style.width = '0%';
strengthBar.className = 'strength-bar';
strengthText.textContent = 'Strength: Not rated';
return;
}
let strength = 'Weak';
let className = 'strength-weak';
if (score === 4) {
strength = 'Strong';
className = 'strength-strong';
} else if (score >= 2) {
strength = 'Medium';
className = 'strength-medium';
}
const percent = score * 25;
strengthBar.style.width = `${percent}%`;
strengthBar.className = `strength-bar ${className}`;
strengthText.textContent = `Strength: ${strength}`;
}
passwordInput.addEventListener('input', () => {
const password = passwordInput.value;
const score = evaluatePassword(password);
updateStrength(password, score);
});
How the Final Solution Works
- The user types a password.
- The
inputevent fires. evaluatePassword()checks the four requirements.- The number of successful checks becomes the score.
updateStrength()converts the score into a label, CSS class, and percentage.- The DOM updates immediately with the new password-strength feedback.
Stretch Goals
- Display a checklist showing exactly which requirements are currently satisfied.
- Add a Show Password button while preserving keyboard accessibility.
- Detect common passwords such as
passwordor12345678. - Add additional strength points for passwords longer than 12 or 16 characters.
- Move the JavaScript into a separate
password-strength.jsfile. - Write unit tests for the password evaluation function.
- Turn the checker into a reusable JavaScript component.
What You Practiced
- Listening for real-time user input with JavaScript.
- Using regular expressions for simple string validation.
- Breaking validation logic into reusable functions.
- Updating DOM elements and CSS classes dynamically.
- Providing accessible status feedback with
aria-live.