Skip to content

List Tables: Keep columns readable with horizontal scrolling. - #13866

Open
mattmiklic wants to merge 15 commits into
WordPress:trunkfrom
mattmiklic:improve/list-table-overflow
Open

mattmiklic wants to merge 15 commits into
WordPress:trunkfrom
mattmiklic:improve/list-table-overflow

Conversation

@mattmiklic

Copy link
Copy Markdown
Contributor

List tables can squeeze columns into an extremely narrow state when they need more space than the table has available. Plugins that add columns can leave little room for content like post titles, producing tall rows that are difficult to scan.

This adds a scrollable wrapper around the existing table. Above the existing mobile breakpoint, tables switch from fixed to automatic layout, with minimum widths for selected Core columns. When the columns exceed the available space, the wrapper scrolls horizontally. Filters, bulk actions, and pagination stay outside the wrapper.

The table's border moves to the new wrapper, and a fade to white inside it indicates that there is hidden content on the right edge. When scrolling, the fade appears on the left as well, when content is hidden on that edge. These are reversed for RTL content. JavaScript in common.js updates the fades during scrolling, resizing, and when tables are replaced or refreshed in place, like when searching Plugins.

When there is horizontal scrolling, the wrapper enters the Tab order so it can be focused and scrolled with the arrow keys. When a table's content fits in the viewport, the wrapper isn't included in the Tab order.

Screenshots

Narrow columns

With enough columns enabled, titles and headers become difficult to read. The updated table ensures readable column widths and scrolls to reveal the remaining content.

Before After
Posts table with plugin columns squeezing titles into narrow vertical stacks Posts table with readable titles and a right-edge fade indicating more columns

Columns that fit without scrolling

With fewer columns visible, the table fits without horizontal scrolling. Automatic layout gives the date column more room, reducing wrapping and row height in this example.

Before After
Posts table with dates wrapping onto three lines and taller rows Posts table fitting within the viewport, with dates wrapping onto two lines and more rows visible

Content that prevents wrapping

Preformatted text, text forced onto one line, or a fixed-width widget previously overflowed outside their column, colliding with the content in any that follow. Now, that column expands to contain whatever is in it, and the horizontal scrolling contains it.

Before After
Comments table with non-wrapping text and a fixed-width widget overlapping adjacent columns and overflowing the page Comments table containing wide content within a horizontally scrollable viewport, with other columns beyond its right edge

Testing

The included tests cover initialization, LTR/RTL scrolling, fractional positions and overscroll, resizing, keyboard focus, and cleanup when tables or wrappers are replaced or moved.

To test in the admin:

  1. Open Posts with enough visible columns enabled to crowd the table. Size the window larger than the mobile breakpoint, and confirm the columns remain readable as the table begins to scroll.
  2. Scroll to both ends and confirm each fade appears only when content is hidden on that side. Repeat in an RTL locale.
  3. Tab to an overflowing wrapper and scroll with the arrow keys. Check that a table which fits does not add a Tab stop, and that sorting links retain a complete focus indicator.
  4. Resize below the mobile breakpoint and check the existing mobile layout remains unchanged.

Trac ticket: https://core.trac.wordpress.org/ticket/52151

Use of AI Tools

AI assistance: Yes
Tool(s): Codex (ChatGPT)
Model(s): GPT-6 Astra
Used for: Developing and iterating on the implementation, writing regression checks and documentation, researching browser support, and assisting with code review.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

Wrap list tables in a named, keyboard-focusable scrolling region and apply minimum widths to desktop text columns. Keep the outer border on the viewport and retain the existing mobile layout.
Retain the existing Comments column width as a desktop minimum so automatic table layout cannot shrink the header enough to wrap its sort arrows.
Overlay a subtle shadow at the inline end of desktop list-table viewports while content remains beyond that edge. Use a scroll-driven CSS animation so the shadow disappears at the end and stays hidden when the table fits. Preserve the existing layout in browsers without support and at mobile widths.
Control the edge shadow through native scroll and resize handling in `common.js` so it no longer depends on CSS scroll-driven animation support. Track right-to-left positions and refresh observers when AJAX replaces a table, while preserving the existing desktop layout and mobile styles.
Show a shadow at each edge when table content is hidden beyond it, including right-to-left layouts. Clamp scroll positions so fitting tables and elastic overscroll do not produce misleading shadows, and suppress horizontal rubber-banding with `overscroll-behavior-x: none` on the desktop wrapper.
Cover initialization, LTR and RTL scroll boundaries, resizing, and cleanup after table replacement. Exercise `common.js` through dedicated QUnit fixtures for normal and minified builds.
Replace edge shadows with full-height buttons that scroll to adjacent columns. Keep their chevrons centered in the visible table area, respect reduced-motion preferences, and return focus to the table when a focused control reaches its boundary.

Extend the QUnit coverage for directional paging, labels, focus handling, icon positioning, and cleanup after table replacement. Preserve the existing mobile layout.
Draw focus indicators inside sortable links so the scroll viewport does not clip them. Move the high-contrast outline inward as well.
Keep list table wrappers in the tab order only when they provide horizontal scrolling. Preserve existing focus when overflow disappears, and restore the original `tabindex` attribute when overflow tracking ends.

Add regression coverage for resizing, focus retention, visible overflow, and cleanup.
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props mattmiklic, joen.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

@jasmussen

Copy link
Copy Markdown

This has kept coming up for me constantly over the years, I've multiple friends and family I've helped with website, they install a single plugin and on their 14 inch laptops, their columns implode. A contextually available scrollbar feels like such a better choice.

I would love if folks could give deep reviews of this one so we can land it. If not in 7.2 then 7.3—it's been an issue for a while and it's worth going straight at it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants