# Wide Tables Need a Scroll Wrapper or Cards

**SHOULD** · **ID:** `layout-responsive-table-overflow` · **Category:** layout
**Source:** Custom
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/layout-responsive-table-overflow

> SHOULD: A table wider than the viewport must not widen the page. Wrap it in an overflow-x:auto container so only the table scrolls, or reflow rows into label–value cards on narrow screens. Add an edge fade/shadow so the scroll is discoverable, and keep the header reachable.

A table wider than the viewport must scroll inside its own overflow-x container or reflow to cards — never push the whole page wide

A table sizes to its columns, and on a phone a real data table is almost always wider than the screen. Left alone it does the worst possible thing: it stretches its containing block, so the WHOLE page gains a horizontal scrollbar and every other element overflows with it — now the body copy scrolls sideways to reveal nothing. Two correct fixes. Wrap the table in an `overflow-x: auto` container so ONLY the table scrolls, within its own bounds, while the page stays put — this is the specific, useful case that layout-no-excessive-scrollbars carves out (a scrollbar on the one thing that genuinely needs it). Or, for the best small-screen result, reflow each row into a stacked card of label–value pairs, so there is no horizontal scroll at all. Give the scroll container an edge affordance (a fade or shadow) so people know more is there, and keep the header reachable. This is the inverse framing of layout-no-excessive-scrollbars: that rule says do not create scrollbars you do not need; this one says when a table truly needs one, contain it to the table instead of the page.

## Rule snippet

```tsx
<div class="overflow-x-auto"><table>…</table></div>
```

## Bad — do not do this

`layout-responsive-table-overflow-bad`

```tsx
const ROWS = [
  ['#1042', 'Alicia Moreno', 'alicia@example.com', 'Pro', '2026-03-14', '$1,240.00'],
  ['#1043', 'Ben Ndlovu', 'ben@example.com', 'Team', '2026-03-15', '$4,900.00'],
];

export function ResponsiveTableOverflowBad() {
  return (
    <div className="w-full max-w-sm">
      {/* No wrapper: the wide table stretches its container and breaks the layout */}
      <div className="rounded-lg border border-border bg-card p-3">
        <table className="w-max text-left text-xs">
          <thead className="text-muted-foreground">
            <tr>
              {['Order', 'Customer', 'Email', 'Plan', 'Date', 'Total'].map((h) => (
                <th key={h} className="whitespace-nowrap px-3 py-1.5">{h}</th>
              ))}
            </tr>
          </thead>
          <tbody className="text-foreground">
            {ROWS.map((r) => (
              <tr key={r[0]} className="border-t border-border">
                {r.map((c, i) => (
                  <td key={i} className="whitespace-nowrap px-3 py-1.5">{c}</td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <p className="mt-4 text-xs text-destructive">
        With no wrapper the table pushes past its card — on a phone this widens the whole page.
      </p>
    </div>
  );
}
```

## Good — do this

`layout-responsive-table-overflow-good`

```tsx
const ROWS = [
  ['#1042', 'Alicia Moreno', 'alicia@example.com', 'Pro', '2026-03-14', '$1,240.00'],
  ['#1043', 'Ben Ndlovu', 'ben@example.com', 'Team', '2026-03-15', '$4,900.00'],
];

export function ResponsiveTableOverflowGood() {
  return (
    <div className="w-full max-w-sm">
      <div className="rounded-lg border border-border bg-card p-3">
        {/* Only the table scrolls; the page stays put */}
        <div className="overflow-x-auto">
          <table className="w-max text-left text-xs">
            <thead className="text-muted-foreground">
              <tr>
                {['Order', 'Customer', 'Email', 'Plan', 'Date', 'Total'].map((h) => (
                  <th key={h} className="whitespace-nowrap px-3 py-1.5">{h}</th>
                ))}
              </tr>
            </thead>
            <tbody className="text-foreground">
              {ROWS.map((r) => (
                <tr key={r[0]} className="border-t border-border">
                  {r.map((c, i) => (
                    <td key={i} className="whitespace-nowrap px-3 py-1.5">{c}</td>
                  ))}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
      <p className="mt-4 text-xs text-success">
        An overflow-x-auto wrapper contains the scroll to the table — the surrounding page never widens.
      </p>
    </div>
  );
}
```

## References

- [nextlevelbuilder — ui-ux-pro-max](https://skills.sh/nextlevelbuilder/ui-ux-pro-max-skill/ui-ux-pro-max)
- [MDN — overflow](https://developer.mozilla.org/en-US/docs/Web/CSS/overflow)
- [web.dev — Responsive tables](https://web.dev/articles/responsive-web-design-basics)
