Opened 7 weeks ago
Closed 9 days ago
#65707 closed defect (bug) (fixed)
The Application Passwords table misses a th row header when first created via AJAX
| Reported by: | afercia | Owned by: | afercia |
|---|---|---|---|
| Priority: | normal | Milestone: | 7.2 |
| Component: | Administration | Version: | |
| Severity: | normal | Keywords: | has-patch has-unit-tests commit |
| Cc: | Focuses: | accessibility |
Description
Splitting this out from #32892.
Tables that extend WP_List_Table are meant to use a <th> element as row header so that when navigating the table vertically with a screen reader, the row header can be referenced and announced to provide context to users.
In [62838] we also added an aria-label attribute to the <th> row header to provide a cleaner accessible name.
However, the table generated for the Application Passwords entirely misses a <th> element when first created via AJAX. The <th> is only rendered after refreshing the page.
The <th> element should be rendered also when first created via AJAX.
To reproduce:
- Go to Users > User Profile, or edit an existing user.
- Scroll down the page to the 'Application Passwords' section.
- Create a new app password.
- Inspect the DOM via your browser dev tools and observe all the cell of the table row are
<td>elements. - Refresh the page.
- Inspect the DOM again and observe that now the cell with the app name is a
<th>element, with ascope="row"attribute. This is the expected markup.
Change History (7)
This ticket was mentioned in PR #12690 on WordPress/wordpress-develop by @khokansardar.
7 weeks ago
#1
- Keywords has-patch has-unit-tests added
This ticket was mentioned in Slack in #accessibility by joedolson. View the logs.
5 weeks ago
This ticket was mentioned in Slack in #accessibility by joedolson. View the logs.
3 weeks ago
@khokansardar commented on PR #12690:
10 days ago
#5
LGTM thank you. I only left two very minor comments.
Thanks @afercia! Both addressed in 9e86fa2 — added a description to the property docblock, and dropped the <td> assertion since the <th scope="row"> one already covers it.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
Tables extending WP_List_Table render the primary column as a
<th scope="row">element so screen readers can announce it as context when navigating the table vertically. The Application Passwords table did this for server-rendered rows but not for the JavaScript row template used when a password is created via AJAX, so the row header was missing until reload.What the problem was:
<th scope="row">(correct).<td>— the<th>row header was missing.What the fix does:
print_js_template_row()as a<th scope="row">element, mirroringWP_List_Table::single_row_columns().Approach and why:
single_row_columns()uses the same$tag/$scopelogic; reusing it keeps the two rendering paths identical. Noaria-labelis added because the table does not overrideget_primary_column_aria_label(), so the server path emits none either — adding one would introduce a new mismatch.Trac ticket: https://core.trac.wordpress.org/ticket/65707
## Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 4.8
Used for: Ticket analysis, tests implementation, and writing PR description. All changes were reviewed and validated by me.