JavaScript Notes
Learn how to build a show/hide password toggle using JavaScript DOM manipulation. Step-by-step beginner project with HTML, CSS, and JS code examples.
Introduction
Have you ever filled out a login form and wished you could see what you typed in the password field? That's exactly what a Show/Hide Password Toggle does — it lets users switch between hidden (••••••) and visible (myPass123) password text with a single click.
This is one of the most practical beginner DOM projects because:
- It's used on every major website (Google, Facebook, Amazon)
- It teaches event handling, attribute manipulation, and conditional logic
- You can build it in under 30 lines of JavaScript
In this tutorial, we'll build a complete password toggle from scratch — with an eye icon that switches between "show" and "hide" states. By the end, you'll understand how to manipulate input attributes and toggle UI states confidently.
HTML Structure
We need a container that holds the password input and a toggle button (eye icon) side by side.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Show/Hide Password Toggle</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="container">
<h2>Login</h2>
<div class="input-group">
<input
type="password"
id="passwordInput"
placeholder="Enter your password"
/>
<button id="toggleBtn" type="button" aria-label="Toggle password visibility">
<i class="fa-solid fa-eye"></i>
</button>
</div>
</div>
<script src="script.js"></script>
</body>
</html>Important points:
- We use Font Awesome for the eye icon (
fa-eyeandfa-eye-slash) - The button has
type="button"so it doesn't submit a form accidentally aria-labelimproves accessibility for screen readers
CSS Styling
The CSS positions the eye icon inside the input field for a clean, modern look.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.container {
background: #fff;
padding: 2.5rem;
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
width: 100%;
max-width: 400px;
}
.container h2 {
margin-bottom: 1.5rem;
color: #333;
text-align: center;
}
.input-group {
position: relative;
width: 100%;
}
.input-group input {
width: 100%;
padding: 14px 50px 14px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 1rem;
outline: none;
transition: border-color 0.3s;
}
.input-group input:focus {
border-color: #667eea;
}
.input-group button {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: #888;
font-size: 1.2rem;
transition: color 0.3s;
}
.input-group button:hover {
color: #667eea;
}Result: A centered login card with a password input field. The eye icon sits inside the input on the right side. Hovering the icon changes its color to purple.
JavaScript — Core Logic
Now let's write the JavaScript that powers the toggle functionality.
Step 1: Select Elements
const passwordInput = document.getElementById('passwordInput');
const toggleBtn = document.getElementById('toggleBtn');
const toggleIcon = toggleBtn.querySelector('i');Step 2: Add Click Event Listener
toggleBtn.addEventListener('click', function () {
// Check current type
const currentType = passwordInput.getAttribute('type');
if (currentType === 'password') {
// Show password
passwordInput.setAttribute('type', 'text');
toggleIcon.classList.remove('fa-eye');
toggleIcon.classList.add('fa-eye-slash');
} else {
// Hide password
passwordInput.setAttribute('type', 'password');
toggleIcon.classList.remove('fa-eye-slash');
toggleIcon.classList.add('fa-eye');
}
});Click 1: Password "hello123" becomes visible → icon changes to eye-slash Click 2: Password "hello123" becomes hidden (••••••••) → icon changes back to eye
How It Works Internally
getAttribute('type')reads the current state of the inputsetAttribute('type', 'text')removes the masking — browser shows plain textclassList.remove / addswaps the Font Awesome icon class- Each click toggles between the two states
Handling Multiple Password Fields
In real forms (like signup pages), you often have two password fields — "Password" and "Confirm Password". Here's how to handle multiple toggles efficiently:
<div class="input-group">
<input type="password" class="pass-field" placeholder="Password" />
<button class="toggle-btn" type="button">
<i class="fa-solid fa-eye"></i>
</button>
</div>
<div class="input-group">
<input type="password" class="pass-field" placeholder="Confirm Password" />
<button class="toggle-btn" type="button">
<i class="fa-solid fa-eye"></i>
</button>
</div>Each toggle button independently controls its own password field. Clicking toggle on "Password" field does NOT affect "Confirm Password" field.
Key techniques used:
querySelectorAllselects all toggle buttonsclosest('.input-group')finds the parent container of the clicked buttonclassList.replace()is a cleaner way to swap classes in one call
Complete Code
Here's the full working project in a single file for quick testing:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Show/Hide Password Toggle</title>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.0/css/all.min.css"
/>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', Tahoma, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.container {
background: #fff;
padding: 2.5rem;
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
width: 100%;
max-width: 400px;
}
.container h2 {
margin-bottom: 1.5rem;
color: #333;
text-align: center;
}
.input-group {
position: relative;
width: 100%;
margin-bottom: 1rem;
}
.input-group input {
width: 100%;
padding: 14px 50px 14px 16px;
border: 2px solid #e0e0e0;
border-radius: 8px;
font-size: 1rem;
outline: none;
transition: border-color 0.3s;
}
.input-group input:focus { border-color: #667eea; }
.input-group button {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
cursor: pointer;
color: #888;
font-size: 1.2rem;
transition: color 0.3s;
}
.input-group button:hover { color: #667eea; }
</style>
</head>
<body>
<div class="container">
<h2>Login Form</h2>
<div class="input-group">
<input type="password" id="passwordInput" placeholder="Enter your password" />
<button id="toggleBtn" type="button" aria-label="Toggle password visibility">
<i class="fa-solid fa-eye"></i>
</button>
</div>
</div>
<script>
const passwordInput = document.getElementById('passwordInput');
const toggleBtn = document.getElementById('toggleBtn');
const toggleIcon = toggleBtn.querySelector('i');
toggleBtn.addEventListener('click', function () {
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
toggleIcon.classList.replace('fa-eye', 'fa-eye-slash');
} else {
passwordInput.type = 'password';
toggleIcon.classList.replace('fa-eye-slash', 'fa-eye');
}
});
</script>
</body>
</html>┌──────────────────────────────┐ │ Login Form │ │ │ │ ┌────────────────────┬───┐ │ │ │ •••••••• │ 👁 │ │ │ └────────────────────┴───┘ │ │ │ │ Click eye icon... │ │ │ │ ┌────────────────────┬───┐ │ │ │ hello123 │ 👁🗨│ │ │ └────────────────────┴───┘ │ └──────────────────────────────┘
Key Takeaways
- The
typeattribute controls visibility — switching between"password"and"text"is all it takes to show or hide the password characters.
- Use
classList.replace()for icon swaps — it's cleaner than callingremove()andadd()separately, and it reads better in code reviews.
closest()enables reusable toggle logic — when handling multiple password fields, useclosest()to scope each button's behavior to its parent container.
- Always add
type="button"on toggle buttons — without it, buttons inside a<form>default totype="submit"and will accidentally submit the form.
- Accessibility matters — add
aria-labelto the toggle button so screen readers announce "Toggle password visibility" instead of reading the icon's class name.
- Direct property access (
input.type) works — you can useelement.typeas a shortcut instead ofgetAttribute('type')/setAttribute('type', value)for standard HTML properties.
FAQ
Q1: Can I use a checkbox instead of an eye icon to toggle password visibility?
Yes! A checkbox approach is simpler and equally valid:
<input type="password" id="passField" />
<label>
<input type="checkbox" id="showPass" /> Show Password
</label>document.getElementById('showPass').addEventListener('change', function () {
const passField = document.getElementById('passField');
passField.type = this.checked ? 'text' : 'password';
});The checkbox version is great for accessibility — screen readers naturally announce the checked/unchecked state. The eye icon version looks more modern but requires aria-label for the same accessibility level.
Q2: Does changing the input type from "password" to "text" cause any security risk?
The toggle itself doesn't create a security vulnerability because:
- The password is already in memory (the user typed it)
- It's only visible on the user's own screen
- It doesn't transmit the password anywhere
However, be mindful of shoulder surfing — someone looking over the user's shoulder could read the password. That's why the default state should always be type="password" (hidden), and the toggle should revert to hidden after a few seconds on sensitive applications.
Q3: Why does my toggle button submit the form instead of toggling?
This happens because buttons inside a <form> element have type="submit" by default. When you click the eye icon button, it submits the form instead of running your toggle code.
Fix: Always set type="button" explicitly:
This is a common mistake in form-based projects. Remember: inside a form, always specify the button type!
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for JavaScript Show/Hide Password Toggle — Beginner DOM Project 2026.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this JavaScript Master Course topic.
Search Terms
javascript-complete-guide, javascript master course, javascript, complete, guide, mini, projects, show
Related JavaScript Master Course Topics