# Mobile data tables without horizontal scrolling

Use this pattern when the requirement is **no horizontal scrolling at all**, including inside wide comparison, pricing, audit, or source-ledger tables. `overflow-x:auto` is not sufficient for that requirement.

## Preferred pattern: semantic table → stacked records

Keep the semantic `<table>` markup on desktop. At the mobile breakpoint, present each `<tr>` as a vertical record/card:

1. Add a stable label to every body cell when rendering HTML:

```html
<th scope="row" data-label="Provider">QuickNode</th>
<td data-label="Free plan">500k requests/month</td>
<td data-label="Rate limit">15 RPS</td>
```

For Markdown-generated tables, parse the header row once and emit its corresponding text as each body cell's `data-label`. Do this in the renderer, not with brittle client-side DOM inference.

2. Preserve the header row for screen readers but visually hide it on mobile.
3. Make `table`, `thead`, `tbody`, `tr`, `th`, and `td` block-level at the mobile breakpoint.
4. Render each body row as a bordered card and each cell as a two-column label/value grid.
5. Reset desktop width constraints such as `min-width`, sticky first columns, and `white-space: nowrap`.
6. Allow long URLs, code, IDs, and provider notes to wrap with `overflow-wrap:anywhere`.

```css
@media (max-width: 800px) {
  .responsive-table { overflow: visible; border: 0; }
  .responsive-table table,
  .responsive-table thead,
  .responsive-table tbody,
  .responsive-table tr,
  .responsive-table th,
  .responsive-table td {
    display: block;
    width: 100%;
    min-width: 0;
  }
  .responsive-table table { min-width: 0; border-collapse: separate; }
  .responsive-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  .responsive-table tbody { display: grid; gap: 14px; }
  .responsive-table tr { border: 1px solid var(--line); border-radius: 16px; overflow: hidden; }
  .responsive-table td,
  .responsive-table tbody th {
    position: static !important;
    display: grid;
    grid-template-columns: minmax(92px, 34%) minmax(0, 1fr);
    gap: 12px;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .responsive-table td::before,
  .responsive-table tbody th::before {
    content: attr(data-label);
    font-size: 0.72rem;
    font-weight: 800;
    text-transform: uppercase;
  }
}
```

Scope this CSS to the relevant table wrapper whenever possible. A site-wide generic rule can degrade older tables whose cells do not have `data-label` attributes.

## Durability

For generated static sites, patch both:

- the currently served stylesheet/output, so the fix is immediately live; and
- the generator/template that owns that output, so the next scheduled regeneration does not erase it.

Then rerun the generator and verify the public URL. Editing only generated HTML/CSS is temporary; editing only the generator delays the visible fix.

## Verification

Verify at least one widest table and one ordinary content page:

- HTTP response remains successful after regeneration.
- Every mobile body cell has a non-empty `data-label`.
- At a phone viewport, `document.documentElement.scrollWidth <= window.innerWidth`.
- Computed mobile styles show `table min-width: 0`, rows stacked, and desktop sticky columns disabled.
- Take a phone-sized screenshot and inspect label/value readability, wrapping, and card boundaries.
- Recheck desktop layout to ensure the semantic table still renders normally.

Do not treat `html, body { overflow-x:hidden }` as the fix by itself. It can mask clipped content. Use it only as a defensive guard after removing the actual overflow source.