A strong password is one an attacker cannot guess within a sensible number of tries. Length matters most, then avoiding common passwords, words, keyboard runs and dates. Type a password below for an offline estimate of guesses and crack time, then copy a ready strength meter with a show password toggle for your own signup form.
| Rule | NIST SP 800-63B |
|---|---|
| Minimum length | 15 characters when the password is the only factor; 8 when used with another factor |
| Maximum length | Allow at least 64 characters |
| Composition rules (must include a symbol...) | Do not impose them |
| Forced periodic changes | Do not require them; force a change only after a compromise |
| Blocklist | Reject common, expected or breached passwords |
| Paste and password managers | Allow them |
Updated
The checker splits your password into the pieces an attacker would try first and multiplies the guesses each piece needs. Nothing you type leaves this page. Below it are two strength meters you can paste into a signup form, one for React with Tailwind and one in plain JavaScript.
A controlled password field with a show and hide button, a four-step bar, a rules checklist and a live text label for screen readers.
import { useId, useState } from "react";
const COMMON = ["password", "123456", "12345678", "qwerty", "111111", "letmein", "iloveyou"];
function score(pw) {
if (!pw) return 0;
if (COMMON.includes(pw.toLowerCase())) return 0;
let s = 0;
if (pw.length >= 8) s++;
if (pw.length >= 12) s++;
if (pw.length >= 15) s++;
if (/[a-z]/.test(pw) && /[A-Z0-9]/.test(pw) && /[^a-zA-Z0-9]/.test(pw)) s++;
if (/(.)\1{2,}|0123|1234|abcd|qwer/i.test(pw)) s = Math.max(0, s - 1);
return Math.min(4, s);
}
const LABELS = ["Too weak", "Weak", "Fair", "Good", "Strong"];
const COLORS = ["bg-red-500", "bg-red-500", "bg-amber-500", "bg-lime-500", "bg-green-600"];
export function PasswordField({ minLength = 15 }) {
const id = useId();
const [pw, setPw] = useState("");
const [show, setShow] = useState(false);
const s = score(pw);
return (
<div className="max-w-sm space-y-2">
<label htmlFor={id} className="block text-sm font-medium">Password</label>
<div className="flex rounded-lg border border-gray-300 focus-within:ring-2 focus-within:ring-blue-500">
<input
id={id}
type={show ? "text" : "password"}
autoComplete="new-password"
minLength={minLength}
maxLength={128}
value={pw}
onChange={(e) => setPw(e.target.value)}
aria-describedby={`${id}-hint ${id}-strength`}
className="w-full rounded-l-lg px-3 py-2 outline-none"
/>
<button
type="button"
onClick={() => setShow(!show)}
aria-pressed={show}
className="px-3 text-sm text-gray-600"
>
{show ? "Hide" : "Show"}
</button>
</div>
<div className="flex gap-1" aria-hidden="true">
{[0, 1, 2, 3].map((i) => (
<div key={i} className={`h-1.5 flex-1 rounded ${i < s ? COLORS[s] : "bg-gray-200"}`} />
))}
</div>
<p id={`${id}-strength`} aria-live="polite" className="text-sm">
{pw ? `Strength: ${LABELS[s]}` : ""}
</p>
<p id={`${id}-hint`} className="text-xs text-gray-500">
Use at least {minLength} characters. A few random words works well.
</p>
</div>
);
}The same idea with no framework. Paste it into any page; the script only touches elements inside the wrapper.
<div class="pw">
<label for="pw">Password</label>
<div class="pw-row">
<input id="pw" type="password" autocomplete="new-password" minlength="15" aria-describedby="pw-msg">
<button type="button" id="pw-toggle" aria-pressed="false">Show</button>
</div>
<meter id="pw-meter" min="0" max="4" low="2" high="3" optimum="4" value="0"></meter>
<p id="pw-msg" aria-live="polite"></p>
</div>
<style>
.pw { font: 15px system-ui, sans-serif; max-width: 320px; }
.pw-row { display: flex; gap: 6px; margin: 4px 0 8px; }
.pw input { flex: 1; padding: 8px; border: 1px solid #ccc; border-radius: 8px; }
.pw button { padding: 0 12px; border-radius: 8px; border: 1px solid #ccc; background: #fff; }
.pw meter { width: 100%; height: 10px; }
</style>
<script>
(function () {
var input = document.getElementById("pw");
var toggle = document.getElementById("pw-toggle");
var meter = document.getElementById("pw-meter");
var msg = document.getElementById("pw-msg");
var labels = ["Too weak", "Weak", "Fair", "Good", "Strong"];
function score(pw) {
var s = 0;
if (pw.length >= 8) s++;
if (pw.length >= 12) s++;
if (pw.length >= 15) s++;
if (/[a-z]/.test(pw) && /[^a-z]/.test(pw)) s++;
if (/(.)\1{2,}|1234|qwer|password/i.test(pw)) s = Math.max(0, s - 2);
return Math.min(4, s);
}
input.addEventListener("input", function () {
var s = score(input.value);
meter.value = s;
msg.textContent = input.value ? "Strength: " + labels[s] : "";
});
toggle.addEventListener("click", function () {
var showing = input.type === "text";
input.type = showing ? "password" : "text";
toggle.textContent = showing ? "Show" : "Hide";
toggle.setAttribute("aria-pressed", String(!showing));
});
})();
</script>
Each extra character multiplies the number of possible passwords. Adding one random lowercase letter multiplies it by 26, while swapping an a for @ in a word adds almost nothing, because attackers apply those swaps automatically.
That is why the estimate rewards long passphrases. Four unrelated words can reach the strongest band while staying easy to type, as long as they are not a famous phrase or song lyric.
A good meter gives feedback that matches the server's rules exactly. If the meter says strong and the server then rejects the password, people stop trusting both. Keep the rules in one place and show the same messages in each.
Announce changes politely with aria-live so screen reader users hear the result without losing their place, and never rely on colour alone: pair the bar with a text label such as Weak or Strong.
The check runs entirely in your browser and the page makes no network request with what you type. Even so, the safest habit is to test a password with the same shape as your real one, not the real one.
It is an estimate. The checker uses short built-in lists of common passwords and words, so a password built from a less common word can score higher here than it deserves. The four scenarios assume typical attack speeds, from a rate-limited login form to a stolen database with a fast hash. Real attackers also use leaked password lists and rules that are far larger than anything a web page can ship.
Current NIST guidance says no. Composition rules push people toward predictable patterns like Password1!, which pass the rule and still fall to guessing. A length minimum plus a check against common and breached passwords does more for security.
Masked fields cause typos, especially on phones, and typos lead to lockouts and password resets. A toggle lets people check what they typed. Use a real button with a clear label and keep the field type switching between password and text.
No. The meters score length, variety and a few obvious patterns in the browser so people get quick feedback. The real gate should be on your server: enforce the minimum length and reject passwords found in breach lists there.
Related: API key generator, Hash generator, Password reset email template, How to add a contact form, HTML accessibility checker.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.