Build a Random Password Generator in JavaScript (Beginner Project)
Build a random password generator in JavaScript — length slider, character options, copy button, strength meter, and why crypto.getRandomValues beats Math.random.
"Password123" is still one of the most common passwords in the world, and every data breach dump proves that humans are terrible at inventing secure passwords. We reuse them, we make them predictable, and we forget the strong ones. The professional solution is a password generator — a small tool that creates long, random, unpredictable passwords in one click.
In this beginner-friendly tutorial, you will build a complete random password generator using only HTML, CSS, and vanilla JavaScript. It will have a length slider, toggles for uppercase letters, numbers, and symbols, a one-click copy button, and even a password strength meter. Along the way you will learn about randomness in JavaScript, the Web Crypto API, clipboard handling, and how to design controls users actually enjoy using.
Why This Is a Perfect Beginner Project
The best beginner projects share three traits: they solve a real problem, they are small enough to finish in one sitting, and they teach transferable skills. A password generator ticks all three boxes. Unlike yet another to-do list, this is a tool you will genuinely use — and showing a working security tool in your portfolio sparks far more interesting conversations than a counter app.
Technically, the project is a goldmine disguised as a toy. You will work with strings and character sets, handle multiple input types (range sliders, checkboxes, buttons), generate cryptographically secure random values, write to the system clipboard, and compute a strength score with simple heuristics. Every one of these skills reappears constantly in real front-end work, from form builders to dashboards.
There is also a genuinely interesting computer science question at the heart of it: what does "random" even mean in JavaScript, and is Math.random() good enough for passwords? We will answer that properly — it is the kind of detail that separates a tutorial-following beginner from a thoughtful developer.
Step 1: Project Setup — The HTML Skeleton
Our interface needs: a readonly text field showing the generated password, a length slider with a live value display, four checkboxes (uppercase, lowercase, numbers, symbols), a generate button, a copy button, and a strength meter bar. Semantic, accessible markup looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Password Generator</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="card">
<h1>Password Generator</h1>
<div class="output-row">
<input type="text" id="password" readonly placeholder="Your password appears here">
<button id="copyBtn" title="Copy to clipboard">Copy</button>
</div>
<div class="strength"><div id="strengthBar"></div></div>
<p id="strengthLabel"></p>
<label>Length: <span id="lenVal">16</span></label>
<input type="range" id="length" min="8" max="64" value="16">
<div class="options">
<label><input type="checkbox" id="upper" checked> Uppercase (A–Z)</label>
<label><input type="checkbox" id="lower" checked> Lowercase (a–z)</label>
<label><input type="checkbox" id="digits" checked> Numbers (0–9)</label>
<label><input type="checkbox" id="symbols" checked> Symbols (!@#$) </label>
</div>
<button id="genBtn" class="primary">Generate Password</button>
</main>
<script src="app.js"></script>
</body>
</html>
A few thoughtful defaults: the minimum length is 8 (anything shorter is not a serious password), the default is 16 (a comfortable modern standard), and all four character types start checked so the first click already produces a strong result. The password field is readonly — users copy it with the button rather than accidentally editing it.
Step 2: Designing the UI with CSS
Security tools should feel secure, so we will use a dark, modern theme — deep navy background, a glowing accent, and a monospace font for the password itself (monospace makes similar characters like l, 1, and I easier to tell apart, which matters when someone reads a password off the screen).
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Segoe UI', system-ui, sans-serif;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
background: #0f172a;
color: #e2e8f0;
padding: 20px;
}
.card {
background: #1e293b;
border-radius: 20px;
padding: 32px;
width: 100%;
max-width: 440px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
border: 1px solid #334155;
}
.card h1 { font-size: 24px; margin-bottom: 20px; text-align: center; }
.output-row { display: flex; gap: 8px; }
#password {
flex: 1;
padding: 14px;
font-family: 'Courier New', monospace;
font-size: 17px;
background: #0f172a;
border: 1px solid #334155;
border-radius: 10px;
color: #4ade80;
}
.strength { height: 8px; background: #334155; border-radius: 99px; margin-top: 14px; overflow: hidden; }
#strengthBar { height: 100%; width: 0; border-radius: 99px; transition: width 0.3s, background 0.3s; }
input[type="range"] { width: 100%; margin: 6px 0 16px; accent-color: #4ade80; }
.options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 20px; }
.primary {
width: 100%;
padding: 15px;
border: none;
border-radius: 12px;
background: linear-gradient(135deg, #22c55e, #16a34a);
color: #052e16;
font-size: 17px;
font-weight: 800;
cursor: pointer;
}
The accent-color property is a lovely modern shortcut — it themes the range slider and checkboxes with one line instead of custom pseudo-element surgery. The strength bar uses a CSS transition so it animates smoothly as the score changes.
Step 3: The Core Logic — Generating Random Strings
Here is the heart of the app. We build a character pool from the checked options, then pick random characters from it, one per position, until we reach the desired length:
const UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const LOWER = 'abcdefghijklmnopqrstuvwxyz';
const DIGITS = '0123456789';
const SYMBOLS = '!@#$%^&*()-_=+[]{}|;:,./?';
function buildPool() {
let pool = '';
if (upperEl.checked) pool += UPPER;
if (lowerEl.checked) pool += LOWER;
if (digitsEl.checked) pool += DIGITS;
if (symbolsEl.checked) pool += SYMBOLS;
return pool;
}
function generatePassword() {
const pool = buildPool();
if (!pool) { alert('Select at least one character type.'); return; }
const length = parseInt(lengthEl.value, 10);
const randomValues = new Uint32Array(length);
crypto.getRandomValues(randomValues);
let password = '';
for (let i = 0; i < length; i++) {
password += pool[randomValues[i] % pool.length];
}
passwordEl.value = password;
updateStrength(password);
}
The loop is simple: for each position, take a random integer, use modulo to map it into the pool's index range, and append that character. But the interesting line is crypto.getRandomValues() — which brings us to the most important lesson of this project.
Step 4: Security Notes — Math.random() vs Crypto
You will see many tutorials generate passwords with Math.random(). It works, it looks random, and for a toy it is fine. But Math.random() is a pseudorandom generator: its output is deterministic given the internal seed, and it was never designed to withstand attack. If someone can observe enough of its outputs, they can predict future ones. For anything security-related — passwords, tokens, session IDs — it is the wrong tool.
crypto.getRandomValues(), part of the Web Crypto API built into every modern browser, fills a typed array with cryptographically secure random numbers drawn from the operating system's entropy pool — the same quality of randomness used for TLS encryption. It costs nothing extra to use and is the correct choice here. One caveat: using modulo (% pool.length) introduces a tiny statistical bias when the pool size does not divide the random range evenly (called modulo bias). For a learning project it is negligible, but production password managers use rejection sampling to eliminate it.
This distinction — knowing which random to use and why — is exactly the kind of judgement that turns a coder into an engineer. Mention it in an interview when showing this project and watch the interviewer's eyebrows go up.
Step 5: Options, Copy Button & Strength Meter
With generation working, we wire up the remaining controls. The length slider updates its label live via the input event; the copy button uses the modern Clipboard API with a fallback for older browsers; and the strength meter scores the password on length plus character variety. The copy button swaps to a checkmark for a second after copying — always confirm invisible actions like clipboard writes so the user knows it worked. Auto-generating a password on page load means the app is useful the instant it opens, with zero clicks required.
Common Mistakes & How to Test
Test like an attacker, not like the author. Uncheck all four character types and hit generate — you should get the alert, not an empty password or a crash. Drag the slider to 8 and 64 and confirm the output length matches exactly. Generate ten passwords in a row and eyeball them for obvious patterns (there should be none). Try the copy button and paste into a text editor to confirm the clipboard actually received the password.
Beginners typically stumble in three places here. First, reading lengthEl.value as a string and using it in arithmetic without parseInt. Second, forgetting the empty-pool guard and producing an empty password when all boxes are unchecked. Third, testing only in one browser — the Clipboard API requires a secure context (HTTPS or localhost), so if copy fails on a file:// page, that is why.
And when you are ready for your next beginner build, download the free source code of our Typing Speed Test (WPM & Accuracy Checker) — it is another single-file-friendly project that levels up your event handling and timing logic, and studying real finished code is the fastest way to grow after any tutorial.
Frequently Asked Questions
Q: Is Math.random() really unsafe for password generation?
A: For real security, yes — use crypto.getRandomValues() instead. Math.random() is predictable given enough observed outputs and was never designed for cryptographic use. The Web Crypto API is free, built into all modern browsers, and the correct tool for passwords, tokens, and anything security-sensitive.
Q: How long should a generated password be in 2026?
A: Sixteen characters drawn from all four character types is a solid default — it has roughly 95^16 possible combinations, far beyond brute-force reach. For master passwords (like your password manager itself), consider 20+ characters or a multi-word passphrase.
Q: Should I store generated passwords in my app?
A: No — a generator should create and hand over the password, then forget it. Storing passwords brings serious security responsibilities (encryption, access control, breach liability). Pair your generator with a reputable password manager instead of building storage yourself.
Q: Can I use this project in my portfolio or resume?
A: Absolutely — and frame it well. Instead of "built a password generator", write "built a password generator using the Web Crypto API with entropy-correct randomness, clipboard integration, and a heuristic strength meter". Specificity signals real understanding.
Keep reading
How to Build a BMI Calculator with HTML, CSS & JavaScript
Build a complete BMI calculator with HTML, CSS & JavaScript in this beginner tutorial — form handling, the BMI formula, validation, and colour-coded health categories.
Read article
Free Invoice Format in Excel for Indian Freelancers (2026 Guide)
Free Excel invoice format for Indian freelancers — GST-compliant fields, step-by-step setup, essential formulas, and common mistakes to avoid in 2026.
Read article
How to Calculate EMI for Home Loans in India: 2026 Guide
Learn how home loan EMI is calculated in India with the official formula, a worked ₹40 lakh example, and smart 2026 tips to lower your monthly payments.
Read article