Password Strength Meter — Free HTML CSS JS Snippet
Password Strength Meter · Forms · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<div class="demo">
<h3>Create password</h3>
<div class="field">
<div class="input-wrap">
<input type="password" id="pwd" placeholder="Enter a password…" oninput="check(this.value)" autocomplete="new-password" />
<button class="eye" onclick="toggleEye(this)" type="button">
<svg id="eye-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
</button>
</div>
<div class="bars">
<div class="bar" id="b1"></div>
<div class="bar" id="b2"></div>
<div class="bar" id="b3"></div>
<div class="bar" id="b4"></div>
</div>
<div class="strength-label" id="label">Enter a password</div>
</div>
<ul class="rules" id="rules">
<li id="r-len">At least 8 characters</li>
<li id="r-upper">Uppercase letter (A–Z)</li>
<li id="r-num">Number (0–9)</li>
<li id="r-sym">Special character (!@#$…)</li>
</ul>
</div>* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #f8fafc; display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 20px; }
.demo { background: #fff; border-radius: 16px; padding: 28px 24px; width: 320px; box-shadow: 0 4px 20px rgba(0,0,0,0.07); display: flex; flex-direction: column; gap: 16px; }
h3 { font-size: 16px; font-weight: 700; color: #1e293b; }
.field { display: flex; flex-direction: column; gap: 8px; }
.input-wrap { position: relative; }
.input-wrap input { width: 100%; padding: 10px 40px 10px 14px; font-size: 14px; font-family: inherit; border: 1.5px solid #e2e8f0; border-radius: 8px; outline: none; color: #1e293b; transition: border-color 0.15s; }
.input-wrap input:focus { border-color: #6366f1; }
.eye { position: absolute; right: 10px; top: 50%; transform: translateY(-50%); background: none; border: none; cursor: pointer; color: #94a3b8; padding: 4px; }
.bars { display: flex; gap: 4px; }
.bar { flex: 1; height: 4px; background: #e2e8f0; border-radius: 4px; transition: background 0.25s; }
.strength-label { font-size: 12px; font-weight: 600; color: #94a3b8; }
.rules { list-style: none; display: flex; flex-direction: column; gap: 5px; }
.rules li { font-size: 12px; color: #94a3b8; display: flex; align-items: center; gap: 6px; transition: color 0.2s; }
.rules li::before { content: '○'; font-size: 10px; }
.rules li.pass { color: #16a34a; }
.rules li.pass::before { content: '●'; color: #16a34a; }function check(v) {
const len = v.length >= 8;
const upper = /[A-Z]/.test(v);
const num = /[0-9]/.test(v);
const sym = /[^A-Za-z0-9]/.test(v);
const score = [len, upper, num, sym].filter(Boolean).length;
const colors = ['', '#ef4444', '#f59e0b', '#6366f1', '#16a34a'];
const labels = ['', 'Weak', 'Fair', 'Good', 'Strong'];
for (let i = 1; i <= 4; i++) {
document.getElementById('b'+i).style.background = i <= score ? colors[score] : '#e2e8f0';
}
document.getElementById('label').textContent = v ? labels[score] : 'Enter a password';
document.getElementById('label').style.color = v ? colors[score] : '#94a3b8';
[['r-len',len],['r-upper',upper],['r-num',num],['r-sym',sym]].forEach(([id,pass]) => {
document.getElementById(id).classList.toggle('pass', pass);
});
}
function toggleEye(btn) {
const inp = document.getElementById('pwd');
const isText = inp.type === 'text';
inp.type = isText ? 'password' : 'text';
document.getElementById('eye-icon').innerHTML = isText
? '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>'
: '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>';
}Extend with AI
Take This Snippet Further With AI
The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.
What's included
Features
About this UI Snippet
Password Strength Meter — Regex Score, Coloured Bars & Rules Checklist

A password strength meter gives users real-time feedback as they type a password on a sign-up form or auth login card — showing which rules are met and visually indicating overall strength. Pair it with a show/hide toggle and a password generator. It reduces weak password submissions and improves security without blocking the user flow.
The four-rule scoring
check(v) tests four conditions: v.length >= 8, /[A-Z]/.test(v) (uppercase), /[0-9]/.test(v) (digit), /[^A-Za-z0-9]/.test(v) (symbol). Each boolean is collected into [len, upper, num, sym] and .filter(Boolean).length counts the passing rules — giving a score of 0–4.
The strength bar
Four coloured bars correspond to the score. document.querySelectorAll('.bar') fills bars up to the score index with the appropriate colour from the colors array: empty → red → amber → indigo → green. Bars above the score stay grey.
The rules checklist
Four rule rows show a ✓ or ✗ indicator that updates on every keystroke. Setting row.classList.toggle('ok', condition) applies a green tick CSS state when the condition is true.
Show/hide password toggle
The eye button calls toggleVis() which switches the input type between password and text and updates the icon SVG.
The four regex rules
The strength meter evaluates four independent criteria: (1) length >= 8 characters, (2) at least one uppercase letter (/[A-Z]/), (3) at least one digit (/[0-9]/), (4) at least one special character (/[^A-Za-z0-9]/). Each test returns a boolean. The score is simply the count of passing tests: 0 (empty), 1 (weak), 2 (fair), 3 (good), 4 (strong). This evaluation runs on every input event with no debounce — password fields are short enough that real-time feedback is performant.
Colour and label mapping
Each score maps to a colour and label: 0→grey/empty, 1→red/Weak, 2→orange/Fair, 3→yellow/Good, 4→green/Strong. The bar uses four segment elements that fill progressively. The label updates simultaneously so users understand the colour meaning at a glance without having to interpret the bar alone.
Show/hide password toggle
The eye icon button toggles the input type between "password" and "text". This uses input.type = value directly — the input value is preserved across type changes. The icon switches between an open eye (visible text) and a closed eye (hidden text).
Customising the strength rules
Add more regex rules for stricter requirements: no consecutive characters (/(..)/), minimum unique characters, or no dictionary words. Each additional rule increases the maximum score — update the bar segment count and the score-to-label mapping accordingly. For very strict requirements (passphrase style), adjust the minimum length threshold from 8 to 16 and add a 'Very Strong' fifth tier at the maximum score.
Step by step
How to Use
- 1Type a passwordType in the password field to see the strength bars fill and the rules checklist update in real time.
- 2Click the eye iconClick the eye button to toggle between hidden and visible password text.
- 3Add or change rulesIn the JS panel, add new regex checks to the conditions and add matching rule rows to the HTML.
- 4Change the strength coloursUpdate the colors array in the JS panel and matching bar CSS rules.
- 5Block form submission on weak passwordsRead the score variable before form submit: if (score < 3) return prevent the submit.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for a React component, or "Tailwind" for a React + Tailwind version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Four boolean conditions are evaluated: length >= 8, /[A-Z]/.test(v), /[0-9]/.test(v), /[^A-Za-z0-9]/.test(v). All four are put in an array and .filter(Boolean).length counts how many are true — giving 0, 1, 2, 3, or 4.
Four .bar elements are queried. Each bar at index i gets the colour from colors[score] if i < score, or an empty/grey state if i >= score. The colors array provides semantic colours per score level.
Add a new regex condition to the conditions array: e.g. const noSpaces = !/\s/.test(v). Add it to the array, increment the checklist rows in the HTML, and handle the new bar state. Update the colors array if you want a 5-level scale.
Read the score variable in the form's onsubmit handler: document.querySelector("form").addEventListener("submit", e => { if (score < 3) { e.preventDefault(); alert("Password too weak"); } });
toggleVis() accesses the password input element and switches input.type between "password" (characters hidden) and "text" (characters visible). The eye icon SVG is also updated to an open or closed eye.
Yes. Click "JSX" for a React component. In React, track the password value in useState. Call the check function in an onChange handler. Store score, rules, and visible as state variables and derive bar colours and rule states from them.