Password Generator with HTML, CSS & JavaScript
20 DAYS 20 PROJECT CHALLENGE
Day #02
Project Overview
The Password Generator is a simple beginner-friendly project built using HTML, CSS, and JavaScript. This application allows the user to create a password consisting of letters, numbers, and symbols. Additionally, user can set the desired length of the password and choose which characters should be included in the password. The password can include lowercase letters, uppercase letters, numbers, and symbols.
Additionally, the application provides options to exclude ambiguous characters, include spaces, copy the generated password, hide or show the password, download it as a .txt file, and check its estimated strength.
Key Features
- Adjustable Password Length: The user can set the desired length of the password using a Range slider. The length of the password can be between 4 and 64 characters, and the selected value is displayed next to the slider.
- Character Type Selection: The character types that can be used in the password are indicated by checkboxes. The user can select which character types are included in the generated password.
- Avoid Ambiguous Characters: Users can enable an option to remove characters that may look similar, such as l, 1, I, 0, and O. This can make generated passwords easier to distinguish when reading or entering them.
- Include Spaces: The password generator includes the option to allow spaces in the created password. The checkbox next to the option indicates whether the space will be included in the character set.
- Random Password Generation: The JavaScript code randomly selects characters from the character sets specified by the user. The generator also ensures that the selected character sets contain the number of characters indicated by the slider.
- Password strength meter:The app provides a simple strength indicator based on password length and character variety. It displays the result as Weak, Okay, or Strong.
- Copy to Clipboard: With the Copy button, the user can save the generated password to the clipboard with one click. To do this, the JavaScript code must first check whether the Clipboard API is available; otherwise, a fallback solution is used.
- Download Password: Users can download the generated password as a .txt file by clicking the Download button. To do this, the JavaScript code creates a Blob object and saves it to the computer using the temporary URL.
- Show and Hide Password: The Hide/Show button adds or removes a blur effect from the password field. This allows the user to hide the password, for example, when working on a public computer.
- The Responsive Design: The application uses CSS Grid to position the elements on the web page. On screens smaller than 800px, the columns are merged to view the elements on a small screen. This makes the interface easier to use on mobile devices.
What You’ll Learn
- Understand how HTML creates the structure of a password generator.
- Learn how range sliders and checkboxes collect user preferences.
- Practice working with JavaScript objects and strings.
- Explore how
Math.random()selects random characters. - Understand how JavaScript builds strings dynamically.
- Learn how the Clipboard API copies text.
- Practice creating downloadable files with JavaScript.
- Explore how the DOM updates the password and strength indicator.
- Learn how event listeners respond to button and input changes.
- Understand how HTML, CSS, and JavaScript work together in an interactive project.
HTML Code
The HTML code creates the complete structure of the Password Generator. The .card container holds the project heading, password controls, preview area, and additional information. The #length range input controls the password length, while #lowercase, #uppercase, #numbers, and #symbols allow users to select character types. Additionally, the #avoidAmbiguous and #includeSpaces checkboxes provide extra generation options.
The preview section contains #password, where the generated password appears. Next, buttons such as #copyBtn, #eyeBtn, and #downloadBtn handle copying, hiding, and downloading the password. Finally, the HTML file loads script.js at the bottom of the <body>. This allows JavaScript to access these elements and add the required functionality.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Day 2 — Password Generator</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<main class="card" role="main">
<header>
<div class="logo">PW</div>
<div>
<h1>Day 2: Password Generator</h1>
<p class="lead">Generates secure random passwords with adjustable length and character sets. Built with arrays, string manipulation and Clipboard API.</p>
</div>
</header>
<section class="grid" style="margin-top:18px">
<!-- LEFT: controls -->
<div class="controls">
<div class="row">
<label for="length">Password length</label>
<div class="length-value" id="lengthValue">16</div>
</div>
<div style="margin-bottom:8px">
<input id="length" type="range" min="4" max="64" value="16" />
</div>
<div class="row">
<label class="small">Include characters</label>
</div>
<div class="checkboxes">
<label class="switch"><input id="lowercase" type="checkbox" checked /> <span class="small">Lowercase (a-z)</span></label>
<label class="switch"><input id="uppercase" type="checkbox" checked /> <span class="small">Uppercase (A-Z)</span></label>
<label class="switch"><input id="numbers" type="checkbox" checked /> <span class="small">Numbers (0-9)</span></label>
<label class="switch"><input id="symbols" type="checkbox" checked /> <span class="small">Symbols (!@#$...)</span></label>
</div>
<div style="margin-top:12px; display:flex; gap:10px;">
<button id="generateBtn" class="btn">Generate</button>
<button id="shuffleBtn" class="btn secondary">Regenerate</button>
</div>
<div style="margin-top:12px">
<label class="small">Options</label>
<div style="display:flex;gap:8px;margin-top:8px;flex-wrap:wrap">
<label class="switch"><input id="avoidAmbiguous" type="checkbox" /> <span class="small">Avoid ambiguous chars (l,1,I,0,O)</span></label>
<label class="switch"><input id="includeSpaces" type="checkbox" /> <span class="small">Allow spaces</span></label>
</div>
</div>
<div style="margin-top:12px" class="small">Concepts used: arrays, random selection, string building, clipboard API, DOM manipulation.</div>
</div>
<!-- RIGHT: preview + copy -->
<aside class="preview">
<div class="password-box">
<div class="password-text" id="password">P@ssw0rd!Example123</div>
<div style="margin-left:auto; display:flex; gap:8px">
<button id="copyBtn" class="btn secondary">Copy</button>
<button id="eyeBtn" class="btn secondary">Hide</button>
</div>
</div>
<div>
<div class="meta">Strength</div>
<div class="strength" aria-hidden="true"><i id="strengthBar"></i></div>
<div class="meta" id="strengthText">Strong</div>
</div>
<div style="display:flex;gap:8px;align-items:center;">
<button id="downloadBtn" class="btn secondary">Download as .txt</button>
<div class="small" style="margin-left:auto">Tip: Click <strong>Copy</strong> to use the password instantly.</div>
</div>
<footer>Notes: Always keep a master copy of passwords in a reputable password manager.</footer>
</aside>
</section>
<section style="margin-top:18px">
<details style="background:transparent;padding:12px;border-radius:10px;border:1px solid rgba(255,255,255,0.02)">
<summary style="cursor:pointer">How it works (short)</summary>
<p class="small" style="margin-top:8px">The script creates arrays for each enabled character type, optionally filters ambiguous characters, then randomly picks characters until the requested length is reached. It ensures a good distribution by guaranteeing at least one character from each selected set (if possible).</p>
</details>
</section>
</main>
<script src="script.js"></script>
</body>
</html>
CSS Code
The CSS code creates the modern dark appearance of the Password Generator. The :root section defines reusable variables for the background, card, accent color, muted text, border radius, and spacing. The .card class controls the application’s width, background, padding, rounded corners, border, and shadow.
Next, the .grid class creates two columns, keeping the password controls on one side and the password preview on the other. The .controls section styles the character options, while .switch gives each checkbox a clean layout. In addition, the .password-box class creates the area for the generated password and action buttons.
The .strength and .strength > i elements create the strength meter. Finally, the @media rule changes the two-column .grid into a single-column layout on smaller screens.
/* Simple modern card style */
:root {
--bg: #0f1724;
--card: #0b1220;
--accent: #7c3aed;
--muted: #9aa4b2;
--glass: rgba(255, 255, 255, 0.03);
--radius: 14px;
--pad: 20px;
font-family: Inter, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial;
}
html,
body {
height: 100%;
}
body {
margin: 0;
background: #002252;
color: #e6eef6;
display: flex;
align-items: center;
justify-content: center;
padding: 32px;
}
.card {
width: min(720px, 96%);
background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
border-radius: var(--radius);
padding: 28px;
box-shadow: 0 10px 30px rgba(2, 6, 23, 0.6);
border: 1px solid rgba(255, 255, 255, 0.03);
}
header {
display: flex;
align-items: center;
gap: 16px;
}
.logo {
width: 56px;
height: 56px;
border-radius: 12px;
background: linear-gradient(135deg, var(--accent), #3b82f6);
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
}
h1 {
font-size: 20px;
margin: 0;
}
p.lead {
margin: 6px 0 18px;
color: var(--muted);
}
.grid {
display: grid;
grid-template-columns: 1fr 320px;
gap: 18px;
}
@media (max-width:800px) {
.grid {
grid-template-columns: 1fr;
}
}
/* Left column */
.controls {
background: var(--glass);
padding: 18px;
border-radius: 12px;
}
.row {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 12px;
}
label {
font-size: 13px;
color: var(--muted);
}
.length-value {
margin-left: auto;
font-weight: 600
}
.checkboxes {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.switch {
display: flex;
align-items: center;
gap: 10px;
background: rgba(255, 255, 255, 0.02);
padding: 10px;
border-radius: 10px;
width: 100%;
}
input[type=range] {
width: 100%;
}
/* Right column */
.preview {
display: flex;
flex-direction: column;
gap: 12px;
align-items: stretch;
}
.password-box {
background: #071022;
padding: 18px;
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.03);
display: flex;
gap: 12px;
align-items: center;
}
.password-text {
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, 'Roboto Mono', monospace;
font-size: 16px;
word-break: break-all;
}
.btn {
padding: 10px 14px;
border-radius: 10px;
border: 0;
background: linear-gradient(90deg, var(--accent), #22c1c3);
color: white;
font-weight: 600;
cursor: pointer
}
.btn.secondary {
background: transparent;
border: 1px solid rgba(255, 255, 255, 0.06);
color: var(--muted)
}
.strength {
height: 10px;
border-radius: 8px;
background: rgba(255, 255, 255, 0.03);
overflow: hidden
}
.strength>i {
display: block;
height: 100%;
width: 0%;
}
.meta {
font-size: 13px;
color: var(--muted)
}
footer {
margin-top: 16px;
color: var(--muted);
font-size: 13px
}
/* tiny helpers */
.small {
font-size: 13px;
color: var(--muted)
} Javascript Code
The JavaScript code handles the password generation and all interactive features. First, the CHARSETS object stores lowercase letters, uppercase letters, numbers, and symbols. The code then selects the required HTML elements using their IDs. The pickRandom() function selects a random character from a string. The main generatePassword() function reads the selected length and checkbox options, builds a character pool, and guarantees at least one character from each selected character type when possible.
Next, the code fills the password until it reaches the requested length and uses the Fisher–Yates shuffle to randomize the character order. The updateStrength() function calculates a simple strength score based on length and character variety. Finally, copyToClipboard() handles copying, downloadTxt() creates the .txt download, and the eyeBtn listener toggles the password’s blur effect. The event listeners connect these functions to the Generate, Regenerate, Copy, and Download buttons.
// Character sets
const CHARSETS = {
lower: 'abcdefghijklmnopqrstuvwxyz',
upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
number: '0123456789',
symbol: "!@#$%^&*()-_=+[]{};:,.<>?/|~`"
};
// Elements
const lengthRange = document.getElementById('length');
const lengthValue = document.getElementById('lengthValue');
const generateBtn = document.getElementById('generateBtn');
const shuffleBtn = document.getElementById('shuffleBtn');
const copyBtn = document.getElementById('copyBtn');
const downloadBtn = document.getElementById('downloadBtn');
const passwordEl = document.getElementById('password');
const strengthBar = document.getElementById('strengthBar');
const strengthText = document.getElementById('strengthText');
const eyeBtn = document.getElementById('eyeBtn');
// Sync UI for slider
lengthRange.addEventListener('input', ()=>{
lengthValue.textContent = lengthRange.value;
updateStrength(passwordEl.textContent || '');
});
// pick a random character from a string
function pickRandom(str){
return str.charAt(Math.floor(Math.random()*str.length));
}
// Main generator
function generatePassword(){
const length = parseInt(lengthRange.value,10);
const useLower = document.getElementById('lowercase').checked;
const useUpper = document.getElementById('uppercase').checked;
const useNumber = document.getElementById('numbers').checked;
const useSymbol = document.getElementById('symbols').checked;
const avoidAmbiguous = document.getElementById('avoidAmbiguous').checked;
const includeSpaces = document.getElementById('includeSpaces').checked;
let pool = '';
const guaranteed = [];
if(useLower){
let s = CHARSETS.lower;
if(avoidAmbiguous) s = s.replace(/[l]/g,'');
pool += s;
guaranteed.push(pickRandom(s));
}
if(useUpper){
let s = CHARSETS.upper;
if(avoidAmbiguous) s = s.replace(/[IO]/g,'');
pool += s;
guaranteed.push(pickRandom(s));
}
if(useNumber){
let s = CHARSETS.number;
if(avoidAmbiguous) s = s.replace(/[01]/g,'');
pool += s;
guaranteed.push(pickRandom(s));
}
if(useSymbol){
let s = CHARSETS.symbol;
if(avoidAmbiguous) s = s.replace(/[\[\]{}()\/\\'\"`.,]/g,'');
pool += s;
guaranteed.push(pickRandom(s));
}
if(includeSpaces){
pool += ' ';
}
if(pool.length === 0){
passwordEl.textContent = 'Select at least one character set.';
updateStrength('');
return;
}
// Build password array
const pass = [];
// ensure guaranteed chars included if possible
for(let i=0;i<guaranteed.length && pass.length<length;i++) pass.push(guaranteed[i]);
while(pass.length < length){
pass.push(pickRandom(pool));
}
// Fisher–Yates shuffle
for(let i=pass.length-1;i>0;i--){
const j = Math.floor(Math.random()*(i+1));
[pass[i],pass[j]] = [pass[j],pass[i]];
}
const final = pass.join('');
passwordEl.textContent = final;
updateStrength(final);
}
// Strength meter (simple estimator)
function updateStrength(pw){
if(!pw){ strengthBar.style.width = '0%'; strengthText.textContent = ''; return; }
let score = 0;
score += Math.min(40, pw.length * 2); // length weight
if(/[a-z]/.test(pw)) score += 15;
if(/[A-Z]/.test(pw)) score += 15;
if(/[0-9]/.test(pw)) score += 15;
if(/[^A-Za-z0-9\s]/.test(pw)) score += 15;
score = Math.min(100, score);
strengthBar.style.width = score + '%';
if(score < 40){ strengthBar.style.background = '#ef4444'; strengthText.textContent = 'Weak'; }
else if(score < 70){ strengthBar.style.background = '#f59e0b'; strengthText.textContent = 'Okay'; }
else { strengthBar.style.background = '#10b981'; strengthText.textContent = 'Strong'; }
}
// Clipboard copy with fallback
async function copyToClipboard(){
const text = passwordEl.textContent;
try{
await navigator.clipboard.writeText(text);
copyBtn.textContent = 'Copied!';
setTimeout(()=> copyBtn.textContent = 'Copy',1200);
}catch(e){
// fallback
const ta = document.createElement('textarea'); ta.value = text; document.body.appendChild(ta);
ta.select();
try{ document.execCommand('copy'); copyBtn.textContent = 'Copied!'; setTimeout(()=> copyBtn.textContent='Copy',1200);}catch(err){ alert('Copy failed — select and copy manually.'); }
ta.remove();
}
}
// Download as .txt
function downloadTxt(){
const blob = new Blob([passwordEl.textContent], {type:'text/plain'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a'); a.href = url; a.download = 'password.txt'; document.body.appendChild(a); a.click(); a.remove(); URL.revokeObjectURL(url);
}
// Toggle show/hide password (simple blur)
let shown = true;
eyeBtn.addEventListener('click', ()=>{
shown = !shown;
if(shown){ passwordEl.style.filter = 'none'; eyeBtn.textContent = 'Hide'; }
else{ passwordEl.style.filter = 'blur(6px)'; eyeBtn.textContent = 'Show'; }
});
// Event listeners
generateBtn.addEventListener('click', generatePassword);
shuffleBtn.addEventListener('click', generatePassword);
copyBtn.addEventListener('click', copyToClipboard);
downloadBtn.addEventListener('click', downloadTxt);
// Initial
lengthValue.textContent = lengthRange.value;
generatePassword();
Related Projects
Day 6 : Tip Calculator
Calculates tip amount and total per person based on bill and tip %.
Concepts: Form inputs, math logic.
Day 7 : Expense Tracker
Track income and expenses, and calculate the total balance.
Concepts: LocalStorage, array methods (map, reduce).
Day 8 : Movie Search App
Search movies and display results with posters using an API.
Concepts: API integration, async/await.