Snippets /
Responsive table
A data table that collapses into stacked cards on narrow containers using container queries.
| Name | Role | Status |
|---|---|---|
| Alice Chen | Engineer | Active |
| Bob Rivera | Designer | Away |
| Carol Tanaka | PM | Active |
Quick implementation
.table-wrap {
container-type: inline-size;
}
.responsive-table {
width: 100%;
border-collapse: collapse;
}
.responsive-table th {
text-align: left;
padding: 0.6rem 0.75rem;
font-weight: 600;
color: oklch(0.65 0.02 260);
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.responsive-table td {
padding: 0.6rem 0.75rem;
border-bottom: 1px solid oklch(0.25 0.01 260);
}
.responsive-table td::before {
content: attr(data-label);
display: none;
font-weight: 600;
color: oklch(0.65 0.02 260);
font-size: 0.75rem;
text-transform: uppercase;
}
@container (max-width: 32rem) {
.responsive-table thead { display: none; }
.responsive-table tr {
display: block;
padding: 0.75rem 0;
border-bottom: 1px solid oklch(0.25 0.01 260);
}
.responsive-table td {
display: flex;
justify-content: space-between;
gap: 1rem;
padding: 0.3rem 0.75rem;
border-bottom: none;
}
.responsive-table td::before {
display: inline;
}
}
Prompt this to your LLM
Paste this into ChatGPT, Claude, or any code-generating model to scaffold the pattern instantly.
Create a responsive data table using CSS container queries.
Wrap the table in a div with container-type: inline-size.
At full width, display a normal table with header row. When
the container is narrower than 32rem, hide the thead and
make each tr a block with each td displayed as flex with
space-between. Use td::before with content: attr(data-label)
to show the column header inline. Each td in the HTML needs
a data-label attribute matching its column header. Use
oklch() colors throughout.
Why this matters
Tables are notoriously difficult to make responsive. Horizontal scrolling is a poor experience, and simply shrinking column widths makes text unreadable. This pattern collapses each row into a mini-card where each cell is labeled, preserving all data in a mobile-friendly stack. Using container queries instead of media queries means the table adapts based on its parent's width, not the viewport, making it work inside sidebars and modals too.
The logic
The wrapper element is declared as an inline-size container with container-type: inline-size. Inside the @container query at max-width: 32rem, the <thead> is hidden with display: none. Each <tr> becomes display: block so it stacks vertically. Each <td> becomes display: flex with justify-content: space-between, creating a label-on-left, value-on-right layout. The ::before pseudo-element reads the data-label attribute to show the original column name, replacing the hidden header.
Accessibility & performance
The <table> element retains its semantic structure at all sizes; only the visual presentation changes. Screen readers still navigate by rows and cells. The data-label pseudo-element content is not exposed to all assistive technology, but the actual cell data in the DOM remains accessible. Use scope="col" on <th> elements for proper header association. Container queries are well-supported in modern browsers and have negligible performance impact since they only evaluate when the container resizes.