Skip to content

feat: add stack-on-phone attribute to os-table - #981

Merged
epeicher merged 5 commits into
WordPress:trunkfrom
Pranjal1423:fix/os-table-stack-on-phone
Oct 19, 2026
Merged

epeicher merged 5 commits into
WordPress:trunkfrom
Pranjal1423:fix/os-table-stack-on-phone

Conversation

@Pranjal1423

@Pranjal1423 Pranjal1423 commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Closes #900

Description

Added a stack-on-phone attribute to <os-table> so tables can automatically switch to a card layout on phone-sized screens without requiring extra JavaScript.

Changes

  • Added the stack-on-phone attribute to <os-table> and updated its documentation.
  • Automatically calls stackOnPhone(this) when the attribute is present.
  • Handles changes to data-os-mode so the table switches between stacked and normal layouts.
  • Cleans up observers and event listeners when the component is disconnected or the attribute is removed.
  • Updated stack-on-phone.ts to find the nearest [data-os-mode] ancestor when no root is provided.
  • Added documentation to docs/components-reference.md.
  • Added unit tests in tests/vitest/os-table-stack-on-phone.test.ts.

How to Test

  1. Run npm run test:js tests/vitest/os-table-stack-on-phone.test.ts.
  2. Add stack-on-phone to an <os-table> containing a standard HTML table.
  3. Set data-os-mode="mobile" on the container and verify that the table switches to a stacked layout with labels taken from the headers.
  4. Remove phone mode and verify that the table returns to its normal layout.
Open WordPress Playground Preview

@epeicher
epeicher self-requested a review October 16, 2026 08:34
@epeicher

epeicher commented Oct 16, 2026 •

Copy link
Copy Markdown
Collaborator

Thank you for taking on #900, @Pranjal1423! Keying the layout off the shell's mode stamp instead of a media query is the right call, and the help block and components reference are nicely updated.

One case still slips through, and it's the one #900 is about. In an .os.php view the app runtime's morph (syncAttributes() in src/app-runtime/morph.ts) removes every attribute the server didn't paint and puts back the ones it did. So on a phone, the first action drops stacked and restores sticky-columns, and the table turns back into a grid. The table only re-checks when data-os-mode changes. Since stacked and stickyColumns are already observed props, re-syncing on those in attributeChangedCallback() should be enough (stackOnPhone() only writes when something differs, so it settles after one pass):

// os-table.ts, attributeChangedCallback()
if (
	( name === 'stacked' || name === 'sticky-columns' ) &&
	this.isConnected &&
	this.hasAttribute( 'stack-on-phone' )
) {
	this._syncStackOnPhone();
}

A test that runs morphChildren over a stacked table in phone mode would pin it. Also, the "How to Test" steps say data-os-mode="phone", but the stamp value is mobile.

@Pranjal1423

Copy link
Copy Markdown
Contributor Author

Thank you for the thorough review, @epeicher!

That makes complete sense — on .os.php view morphs, syncAttributes() dropped stacked and restored sticky-columns, reverting the table back to a grid without triggering the mode stamp observer.

In commit 984703b, I have:

  1. Re-synced on observed attributes: Added observation and re-syncing for stacked and sticky-columns in attributeChangedCallback(), guarded against re-entrancy so it settles in a single pass.
  2. Preserved sticky columns across morphs: Retained the original sticky-columns count on the element instance so that when syncAttributes() cleans up unpainted attributes (like data-os-sticky-columns), returning to desktop mode or dynamically removing stack-on-phone cleanly restores the original pinned columns.
  3. Added regression tests: Added unit tests in os-table-stack-on-phone.test.ts running morphChildren() over <os-table stack-on-phone> in mobile mode, verifying both morph persistence and subsequent desktop/grid restoration.
  4. Updated PR description: Corrected the "How to Test" section in the PR description to use data-os-mode="mobile" instead of phone.

@epeicher epeicher left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for addressing the comments @Pranjal1423! I have tested it with a wide table, and it works as expected, it renders the columns as stacked cards. I like it. Changes LGTM!

Before After
Image Image

P.S. Thanks @juanlentino for the original idea as part of #900

@epeicher
epeicher merged commit a7a7bc8 into WordPress:trunk Oct 19, 2026
8 checks passed
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.

os-table: no declarative way for a server-painted table to stack on a phone

2 participants