About this snippet

Help users pick strong passwords visually. We update an SVG progress ring in real-time, but the interface stays clean and out of the way until they start typing.

Size
3.5 KB
Uses
HTML, CSS, JavaScript
Loads
Nothing external
Views
150
<div class="password-group">
  <label for="pwd-input">Create Password</label>
  <div class="input-wrapper">
    <input type="password" id="pwd-input" placeholder="Enter a strong password">
    <div class="strength-ring">
      <svg viewBox="0 0 36 36" width="24" height="24">
        <path class="ring-bg" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="#e5e7eb" stroke-width="4" />
        <path class="ring-progress" id="ring-progress" d="M18 2.0845 a 15.9155 15.9155 0 0 1 0 31.831 a 15.9155 15.9155 0 0 1 0 -31.831" fill="none" stroke="#ef4444" stroke-width="4" stroke-dasharray="100, 100" stroke-dashoffset="100" />
      </svg>
    </div>
  </div>
  <p class="hint">Use at least 8 characters, numbers, and symbols.</p>
</div>
*, *::before, *::after {
  box-sizing: border-box;
}

body {
  font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
  background: #f9fafb;
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
  margin: 0;
  padding: 20px;
}

.password-group {
  background: #ffffff;
  padding: 30px;
  border-radius: 16px;
  box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
  width: 100%;
  max-width: 400px;
  border: 1px solid #f3f4f6;
}

label {
  display: block;
  margin-bottom: 8px;
  font-weight: 500;
  color: #374151;
}

.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}

#pwd-input {
  width: 100%;
  padding: 12px 48px 12px 16px;
  border: 1px solid #d1d5db;
  border-radius: 8px;
  outline: none;
  transition: border-color 0.2s;
  font-size: 1rem;
  color: #111827;
}

#pwd-input:focus {
  border-color: #3b82f6;
}

.strength-ring {
  position: absolute;
  right: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}

.ring-progress {
  transition: stroke-dashoffset 0.4s ease, stroke 0.4s ease;
}

.hint {
  font-size: 0.875rem;
  color: #6b7280;
  margin-top: 12px;
  margin-bottom: 0;
}
const input = document.getElementById("pwd-input");
const ring = document.getElementById("ring-progress");

input.addEventListener("input", () => {
  const val = input.value;
  let score = 0;
  
  // 1. Point for length
  if (val.length > 7) {
    score++;
  }

  let hasUpper = false;
  let hasNumber = false;
  let hasSpecial = false;

  // 2. Loop through and look at every single character using charAt()
  for (let i = 0; i < val.length; i++) {
    const char = val.charAt(i);
    
    if (char >= 'A' && char <= 'Z') {
      hasUpper = true;
    } else if (char >= '0' && char <= '9') {
      hasNumber = true;
    } else if (char >= 'a' && char <= 'z') {
      // It is a lowercase letter, so we just continue
    } else {
      // If it is not uppercase, not a number, and not lowercase, it must be a special character
      hasSpecial = true;
    }
  }

  // 3. Add points based on what we found
  if (hasUpper) score++;
  if (hasNumber) score++;
  if (hasSpecial) score++;

  // 4. Update the visual ring
  let offset = 100;
  let color = "#ef4444"; 

  if (score === 1) { 
    offset = 75; 
    color = "#ef4444"; 
  } else if (score === 2) { 
    offset = 50; 
    color = "#f59e0b"; 
  } else if (score === 3) { 
    offset = 25; 
    color = "#3b82f6"; 
  } else if (score >= 4) { 
    offset = 0; 
    color = "#10b981"; // Green!
  } 

  // Reset if input is empty
  if (val.length === 0) {
    offset = 100;
  }

  ring.style.strokeDashoffset = offset;
  ring.style.stroke = color;
});
Esc
↑↓ moveEnter select

Start from a template

Open an .html file, or HTML, CSS, JS, Markdown, Less or TypeScript files. You can also drop them here. Styles and scripts go into their panes.

Share

Source

Keyboard shortcuts

Save