Rendering Tables
GFM syntax
In Markdown, it is preferable to write tables via GFM syntax.
| left   | center | right |
| :----- | :----: | ----: |
| foo    |  bar   |   baz |
| banana | apple  |  kiwi |will be rendered as:
| left | center | right | 
|---|---|---|
| foo | bar | baz | 
| banana | apple | kiwi | 
HTML Literal Tables
If you try to render the following literal <table /> element:
<table>
  <thead>
    <tr>
      <th>left</th>
      <th align="center">center</th>
      <th align="right">right</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>foo</td>
      <td align="center">bar</td>
      <td align="right">baz</td>
    </tr>
    <tr>
      <td>banana</td>
      <td align="center">apple</td>
      <td align="right">kiwi</td>
    </tr>
  </tbody>
</table>you’ll get the following result:
| left | center | right | 
|---|---|---|
| foo | bar | baz | 
| banana | apple | kiwi | 
Confused by unstyled elements? We explained here, why this happens.
Dynamic Tables
How to Write
Want to render a dynamic table? You can use embedded JavaScript expressions into your table for it:
<table>
  <thead>
    <tr>
      <th>Country</th>
      <th>Flag</th>
    </tr>
  </thead>
  <tbody>
    {[
      { country: 'France', flag: '🇫🇷' },
      { country: 'Ukraine', flag: '🇺🇦' }
    ].map(item => (
      <tr key={item.country}>
        <td>{item.country}</td>
        <td>{item.flag}</td>
      </tr>
    ))}
  </tbody>
</table>will be rendered as:
| Country | Flag | 
|---|---|
| France | 🇫🇷 | 
| Ukraine | 🇺🇦 | 
Confused by unstyled elements? We explain below 👇 why it happens.
Unexpected Result
Table looks different compared to GFM syntax table:
- 
only children of table body
<tbody />is styled - 
table header is unstyled
 - 
table doesn’t have margin top
 
Why This Happens
MDX2 doesn’t replace literal HTML elements with <MDXProvider />.
Adam Wathan, creator of Tailwind CSS submitted an issue in MDX2 to have some an escape hatch that we can name like:
please only transform markdown tags, not literal HTML tags
Table header looks unstyled since it has not been replaced with Nextra’s MDX
components <tr />, <th /> and <td />, for the same
reason <table /> literal is not replaced and doesn’t have default
margin-top aka mt-6.
Ways to Fix It
One-Time Fix
Just wrap your table with curly braces { and }, e.g.
{<table>
  ...
</table>}Changing Default Behaviour
If this thing is still confusing for you, and you want to use regular literal HTML elements for your tables, do the following:
Install remark-mdx-disable-explicit-jsx package
npm i remark-mdx-disable-explicit-jsxSetup
Configure plugin in nextra function inside next.config.mjs file
import nextra from 'nextra'
import remarkMdxDisableExplicitJsx from 'remark-mdx-disable-explicit-jsx'
 
const withNextra = nextra({
  theme: 'nextra-theme-docs',
  themeConfig: './theme.config.tsx',
  mdxOptions: {
    remarkPlugins: [
      [
        remarkMdxDisableExplicitJsx,
        { whiteList: ['table', 'thead', 'tbody', 'tr', 'th', 'td'] }
      ]
    ]
  }
})
 
export default withNextra()