A password generator is an example of one of those projects that help you learn the basics of JavaScript and create a practical tool at the same time. In today’s post, I will describe in detail the process of creating my own password generator.
The Problem
Everyone needs good and unique passwords to secure all their accounts. However, manual generation of random passwords is a cumbersome process, and using the same password for each login makes you vulnerable to threats. This is where a password generator can help.
The Approach
My goal was simple: build a generator that:
- It Lets users choose which character types to include (uppercase, lowercase, numbers, symbols)
- This Allows adjusting the password length with a slider
- It can Generates a random password instantly
- It Help Copies the password to the clipboard with one click
The entire thing had to be clean, responsive, and work without any external libraries.
Step 1: I Define the Character Pools First
The foundation of any password generator is the character sets you draw from. I defined these four strings:
Javascript
const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const LOWER = "abcdefghijklmnopqrstuvwxyz";
const NUMBERS = "0123456789";
const SYMBOLS = "!@#$%^&*()_+-=[]{}|;:,.<>?/";
Step 2: Collecting User Preferences
Next, I needed to know what the user wants. So, I used checkboxes for character types and a range slider for length that can go from 6-32 characters long:
Javascript
function generatePassword() {
let pool = '';
if (includeUpper.checked) pool += UPPER;
if (includeLower.checked) pool += LOWER;
if (includeNumbers.checked) pool += NUMBERS;
if (includeSymbols.checked) pool += SYMBOLS;
// Fallback in case nothing is selected
if (pool === '') pool = LOWER;
const length = parseInt(lengthSlider.value, 10);
// ... generation happens next
}
This fallback is important; it prevents the generator from breaking if the user unchecks everything.
Step 3: The Generation Logic
This is the heart of the generator. It was surprisingly simple:
Javascript
let password = '';
for (let i = 0; i < length; i++) {
const idx = Math.floor(Math.random() * pool.length);
password += pool[idx];
}
passwordOutput.value = password;
For each position in the password, I pick a random character from our pool and append it. No complex algorithms, no external APIs—just pure JavaScript randomness.
Step 4: Copy to Clipboard
The copy feature makes the generator practical. I used the Clipboard API:
Javascript
function copyPassword() {
const pass = passwordOutput.value;
if (!pass) return;
navigator.clipboard.writeText(pass).catch(() => {
// Fallback for older browsers
passwordOutput.select();
document.execCommand('copy');
});
}
Step 5: I Put It All Together
Here’s the complete source code for the generator logic:
Javascript
// DOM references
const passwordInput = document.getElementById('passwordOutput');
const generateBtn = document.getElementById('generateBtn');
const copyBtn = document.getElementById('copyBtn');
const lengthSlider = document.getElementById('lengthSlider');
const lengthDisplay = document.getElementById('lengthDisplay');
const includeUpper = document.getElementById('includeUppercase');
const includeLower = document.getElementById('includeLowercase');
const includeNumbers = document.getElementById('includeNumbers');
const includeSymbols = document.getElementById('includeSymbols');
const UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const LOWER = 'abcdefghijklmnopqrstuvwxyz';
const NUMBERS = '0123456789';
const SYMBOLS = '!@#$%^&*()_+-=[]{}|;:,.<>?/';
function generatePassword() {
let pool = '';
if (includeUpper.checked) pool += UPPER;
if (includeLower.checked) pool += LOWER;
if (includeNumbers.checked) pool += NUMBERS;
if (includeSymbols.checked) pool += SYMBOLS;
if (pool === '') pool = LOWER;
const length = parseInt(lengthSlider.value, 10);
let password = '';
for (let i = 0; i < length; i++) {
const idx = Math.floor(Math.random() * pool.length);
password += pool[idx];
}
passwordInput.value = password;
}
function copyPassword() {
navigator.clipboard.writeText(passwordInput.value);
}
// Event listeners
generateBtn.addEventListener('click', generatePassword);
copyBtn.addEventListener('click', copyPassword);
lengthSlider.addEventListener('input', () => {
lengthDisplay.textContent = lengthSlider.value;
});
// Generate initial password
generatePassword();
The UI
I maintained the interface to be minimal yet useful. The password is displayed clearly in a line along with the Copy button. The options have been provided in checkboxes, and the length slider provides updates in real-time.
Yes, I know what you might be wondering. I got the JavaScript code, but where is the HTML/CSS code? No worries, I got you here. This is the ui and the fully functional code of the project you can use then as you want and make changes and try to practice on your own beUIuse its better to write on your own rather than just reading. Good luck and happy learning.
Source Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Password Generator · simple tutorial</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #f2f7fb;
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
padding: 2rem 1rem;
display: flex;
justify-content: center;
}
.wrapper {
max-width: 960px;
width: 100%;
background: white;
border-radius: 32px;
padding: 2rem 2.2rem;
box-shadow: 0 12px 30px rgba(0,0,0,0.06);
}
h1 {
font-size: 2.2rem;
font-weight: 600;
color: #0b2b3b;
letter-spacing: -0.02em;
margin-bottom: 0.25rem;
}
.sub {
color: #2d5a72;
border-left: 3px solid #3a8bb0;
padding-left: 1rem;
margin-bottom: 2rem;
font-size: 1rem;
}
/* demo box */
.demo-box {
background: #f0f6fc;
border-radius: 28px;
padding: 1.8rem 2rem 2rem;
border: 1px solid #d6e3ed;
margin-bottom: 2.8rem;
}
.password-row {
background: white;
border-radius: 60px;
padding: 0.2rem 0.2rem 0.2rem 1.8rem;
display: flex;
align-items: center;
gap: 0.5rem;
border: 1px solid #cbdde9;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
#passwordOutput {
font-family: 'Fira Mono', 'JetBrains Mono', monospace;
font-size: 1.4rem;
font-weight: 500;
color: #0b2b3b;
padding: 0.7rem 0;
border: none;
background: transparent;
flex: 1;
min-width: 150px;
outline: none;
letter-spacing: 0.5px;
}
.copy-btn {
background: #1f4b66;
border: none;
color: white;
padding: 0.6rem 1.8rem;
border-radius: 60px;
font-weight: 600;
font-size: 0.95rem;
cursor: pointer;
transition: 0.1s;
white-space: nowrap;
}
.copy-btn:hover {
background: #143a4e;
}
.options {
display: flex;
flex-wrap: wrap;
gap: 1rem 2rem;
align-items: center;
margin: 0.8rem 0 1.2rem;
}
.opt {
display: flex;
align-items: center;
gap: 8px;
background: white;
padding: 0.3rem 1rem 0.3rem 0.8rem;
border-radius: 40px;
border: 1px solid #d6e3ed;
}
.opt input[type="checkbox"] {
width: 17px;
height: 17px;
accent-color: #1f6b8a;
cursor: pointer;
}
.opt label {
font-weight: 500;
color: #1a4055;
font-size: 0.95rem;
cursor: pointer;
}
.length-box {
display: flex;
align-items: center;
gap: 12px;
background: white;
padding: 0.2rem 1rem 0.2rem 1.2rem;
border-radius: 40px;
border: 1px solid #d6e3ed;
}
.length-box label {
font-weight: 500;
color: #1a4055;
}
.length-box input[type="range"] {
width: 130px;
accent-color: #1f6b8a;
cursor: pointer;
}
.len-val {
min-width: 2.4rem;
font-weight: 600;
background: #e2eef9;
padding: 0.1rem 0.5rem;
border-radius: 30px;
text-align: center;
font-size: 0.95rem;
color: #0b2b3b;
}
.generate-btn {
background: #1b6b8f;
border: none;
color: white;
font-weight: 600;
font-size: 1.05rem;
padding: 0.7rem 2.2rem;
border-radius: 60px;
cursor: pointer;
transition: 0.1s;
margin-top: 0.6rem;
border: 1px solid #2b7fa3;
}
.generate-btn:hover {
background: #0f5272;
}
/* tutorial */
.step {
background: #f8fbfe;
border-radius: 24px;
padding: 1.5rem 1.8rem;
margin-bottom: 1.5rem;
border: 1px solid #e2edf5;
}
.step h3 {
font-size: 1.3rem;
font-weight: 600;
color: #0b3348;
margin-bottom: 0.8rem;
}
.step p, .step li {
color: #1d3a4e;
line-height: 1.7;
font-size: 1rem;
}
.step ul {
padding-left: 1.5rem;
margin: 0.4rem 0;
}
.code {
background: #0b1f2b;
border-radius: 18px;
padding: 1.2rem 1.6rem;
margin: 1rem 0 0.2rem;
color: #d4e9f5;
font-family: 'Fira Mono', 'JetBrains Mono', monospace;
font-size: 0.9rem;
overflow-x: auto;
white-space: pre-wrap;
word-break: break-word;
border: 1px solid #264b5e;
line-height: 1.6;
}
.code .c { color: #7fa9be; }
.code .k { color: #f1c40f; }
.code .fn { color: #6bc5f7; }
.code .s { color: #b3d9a8; }
.code .n { color: #d4e9f5; }
.inline {
background: #e3eef7;
padding: 0.15rem 0.6rem;
border-radius: 30px;
font-family: 'Fira Mono', monospace;
font-size: 0.85rem;
color: #11435c;
}
.foot {
margin-top: 0.8rem;
color: #2d5b77;
border-top: 1px dashed #b6d2e3;
padding-top: 1rem;
font-size: 0.95rem;
}
hr {
border: none;
border-top: 2px solid #dbe8f2;
margin: 2rem 0 0.5rem;
}
@media (max-width: 650px) {
.wrapper { padding: 1.2rem; }
.options { flex-direction: column; align-items: stretch; }
.length-box { flex-wrap: wrap; }
.password-row { background: transparent; padding: 0.2rem; gap: 0.6rem; }
#passwordOutput { background: white; border-radius: 60px; padding: 0.6rem 1rem; }
.copy-btn { width: 100%; justify-content: center; }
}
</style>
</head>
<body>
<div class="wrapper">
<h1>Password generator</h1>
<div class="sub">step-by-step tutorial with source code</div>
<!-- LIVE DEMO + SCREENSHOT -->
<div class="demo-box">
<div class="password-row">
<input type="text" id="passwordOutput" readonly value="N4#vL9$qR2!">
<button class="copy-btn" id="copyBtn">Copy</button>
</div>
<div class="options">
<div class="opt">
<input type="checkbox" id="includeUppercase" checked>
<label for="includeUppercase">A-Z</label>
</div>
<div class="opt">
<input type="checkbox" id="includeLowercase" checked>
<label for="includeLowercase">a-z</label>
</div>
<div class="opt">
<input type="checkbox" id="includeNumbers" checked>
<label for="includeNumbers">0-9</label>
</div>
<div class="opt">
<input type="checkbox" id="includeSymbols" checked>
<label for="includeSymbols">!@#$</label>
</div>
<div class="length-box">
<label for="lengthSlider">Length</label>
<input type="range" id="lengthSlider" min="6" max="32" value="14">
<span class="len-val" id="lengthDisplay">14</span>
</div>
</div>
<button class="generate-btn" id="generateBtn">Generate password</button>
</div>
<script>
(function() {
const passwordOutput = document.getElementById('passwordOutput');
const generateBtn = document.getElementById('generateBtn');
const copyBtn = document.getElementById('copyBtn');
const lengthSlider = document.getElementById('lengthSlider');
const lengthDisplay = document.getElementById('lengthDisplay');
const includeUpper = document.getElementById('includeUppercase');
const includeLower = document.getElementById('includeLowercase');
const includeNumbers = document.getElementById('includeNumbers');
const includeSymbols = document.getElementById('includeSymbols');
const UPPER = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const LOWER = 'abcdefghijklmnopqrstuvwxyz';
const NUMBERS = '0123456789';
const SYMBOLS = '!@#$%^&*()_+-=[]{}|;:,.<>?/';
function generatePassword() {
let pool = '';
if (includeUpper.checked) pool += UPPER;
if (includeLower.checked) pool += LOWER;
if (includeNumbers.checked) pool += NUMBERS;
if (includeSymbols.checked) pool += SYMBOLS;
if (pool === '') pool = LOWER;
const length = parseInt(lengthSlider.value, 10);
let password = '';
for (let i = 0; i < length; i++) {
const idx = Math.floor(Math.random() * pool.length);
password += pool[idx];
}
passwordOutput.value = password;
}
function copyPassword() {
const pass = passwordOutput.value;
if (!pass) return;
navigator.clipboard.writeText(pass).catch(() => {
passwordOutput.select();
document.execCommand('copy');
});
const original = copyBtn.textContent;
copyBtn.textContent = 'Copied!';
setTimeout(() => { copyBtn.textContent = original; }, 1500);
}
generateBtn.addEventListener('click', generatePassword);
copyBtn.addEventListener('click', copyPassword);
lengthSlider.addEventListener('input', function() {
lengthDisplay.textContent = this.value;
});
document.querySelectorAll('.opt input[type="checkbox"]').forEach(cb => {
cb.addEventListener('change', generatePassword);
});
generatePassword();
})();
</script>
</body>
</html>
How UI Looks?
Here is the little glimpse of the UI of what it looks like:

What I Learned?
Developing this generator taught me some important lessons:
- Random number generation in JS: This can be done using Math.random() along with string indexes.
- User experience: The presence of the “Copy” button that displays “Copied!” lets the user know what has happened.
- Accessibility: By providing labels for the checkboxes and sliders, you make your application accessible to everyone.
- Safe programming practices: You should always have a backup in place to avoid problems.
Enhancements You Could Add
This is a minimal generator, but you could extend it with:
- You can use a strength password indicator
- Option to exclude ambiguous characters (like
0vsO) - Ability to generate multiple passwords at once
- Password history or favorites
- Exporting generated passwords
Final Thoughts
Password generation can be considered an ideal beginner/intermediate-level project. It is practical, teaches DOM and event manipulation, and provides something useful for yourself. You can find the whole code above, so feel free to use it for yourself. It was a great experience for me and I am trying to make other projects in the upcoming future till then Happy coding, and stay safe with strong passwords!
Explore Our Programming Category


