What a strength bar should say
Type a password, or press one of the classics. The number beside it is what a bar that counts capitals and symbols would have told you.
<div class="demo demo--wide">
<label class="demo-hint" for="email">Their email, so the meter can spot it in there</label>
<input class="demo-input" id="email" value="ahmed@example.com">
<label class="demo-hint" for="password">Password</label>
<input class="demo-input" id="password" type="text" autocomplete="off" placeholder="Try typing one">
<div id="meter"></div>
<div class="demo-row">
<button class="demo-btn demo-btn--ghost" data-try="P@ssw0rd1">P@ssw0rd1</button>
<button class="demo-btn demo-btn--ghost" data-try="correct horse battery staple">correct horse battery staple</button>
<button class="demo-btn demo-btn--ghost" data-try="ضصثقفغعه">ضصثقفغعه</button>
<button class="demo-btn demo-btn--ghost" data-try="ahmed1990!">ahmed1990!</button>
</div>
<div class="demo-row">
<div class="demo-seg" id="locale" role="group" aria-label="Language">
<button type="button" data-locale="en" aria-pressed="true">English</button>
<button type="button" data-locale="ar">العربية</button>
<button type="button" data-locale="ur">اردو</button>
</div>
</div>
<dl class="demo-kv" id="out"></dl>
<p class="demo-hint"><strong>P@ssw0rd1</strong> has a capital, a digit, a symbol and nine
characters — full marks on every bar that counts those, and it is in every wordlist.</p>
</div>
import { createStrengthMeter } from 'https://devix.pk/cdn/oss/password-strength@1.0.0/index.js';
const field = document.getElementById('password');
const email = document.getElementById('email');
const out = document.getElementById('out');
let locale = 'en';
let meter;
function build() {
meter?.destroy();
meter = createStrengthMeter(field, {
container: document.getElementById('meter'),
locale,
userInputs: [email.value],
showTime: true,
debounce: 60,
onChange: (result) => show(result),
});
}
// What a bar that counts character classes would have said — the comparison is
// the point of the demo.
function theatreScore(password) {
if (!password) return 0;
let score = [/[a-z]/, /[A-Z]/, /\d/, /[^A-Za-z0-9]/].filter((test) => test.test(password)).length;
if (password.length >= 8) score += 1;
return Math.min(4, score);
}
function show(result) {
const password = field.value;
out.innerHTML = `
<div><dt>this meter</dt><dd>${password ? `${result.score} of 4` : '—'}</dd></div>
<div><dt>a class-counting bar</dt><dd>${password ? `${theatreScore(password)} of 4` : '—'}</dd></div>
<div><dt>why</dt><dd>${result.warning ?? '—'}</dd></div>
<div><dt>offline crack time</dt><dd>${password ? result.crackTimeOffline : '—'}</dd></div>`;
}
for (const button of document.querySelectorAll('[data-try]')) {
button.addEventListener('click', () => {
field.value = button.dataset.try;
field.dispatchEvent(new Event('input', { bubbles: true }));
field.focus();
});
}
email.addEventListener('input', () => meter.setUserInputs([email.value]));
document.getElementById('locale').addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
for (const other of event.currentTarget.querySelectorAll('button')) other.setAttribute('aria-pressed', String(other === button));
locale = button.dataset.locale;
build();
});
build();
@import url('https://devix.pk/cdn/oss/password-strength@1.0.0/password-strength.min.css');
#password, #email { width: 100%; }
.demo-btn { font-size: 12px; }