A Responsive Table Is Really Two Interfaces Sharing One Dataset

I recently added a dynamic table shortcode to a WordPress theme. On paper, it was a formatting feature: accept headers, accept rows, render a table. The real work began when the same information had to remain useful at 390 pixels and 1280 pixels, support three columns or eight, preserve older hand-written markup, and fail safely when an editor supplied the wrong number of cells. That stopped being a table problem. It became two interfaces—a desktop comparison grid and a mobile disclosure list—sharing one validated dataset.
The desktop shape was not the mobile shape
Wide tables are excellent when a reader wants to scan down a column and compare across rows. Shrinking that grid until every cell becomes unreadable preserves the HTML but destroys the task. Horizontal scrolling can help, yet an eight-column schedule still makes a phone reader remember headings that have disappeared off screen.
I kept semantic table markup for larger viewports, including a sticky first column and horizontal containment when the content genuinely needed it. Below the mobile breakpoint, each row becomes a compact disclosure. The row label stays visible, data labels move beside their values, and the reader opens only the item they need. It is the same information, but the interaction matches the screen.
Dynamic columns made validation part of rendering
The shortcode accepts pipe-separated headers and any number of nested rows. Simple rows can use pipe-separated values; richer cells support alternatives, notes, pills, formatted content, and intentional blanks. That flexibility creates a hard rule: every row must resolve to the number of data columns promised by the headers.
I chose to fail closed. If the title, headers, rows, or dimensions are invalid, the renderer returns no partial table. A broken half-table can look authoritative while associating a value with the wrong heading. An empty result is easier to detect in review and safer than plausible misinformation.
CSS-only disclosure was a deliberate constraint
The mobile rows use keyboard-operable checkboxes and CSS state, with first, all, or none as the default-open policy. That avoided making essential content depend on a JavaScript bundle. It also kept the component usable in previews and unusual embedding contexts where the theme script might not run.
The constraint was not “avoid JavaScript at all costs.” It was “do not spend JavaScript on state the browser can already express.” If the component later needs synchronized analytics, deep links, or cross-row controls, script may earn its place. For the present interaction, native controls and CSS are the smaller failure surface.
Compatibility changed the architecture
There was already reviewed raw markup using the same visual class contract. Replacing it with an entirely new component would have created two systems and a migration project. Instead, the shortcode emits the established class names, and the complete component styling lives in the theme so old markup and new authoring share one runtime.
A reusable component is not only a nicer way to create new content. It is a promise about how existing content keeps working.
That promise affected names, CSS ownership, preview behavior, and the decision not to rewrite saved posts.
The useful test matrix crossed content and viewport
I did not test one happy table at one phone size. Fixtures covered three-, six-, and eight-column variants; simple and advanced cells; empty slots; primary and secondary time labels; footer notes; and malformed dimensions. Browser coverage ran across several phone widths, tablet, and desktop, while PHP tests exercised parsing and escaping.
The test question was never merely “is it visible?” On desktop I checked semantics, sticky labels, containment, and alignment. On mobile I checked the default-open policy, keyboard operation, data labels, hidden empty cells, and whether expanding one row exposed the correct values.
One subtle issue was editorial preview. A shortcode that behaves well only on the public template is difficult to review, so I kept the same class contract available to isolated admin previews. Editors can see the column relationships and richer cell forms before publishing, while the public CSS remains the canonical presentation. I did not try to reproduce every viewport inside the editing screen; the preview communicates structure, and browser verification owns responsive behavior.
I also documented literal pipes and mixed rich-cell syntax because delimiter formats become frustrating when the escape rules are tribal knowledge. The authoring guide shows the simple path first and promotes nested cells only when content actually needs them. Good flexibility should not make the common three-column table feel like programming.
What I would decide before building the next one
- What comparison task does the wide layout support?
- What single-row task matters on a phone?
- Which content forms are allowed, and how are dimensions validated?
- Can essential content remain available without JavaScript?
- Which existing markup or saved content must remain compatible?
The implementation ended up larger than a “table shortcode,” but the extra code was not decorative. It encoded the editorial contract and the two reading modes. That is the lesson I am keeping: responsive design is sometimes not a rearrangement of one interface. It is a careful translation between two interfaces that must never disagree about the data.
Written by
Adrian Saycon
A developer with a passion for emerging technologies, Adrian Saycon focuses on transforming the latest tech trends into great, functional products.


