Current WordPress core already provides a Show password button on the standard login screen, so you normally do not need a plugin or custom JavaScript. Visit wp-login.php (or go to /wp-admin/ while logged out), focus the password field, and activate the eye button. The password changes from masked to visible; activating it again changes the control to Hide password.
Check the native WordPress login first
The standard WordPress login page is wp-login.php. A logged-out request for /wp-admin/ redirects to that page. Current core renders the password field in a .wp-pwd wrapper with a real button labelled Show password. When selected, the input becomes visible and the accessible label changes to Hide password.
- Open the login page in a private window or while logged out.
- Enter a value in the password field.
- Select the eye button and verify that the characters become visible.
- Select it again and verify that masking returns.
If this works, do not add a second button. Duplicate controls can confuse users and may load unnecessary scripts.
When a custom control is necessary
You need your own implementation when a theme, plugin, membership system, or custom template replaces the core login form, or when a form is embedded elsewhere on the site. The essential behavior is to switch one password input between type="password" and type="text" without reading, logging, copying, or transmitting its value.
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
Adding show/hide behavior to a wp_login_form() form
wp_login_form() creates a simple WordPress login form for use in a page, widget, or template. Its password field uses autocomplete="current-password", which should be retained for password-manager compatibility. The function provides login_form_top, login_form_middle, and login_form_bottom filters for adding markup.
1. Give the password field and button stable attributes
For a custom template, place a keyboard-focusable button beside the password input. The following example scopes the control to one form and starts in the masked state:
Rank #2
<form id="member-login">
<label for="member-password">Password</label>
<div class="password-control">
<input id="member-password"
name="pwd"
type="password"
autocomplete="current-password">
<button type="button"
class="password-toggle"
aria-pressed="false"
aria-label="Show password">
Show
</button>
</div>
</form>
If you insert this into a generated form with a filter, target the actual password field ID used by that form. Do not assume that a selector intended for one form is safe when several login forms appear on the same page.
2. Toggle only the intended input
document.addEventListener('DOMContentLoaded', function () {
const form = document.querySelector('#member-login');
if (!form) return;
const input = form.querySelector('#member-password');
const button = form.querySelector('.password-toggle');
if (!input || !button) return;
button.addEventListener('click', function () {
const showing = input.type === 'text';
input.type = showing ? 'password' : 'text';
button.setAttribute('aria-pressed', String(!showing));
button.setAttribute('aria-label', showing ? 'Show password' : 'Hide password');
button.textContent = showing ? 'Show' : 'Hide';
});
});
The script changes only the input type and the button state. It does not submit, store, copy, or otherwise expose the password value.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
3. Keep the control accessible
- Use a real
<button type="button">, not a clickable<span>or link. - Keep the button reachable with the keyboard and provide a clearly visible focus style.
- Change the accessible label from Show password to Hide password as the state changes.
- Keep
aria-pressed="false"when masked andaria-pressed="true"when visible. - If an icon is used, give it an empty
altvalue or hide it from assistive technology so the button label is announced once.
Extending the native wp-login.php screen with hooks
When a plugin must add behavior to the core login page, use documented hooks rather than editing wp-login.php. The login_form action runs after the password field, making it suitable for adding adjacent markup. Use login_enqueue_scripts to load a JavaScript file or stylesheet only on the login screen.
add_action('login_form', function () {
echo '<button type="button" class="my-password-toggle" aria-pressed="false" aria-label="Show password">Show</button>';
});
add_action('login_enqueue_scripts', function () {
wp_enqueue_script(
'my-login-password-toggle',
plugin_dir_url(__FILE__) . 'login-password-toggle.js',
array(),
'1.0.0',
true
);
});
Your JavaScript must select the password input and button belonging to the native login form, then apply the same type, label, pressed-state, keyboard, and focus rules described above. Check the rendered markup on the WordPress version you support: core classes and surrounding HTML can change even though the user-facing behavior remains the same.
Rank #4
Native core versus a custom form
| Concern | Native WordPress login | Custom form or replacement |
|---|---|---|
| Show/hide control | Already included by current core. | Must be added and maintained by the site code. |
| Updates | Core receives future fixes and markup changes. | Selectors and scripts must be checked after WordPress, theme, or plugin updates. |
| Accessibility | Core supplies the Show password and Hide password states. | Your button must provide equivalent labels, pressed state, keyboard access, and focus styling. |
| Password managers | Core login behavior is integrated with the normal password field. | Retain autocomplete="current-password" and avoid replacing the field unnecessarily. |
| Multiple forms | The core screen has one intended login form. | Scope each toggle to its own form so one button cannot change another form’s field. |
| Script loading | No extra script is needed solely for this feature. | Use login_enqueue_scripts for native-screen assets, or load assets only where the custom form exists. |
Common problems and fixes
The button is missing on the normal login URL
Confirm that you are viewing the core login page rather than a branded or membership replacement. Inspect whether a plugin or theme has replaced the password markup. Also test with other login-customization plugins disabled in a staging environment.
Clicking the button submits the form
Set the control to type="button". A button inside a form defaults to submit when no type is specified.
Best Value
The label never changes
Update both the visible state and the accessible name on every click. The masked state should announce Show password; the visible state should announce Hide password.
One toggle changes the wrong field
Do not use a page-wide selector such as the first input[type=password] when multiple forms exist. Find the containing form first, then query its password input and button.
Password-manager suggestions disappear
Keep the password input’s autocomplete="current-password" attribute and avoid replacing the input node during the toggle. Changing only its type is sufficient.
Core updates break a custom selector
Do not edit wp-login.php directly. Load assets through the documented login hooks and verify selectors against the target WordPress release after updates.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




