DocsHub
JavascriptIntermediate

Password Validator

Build a password validator that checks password strength and shows which rules pass or fail in real time.

Password Validator

Problem

Build a password validator where the user types a password and the app shows in real time which rules pass and which fail. A strength indicator updates as more rules are met.

Input: "abc"
Rules:
❌ At least 8 characters
❌ At least one uppercase letter
✅ At least one lowercase letter
❌ At least one number
❌ At least one special character (!@#$%^&*)
Strength: Weak

Input: "Password1"
Rules:
✅ At least 8 characters
✅ At least one uppercase letter
✅ At least one lowercase letter
✅ At least one number
❌ At least one special character
Strength: Good

Input: "Password1!"
Rules:
✅ At least 8 characters
✅ At least one uppercase letter
✅ At least one lowercase letter
✅ At least one number
✅ At least one special character
Strength: Strong

Logic

  1. Select the password input and all rule elements
  2. Listen for the input event on the password field
  3. For each rule — test the password against a regex pattern
  4. Mark each rule as passed or failed
  5. Count how many rules pass
  6. Update the strength indicator based on the count
  7. Update the strength bar width and color

Flow

0 to 1 2 to 3 4 5 User types password input event fires Test each rule with regex Mark rules pass or fail Count passed rules How many pass? Strength: Weak Strength: Fair Strength: Good Strength: Strong Update bar and label

HTML Structure

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Password Validator</title>
    <style>
      body {
        font-family: sans-serif;
        max-width: 440px;
        margin: 60px auto;
        padding: 0 20px;
      }

      /* password input wrapper — for show/hide toggle */
      .input-wrapper {
        position: relative;
        margin-bottom: 20px;
      }

      input[type="password"],
      input[type="text"] {
        width: 100%;
        padding: 12px 44px 12px 12px;
        font-size: 1rem;
        border: 2px solid #ccc;
        border-radius: 8px;
        box-sizing: border-box;
        outline: none;
      }

      input:focus {
        border-color: #555;
      }

      /* show/hide password button */
      #toggle-btn {
        position: absolute;
        right: 12px;
        top: 50%;
        transform: translateY(-50%);
        background: none;
        border: none;
        cursor: pointer;
        font-size: 0.85rem;
        color: #555;
      }

      /* strength bar container */
      .strength-bar-container {
        height: 6px;
        background: #e0e0e0;
        border-radius: 4px;
        margin-bottom: 8px;
        overflow: hidden;
      }

      /* the fill part of the bar */
      #strength-bar {
        height: 100%;
        width: 0%;
        border-radius: 4px;
        transition: width 0.3s ease, background 0.3s ease;
      }

      /* strength label */
      #strength-label {
        font-size: 0.85rem;
        font-weight: 600;
        margin-bottom: 16px;
        color: #888;
      }

      /* rules list */
      .rules {
        list-style: none;
        padding: 0;
        margin: 0;
      }

      .rules li {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 7px 0;
        font-size: 0.9rem;
        color: #888;
        border-bottom: 1px solid #f0f0f0;
        transition: color 0.2s;
      }

      .rules li:last-child {
        border-bottom: none;
      }

      /* icon shown before each rule */
      .rules li .icon {
        font-size: 1rem;
        width: 20px;
        text-align: center;
      }

      /* passed rule — green */
      .rules li.passed {
        color: #1a7a3f;
      }

      /* failed rule — default grey */
      .rules li.failed {
        color: #aaa;
      }
    </style>
  </head>
  <body>
    <h1>Password Validator</h1>

    <!-- password input with show/hide toggle -->
    <div class="input-wrapper">
      <input type="password" id="password-input" placeholder="Enter password..." />
      <button id="toggle-btn">Show</button>
    </div>

    <!-- strength bar -->
    <div class="strength-bar-container">
      <div id="strength-bar"></div>
    </div>

    <!-- strength label -->
    <div id="strength-label">Enter a password</div>

    <!-- rules list — each li has a data-rule attribute matching the rules object -->
    <ul class="rules">
      <li data-rule="minLength">
        <span class="icon">○</span>
        At least 8 characters
      </li>
      <li data-rule="uppercase">
        <span class="icon">○</span>
        At least one uppercase letter
      </li>
      <li data-rule="lowercase">
        <span class="icon">○</span>
        At least one lowercase letter
      </li>
      <li data-rule="number">
        <span class="icon">○</span>
        At least one number
      </li>
      <li data-rule="special">
        <span class="icon">○</span>
        At least one special character (!@#$%^&*)
      </li>
    </ul>

    <script src="script.js"></script>
  </body>
</html>

Solution

// Step 1 — select elements
const passwordInput = document.querySelector("#password-input");
const toggleBtn = document.querySelector("#toggle-btn");
const strengthBar = document.querySelector("#strength-bar");
const strengthLabel = document.querySelector("#strength-label");

// Step 2 — define the rules
// each rule has a name, a regex to test against, and a label
const rules = {
  minLength: {
    regex: /.{8,}/,          // 8 or more characters
    label: "At least 8 characters"
  },
  uppercase: {
    regex: /[A-Z]/,           // at least one uppercase letter
    label: "At least one uppercase letter"
  },
  lowercase: {
    regex: /[a-z]/,           // at least one lowercase letter
    label: "At least one lowercase letter"
  },
  number: {
    regex: /[0-9]/,           // at least one digit
    label: "At least one number"
  },
  special: {
    regex: /[!@#$%^&*]/,     // at least one special character
    label: "At least one special character"
  }
};

// Step 3 — define strength levels
// each level has a label, color for the bar, and width percentage
const strengthLevels = [
  { label: "",        color: "#e0e0e0", width: "0%"   }, // 0 rules
  { label: "Weak",    color: "#e74c3c", width: "20%"  }, // 1 rule
  { label: "Weak",    color: "#e74c3c", width: "40%"  }, // 2 rules
  { label: "Fair",    color: "#f39c12", width: "60%"  }, // 3 rules
  { label: "Good",    color: "#3498db", width: "80%"  }, // 4 rules
  { label: "Strong",  color: "#1a7a3f", width: "100%" }  // 5 rules
];

// Step 4 — listen for input event
passwordInput.addEventListener("input", validatePassword);

function validatePassword() {
  const password = passwordInput.value;

  // Step 5 — test each rule and count how many pass
  let passedCount = 0;

  for (const [ruleName, rule] of Object.entries(rules)) {
    // test the password against this rule's regex
    const passed = rule.regex.test(password);

    if (passed) passedCount++;

    // Step 6 — find the matching li element using data-rule attribute
    const ruleElement = document.querySelector(`[data-rule="${ruleName}"]`);
    const icon = ruleElement.querySelector(".icon");

    // update the class and icon based on pass/fail
    if (passed) {
      ruleElement.classList.add("passed");
      ruleElement.classList.remove("failed");
      icon.textContent = "✅";
    } else {
      ruleElement.classList.add("failed");
      ruleElement.classList.remove("passed");
      icon.textContent = "○";
    }
  }

  // Step 7 — update the strength bar and label
  const level = strengthLevels[passedCount];
  strengthBar.style.width = level.width;
  strengthBar.style.background = level.color;
  strengthLabel.textContent = password.length === 0
    ? "Enter a password"
    : level.label || "Weak";
  strengthLabel.style.color = level.color;
}

// Step 8 — show/hide password toggle
toggleBtn.addEventListener("click", () => {
  const isPassword = passwordInput.type === "password";
  passwordInput.type = isPassword ? "text" : "password";
  toggleBtn.textContent = isPassword ? "Hide" : "Show";
});

Code Execution

Trace through typing "Password1!":

RuleRegexTestResult
minLength/.{8,}/"Password1!".length >= 8✅ pass
uppercase/[A-Z]/contains P✅ pass
lowercase/[a-z]/contains assword✅ pass
number/[0-9]/contains 1✅ pass
special/[!@#$%^&*]/contains !✅ pass
Passed count5Strength: Strong
Barwidth 100%, color #1a7a3fgreen full bar

Trace through typing "abc":

RuleRegexTestResult
minLength/.{8,}/"abc".length < 8❌ fail
uppercase/[A-Z]/no uppercase❌ fail
lowercase/[a-z]/contains abc✅ pass
number/[0-9]/no number❌ fail
special/[!@#$%^&*]/no special❌ fail
Passed count1Strength: Weak
Barwidth 20%, color #e74c3cred short bar

Output

Type "abc"         → 1/5 rules pass  — Weak    (red bar 20%)
Type "Password1"   → 4/5 rules pass  — Good    (blue bar 80%)
Type "Password1!"  → 5/5 rules pass  — Strong  (green bar 100%)
Empty input        → "Enter a password"

On this page