### What’s really happening under the hood 1. **The browser’s “auto” table-layout algorithm** By default (`table-layout: auto`) every column’s width is negotiated between: * **min-content width** – the narrowest the column can get if the text wraps at every possible break. * **max-content width** – the width of the longest unbreakable piece (a long URL, a `superLongVariableName`, etc.). The browser tries to fit the table inside the available block, but if a scroll container (`overflow-x:auto`) says *“don’t worry, the table can spill out horizontally”*, the algorithm happily lets the table grow until it hits something closer to the max-content widths. That’s why you don’t end up with 2-word columns but you also don’t get a single **100-word-wide** column: the browser lands somewhere between the two extremes. 2. **OpenAI’s tweak** ChatGPT wraps each `<table>` in a div that scrolls **and** sets a *reasonable cap* on every cell: ```css td, th { max-width: 40ch; /* ~40 characters before wrapping */ white-space: normal; /* allow wrapping */ overflow-wrap: anywhere; /* break long URLs/words */ } ``` *Short cells stay short, long paragraphs wrap after \~40 characters, and horizontal scroll still kicks in once the total table width exceeds the viewport.* --- ### Bring that behaviour to your Next.js / Docusaurus site #### 1. Global CSS you can drop in today ```css /* 1️⃣ Make tables scroll when needed */ table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; } /* 2️⃣ Let rows grow naturally, but stop cells from getting ridiculous */ table td, table th { max-width: 40ch; /* tweak to taste: 35–50ch feels good */ white-space: normal; /* wrap as needed */ overflow-wrap: anywhere; /* optional polish */ padding: 0.4rem 0.8rem; vertical-align: top; } ``` *Result:* long prose wraps after \~40 characters, URLs break when they have to, and the whole table scrolls horizontally once its total width tops the viewport. #### 2. A reusable MDX component (the nice-to-maintain way) ```tsx // components/ScrollableTable.tsx export default function ScrollableTable( props: React.TableHTMLAttributes<HTMLTableElement> ) { return ( <div className="overflow-x-auto my-4 -mx-4"> <table {...props} className="min-w-full border-collapse prose-table" /> </div> ); } ``` Then shadow/override the `<table>` element just once: * **Next.js (with `@mdx-js/react` or `next-mdx-remote`)** ```tsx import { MDXProvider } from '@mdx-js/react'; import ScrollableTable from '@/components/ScrollableTable'; const components = { table: ScrollableTable }; export default function MyApp({ Component, pageProps }) { return ( <MDXProvider components={components}> <Component {...pageProps} /> </MDXProvider> ); } ``` * **Docusaurus v2** ```jsx // src/theme/MDXComponents.js import React from 'react'; import MDXComponents from '@theme-original/MDXComponents'; import ScrollableTable from '@site/src/components/ScrollableTable'; export default { ...MDXComponents, table: ScrollableTable, }; ``` Add the same CSS from the previous step (or Tailwind equivalents like `max-w-[40ch]` and `break-words`) and every markdown table now behaves like ChatGPT’s—no matter who writes the docs. --- ### Fine-tuning knobs you can play with | What you want | Tweak | | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | **Narrower / wider wrap** | Change `max-width: 35ch` … `50ch` or use `em` units. | | **Keep header sticky** | In the scroll wrapper add `position: relative`; then:<br>`thead th { position: sticky; top: 0; background: var(--ifm-background-color); }` | | **Don’t wrap code blocks inside cells** | `td code { white-space: nowrap; }` | | **A11y for keyboard users** | Give the wrapper `role="region"` and an `aria-labelledby` linking to a `<caption>` or heading so screen-reader users know they can scroll. | --- **TL;DR** Put your table inside a horizontal-scroll wrapper **and** cap each cell’s width (`max-width: 40ch; overflow-wrap:anywhere;`). That yields the same “sensible middle ground” ChatGPT uses—easy to scan, impossible to break your layout.