More Forms Snippets
Password Generator — Free HTML CSS JS Snippet
Password Generator · Forms · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Password Generator — Cryptographic Randomness, Strength Meter, Options & Copy History

Ask a hundred people to "type a random password" and you'll get a hundred passwords shaped by human habit — favourite numbers, keyboard patterns, a capital letter only at the start. Computers are much better at *actually* random, which is the entire reason password generators exist: they remove the human from the one step where humans are predictably bad. This snippet builds a complete one — cryptographically secure generation, an 8–32 character length slider, checkboxes for each character class plus an "exclude look-alike characters" option, a live strength meter, one-click clipboard copy, and a five-item history so a regenerated password isn't lost forever.
Why `crypto.getRandomValues()` and not `Math.random()`
This is the one decision in the whole snippet that actually matters for security, so it's worth understanding precisely *why*. Math.random() is a pseudo-random number generator — deterministic math seeded from an internal state, which means that given enough observed outputs, an attacker can reconstruct the seed and predict every value that comes next. That's a frightening property for something protecting an account. crypto.getRandomValues(new Uint32Array(length)) instead draws from the operating system's entropy pool — noise gathered from hardware events like disk timing and interrupt jitter — producing numbers that are genuinely unpredictable, not just statistically scattered. Each 32-bit integer is then mapped onto the chosen character set with charset[n % charset.length], a modulo operation that wraps a huge number down into a small alphabet while preserving its randomness.
Scoring strength as a sum of small truths
Rather than a single opaque "strength score," the meter adds up six independent yes/no checks — is it at least 12 characters? At least 16? Does it contain an uppercase letter, a lowercase letter, a digit, a symbol? Each "yes" contributes one point out of six, the total becomes a percentage, and that percentage drives both the fill width and colour of .strength-fill through four bands: Weak (red), Fair (amber), Good (green), Strong (indigo). Building the meter from named, inspectable conditions rather than a black-box formula means anyone reading the code — or extending it — can see *exactly* what separates a "Fair" password from a "Strong" one, the same transparency the Password Strength Meter snippet applies to user-typed input.
A `Set` that filters out the characters people mistype
The digits 0 and 1, the letters O, I, and l, and a handful of others look nearly identical in many fonts — exactly the characters someone squints at when copying a password by hand onto a sticky note or a phone keyboard. The "Exclude similar" option collects them into a Set (for constant-time .has() lookups) and, when checked, filters the active character set with [...charset].filter(c => !AMBIG.has(c)). It's a small accessibility courtesy that trades a sliver of entropy for a meaningfully lower chance of a frustrated retry-and-lockout cycle.
A five-item history that survives "oops, I meant the last one"
Every freshly generated password is unshifted onto the front of a history array, then the array is trimmed to five with .pop() — the same newest-first, fixed-length pattern used by the Emoji Picker's recent tab. It solves a real annoyance: clicking "Generate" one too many times no longer means the good password is gone forever, since each entry in the list carries its own copy button.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You don't have to work out the entropy math in your head. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain precisely why crypto.getRandomValues feeding a Uint32Array is safe for password generation while Math.random is not, and how the modulo mapping charset[n % charset.length] can introduce a small bias when the charset length doesn't evenly divide the integer range. The same assistant can help optimize it, for example checking whether the ambiguous-character Set lookup is the cheapest way to filter the charset on every regenerate, or whether the six-point strength scoring should weight character-class diversity more heavily than raw length. It's also useful for extending the effect: ask it to add a passphrase mode built from a wordlist, a pattern-based mode for PINs or invite codes, or a strength check against a breached-password list. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a password generator in plain HTML, CSS, and vanilla JavaScript that uses only the Web Crypto API for randomness — never Math.random — plus a live strength meter and a short history list.
Requirements:
- Character-class checkboxes for uppercase, lowercase, numbers, and symbols, plus an "exclude similar characters" checkbox that filters out visually ambiguous characters like 0, O, 1, I, l, B, 8 from whichever charset is active.
- A length slider (roughly 8 to 32 characters) whose value is displayed live and, if a password already exists, triggers an automatic regeneration when moved.
- Generate the password by filling a Uint32Array of the chosen length with crypto.getRandomValues, then mapping each random integer to a character via modulo against the active charset's length — do not use Math.random anywhere in the generation path.
- Compute a strength score out of six independent boolean checks (length at least 12, length at least 16, contains uppercase, contains lowercase, contains a digit, contains a symbol), convert it to a percentage, and drive both the fill width and the color of a strength bar plus a text label (Weak/Fair/Good/Strong) from that percentage.
- A copy-to-clipboard button using the async Clipboard API with a textarea-based execCommand fallback for browsers that lack it, giving visual "Copied!" confirmation that reverts after about two seconds.
- Maintain a rolling history of the 5 most recently generated passwords (newest first, oldest dropped) each with its own copy button, and a control to clear the history entirely.Step by step
How to Use
- 1Click "Generate password" to create a random passwordA cryptographically random password appears in the monospace output field. The strength meter updates immediately. The password is added to the recent history list below.
- 2Adjust the length slider and checkboxesMove the slider between 8 and 32 characters. Check or uncheck uppercase, lowercase, numbers, symbols, and exclude-similar. Each checkbox change regenerates the current password automatically.
- 3Click Copy to copy to clipboardThe Copy button copies the displayed password. It turns green and shows "Copied!" for 2 seconds. Each history item also has its own copy button.
- 4Use the history to recover a previous passwordThe 5 most recent passwords appear below the generator. Click any copy button to copy a previous password. Clear all history with the Clear button.
- 5Use for a registration form default passwordCall generate() on page load to pre-fill a suggested password in a registration form. Wire the generated value to a hidden input that submits with the form.
- 6Export in your formatClick "HTML" for a standalone page, "JSX" for a React component with useState for password and options, or "Tailwind" for a Tailwind CSS version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Math.random() uses a deterministic pseudo-random number generator (PRNG) — given the initial seed value, an attacker who observes several outputs can predict future values. crypto.getRandomValues() reads from the operating system entropy pool, which gathers entropy from hardware events (disk timing, network packet timing, mouse movement). This makes the output genuinely unpredictable and safe for cryptographic use. Always use crypto.getRandomValues() for passwords, tokens, keys, and any security-sensitive random generation.
crypto.getRandomValues(new Uint32Array(length)) fills an array with random 32-bit unsigned integers (0 to 4,294,967,295). Each integer is mapped to a character via charset[n % charset.length]. Modulo is used because it wraps the large integer into the charset range. The distribution is not perfectly uniform (there is a slight bias if 4,294,967,295 is not divisible by charset.length), but for practical password lengths and charsets, the bias is negligible — less than 0.000001%.
Add an input for the password: <input type="password" id="pw-field">. After generating: document.getElementById("pw-field").value = currentPw. Fire an input event so any listeners (React, validators) see the change: field.dispatchEvent(new Event("input", { bubbles: true })). If using a confirm-password field, set both fields to the same value. The user can then edit the suggested password or accept it as-is.
Save the options (length, character set checkboxes) to localStorage: function saveOptions() { localStorage.setItem("pwgen_opts", JSON.stringify({ len: +lenRange.value, upper: upperCheck.checked, ...}) }. Call saveOptions() on every option change. On page load: const saved = JSON.parse(localStorage.getItem("pwgen_opts")); if (saved) restoreOptions(saved). The history array can also be persisted: localStorage.setItem("pwgen_history", JSON.stringify(history)).