Opened 4 weeks ago
Closed 4 weeks ago
#65630 closed defect (bug) (fixed)
Add user page should not set initial focus on the password field.
| Reported by: | afercia | Owned by: | afercia |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.1 |
| Component: | Administration | Version: | 5.9 |
| Severity: | normal | Keywords: | has-patch |
| Cc: | Focuses: | accessibility |
Description
Setting initial focus on a specific control in the UI makes sense only when there is a unique, very specific task to perform for users.
In all other cases, great care should be taken to not make assumptions and not disrupt the native tab order, keyboard navigation, and discoverability of the UI.
To reproduce:
- Go to WP Admin > Users > Add user
- Observe initial focus is set on the password field, which is in the middle of the form.
- Observe that for keyboard users half of the form has been just skipped.
This is not ideal for all keyboard users, including screen reader users, and should be fixed.
Originally introduced in [52193] / #40302 for the 5.9 milestone.
The original intent was to set focus on the reset password field in wp-login.php. Somehow, it was missed that the selector to get the field to set focus to is used on other pages as well thus triggering an undesirable initial focus.
Change History (10)
This ticket was mentioned in Slack in #accessibility by afercia. View the logs.
4 weeks ago
This ticket was mentioned in PR #12534 on WordPress/wordpress-develop by @iamchitti.
4 weeks ago
#5
- Keywords has-patch added; needs-patch removed
## Ticket
https://core.trac.wordpress.org/ticket/65630
## Description
Setting initial focus on a specific control only makes sense when there is a single, well-defined task for the user. On the Add New User screen, focus is currently placed on the password field in the middle of the form, skipping the Username, Email, and Name fields. This disrupts the native tab order and hurts discoverability for keyboard and screen reader users.
## Cause
In src/js/_enqueues/admin/user-profile.js, the password field is focused whenever generatePassword() runs, which happens on every screen where the field carries data-reveal="1" — the wp-login.php reset password form, install.php, and user-new.php (Add New User).
The existing guard is a blocklist that only excludes the mailserver (#mailserver_pass) and install (#weblog_title) screens, so Add New User slips through and steals focus. The behavior was originally introduced in 52193 and was only ever intended for the reset password field on wp-login.php; the shared selector caused it to leak onto other pages.
## Testing
- Add New User (
wp-admin/user-new.php): focus is no longer forced onto the password field; tab order starts at the top of the form. - Reset password (
wp-login.php): password field still receives focus as intended. - Unaffected screens verified:
install.php,options-writing.php(#mailserver_pass),setup-config.php(#pwd, not matched by$pass1).
## Screenshots
Before
https://github.com/user-attachments/assets/f05ce9bf-5d98-435a-bd03-517ad6da4913
After
https://github.com/user-attachments/assets/39911c72-899d-485c-8c03-422ce4968c7e
@afercia commented on PR #12534:
4 weeks ago
#6
@i-am-chitti thanks for your PR. While testing, I noticed something I was not aware of.
Can you please help me confirm the following:
- Completely remove the line that sets focus on the password field.
- Follow the reset password flow from the login screen. This implies setting up the environment to catch emails with Mailpit and get the link to the reset password screen.
- On the reset password screen, observe the password field gets initial focus anyways even after the code in
user-profile.jsis removed.
To my understanding, in wp-login.php the case 'rp': of the big PHP switch prints out the markup for the reset password screen. It already includes a small JS script to set focus _when the password input field is not empty_, which is always the case.
See here:
If it is confirmed, I wonder why the code in user-profile.js was added in the first place as it appears the original intent was scoped to the reset password screen, which already sets focus on the password field.
#7
@
4 weeks ago
Relevant previous changes for this are: [52193], [55974], and [60268]
where [52193] already changed the param passed to login_footer from
login_footer( 'user_pass' );
to
login_footer( 'pass1' );
That already prints an inline script on the reset password page to set the initial focus so it's not clear to me why the logic was duplicated in user-profile.js by using $( $pass1 ).trigger( 'focus' );.
@iamchitti commented on PR #12534:
4 weeks ago
#8
Thanks @afercia for pointing out. I traced it through all three changesets and this JS line has been redundant since it was added.
52193 added it alongside the real fix: correcting login_footer( 'user_pass' ) → login_footer( 'pass1' ), which prints the server-side inline script that focuses #pass1. Since user-profile.js is enqueued on the reset screen too https://github.com/WordPress/wordpress-develop/blob/144d701af9d2ef75bf4ccef226972190ecd1e9a0/src/wp-login.php#L1092, the JS trigger( 'focus' ) just repeats focus the inline script already set. And because $pass1 matches #pass1 / #mailserver_pass on multiple screens, it leaks focus elsewhere.
The follow-ups confirm it: 55974 and 60268 each added a guard (mailserver_pass, then #weblog_title) to stop that leak on new pages. 65630 is just the next instance.
Is explicit focus required? No — the reset screen keeps its focus via login_footer( 'pass1' ).
Regressions from removing it? None. Reset password still works; Add New User / install / options-writing have no focus on password field as desired. Hence, I've dropped the block entirely.
@afercia commented on PR #12534:
4 weeks ago
#9
@i-am-chitti Thank you for the thorough investigation 👍🏻
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
I looked into this and can confirm the cause.
The initial focus is set in
src/js/_enqueues/admin/user-profile.js, where the password field is focused whenever it carriesdata-reveal="1". That attribute is used on several screens — thewp-login.phpreset password form,install.php, anduser-new.php(Add New User). The current guard only excludes the mailserver and install screens, so the Add New User page slips through and grabs focus in the middle of the form, exactly as reported.As the ticket notes, [52193] only ever intended to focus the reset field on
wp-login.php; the shared selector caused it to leak onto other pages.I think this is worth fixing. The focus is genuinely disruptive here: it drops keyboard and screen reader users into the middle of the form, skipping the Username, Email, and Name fields entirely, which hurts discoverability and breaks the natural tab order. It's also low risk to fix — the focus behavior is only correct on one specific screen (the reset password form), so scoping it to that form restores the native tab order everywhere else without affecting the intended flow.
I'm drafting a PR for its fix.