How to make a table responsive with scrolling
Short answer
Wrap the table in a block with overflow-x: auto — on a narrow screen horizontal scrolling appears inside the block rather than on the whole page:
<style>
.table-wrap { overflow-x: auto; max-width: 300px; border: 1px solid silver; }
table { border-collapse: collapse; }
th, td { padding: 6px 12px; white-space: nowrap; text-align: left; }
</style>
<div class="table-wrap" tabindex="0" role="region" aria-label="Price list">
<table>
<tr><th>Plan</th><th>Storage</th><th>Users</th><th>Support</th><th>Price</th></tr>
<tr><td>Basic</td><td>10 GB</td><td>1</td><td>Email</td><td>$5</td></tr>
<tr><td>Team</td><td>100 GB</td><td>10</td><td>Chat</td><td>$25</td></tr>
</table>
</div>white-space: nowrap keeps the cells from shrinking into narrow columns with one word per line.
Scrolling from the keyboard
The tabindex="0" attribute lets the wrapper be selected with Tab and scrolled with the arrows. Together with it, role="region" and aria-label are set so a screen reader explains what the area is.
Other options
On a phone a table can be rebuilt into cards: a media query turns rows into blocks, and the headings are shown next to the values. That is harder, and scrolling fits most cases.
Common mistake
overflow-x: auto is put on the table itself. This property does not work on a <table> element: the table still stretches past the screen, and the whole page scrolls. A wrapper is needed — a plain <div>.
Functions used in this recipe
- overflow — What to do with content that does not fit into the element.
- <table> — A table made of rows (`<tr>`) and cells.
- white-space — How spaces and line breaks in the source are handled and whether lines may wrap.
- tabindex — Controls whether an element can be reached with the Tab key.