Skip to content
JamdeskUtilities
Updated

MDX Cheatsheet

MDX combines Markdown with JSX. Write content in Markdown the way you always have, then drop in React components and JavaScript expressions wherever you need them: callouts, tabs, dynamic data, anything you can build with React. Because the file compiles to a JavaScript module, MDX works with React, Next.js, Astro, Remix, and Gatsby. The spec lives at mdxjs.com.

Validate your MDX with the MDX Validator or format it with the MDX Formatter.

Markdown basics

Headings

h1 through h6, same as plain Markdown.

# H1
## H2
### H3

Preview headings in the MDX Viewer

Lists

Bulleted with `-` or `*`. Numbered with `1.`; the actual number doesn't matter, since renderers reflow them.

- Item one
- Item two
  - Nested

1. First
2. Second

Links and images

Standard Markdown. Use the JSX `<Image>` component when you need optimization or layout control.

[Read the docs](https://mdxjs.com)

![Hero illustration](/hero.png)

Inline formatting

Bold, italic, inline code. Combine them.

**bold**, *italic*, `code`, ***both***

Blockquotes

A `>` at the start of a line. Nest them by stacking.

> A quote.
>
> > Nested.

Code blocks

Triple-backtick fences. Most MDX setups also accept a meta string for titles and line highlights, though support varies by toolchain.

```typescript title="hello.ts" {2}
function hello(name: string) {
  return `Hi, ${name}`
}
```

Convert Markdown to HTML

Tables

Pipes and dashes. Use `:---:`, `:---`, or `---:` to align columns.

| Feature | Markdown | MDX |
|---------|----------|-----|
| JSX     | No       | Yes |
| YAML    | No       | Yes |

Generate tables from CSV

Footnotes

GFM addition. Reference with `[^id]` in the text, define with `[^id]:` at the bottom of the file.

A claim that needs a citation.[^1]

[^1]: Source: <https://example.com>.

GFM extras

GitHub Flavored Markdown adds two everyday extensions: strikethrough with `~~`, and task list checkboxes inside list items.

~~outdated~~

- [x] Done
- [ ] To do

MDX additions

Frontmatter

YAML between `---` delimiters at the top of the file. Parsed by remark-frontmatter, and usually exposed as a `frontmatter` export.

---
title: My Page
description: A short description
---

Validate YAML frontmatter

JS expressions

A single curly brace runs JavaScript. Works in body text and inside JSX attributes.

Year: {new Date().getFullYear()}

<a href={`/posts/${slug}`}>Read more</a>

Escaping curly braces

Body text with a literal `{` or `}` triggers the JSX parser and breaks the build. Wrap them in code spans, or escape with a backslash.

Use \{ and \} for literal braces.

Or put them in `code`: { literal }

Imports

ES module imports at the top of the file. Components, data, even other MDX files.

import { Tabs, Tab } from '@/components/Tabs'
import About from './about.mdx'

Exports

Export metadata or helpers from your file. Frameworks read these at build time.

export const metadata = {
  title: 'My Page',
  date: '2026-04-29',
}

Comments

JSX-style. Stripped from output.

{/* Reminder to update this section after launch. */}

Components and layout

JSX components

Drop any imported React component inline. Self-close when there are no children.

<Callout type="warning">
  Read this first.
</Callout>

<Image src="/hero.png" alt="Hero" width={1200} height={630} />

Catch unclosed JSX tags

Markdown inside components (the gotcha)

Markdown sitting flush against a JSX tag won't render. Leave a blank line and it will. This is the most common MDX bug.

<Callout>
  **Wrong** — sits next to the tag, renders as plain text.
</Callout>

<Callout>

  **Right** — blank line above and below.

</Callout>

Mapping arrays in JSX

Need a generated list? Map inside braces.

<ul>
  {['Docs', 'Blog', 'API'].map((label) => (
    <li key={label}>{label}</li>
  ))}
</ul>

Default export (page-level layout)

Wrap every page in shared chrome by default-exporting a function. Frameworks like Next.js call it with the rest of the file as `children`.

import Layout from '@/components/DocLayout'

export default function Page({ children }) {
  return <Layout>{children}</Layout>
}

Need plain Markdown output? Run your file through the MDX → Markdown converter. It strips imports, exports, and JSX, leaving the Markdown body.

Frequently Asked Questions

What's the difference between MDX and Markdown?
MDX is a superset. It adds imports, exports, and JSX to Markdown. Everything in Markdown still works the same way: headings, lists, code blocks, tables. What is new is rendering React components inline and running JavaScript inside curly braces. MDX compiles to a JavaScript module; plain Markdown compiles to HTML.
How do I use Markdown inside an MDX component?
Leave a blank line between the component's tag and the Markdown content. Putting <Callout>**bold**</Callout> on a single line renders as plain text. The same content with a blank line above and below renders the bold correctly. It's the most common MDX bug, and it trips up almost everyone the first time.
Does MDX support TypeScript?
Yes, indirectly. MDX itself has no TypeScript syntax. You can't write `: string` in an MDX file. The components, helpers, and data you import are TypeScript files, though, and your toolchain's compiler type-checks them as usual. Type the imports, not the MDX file.
Why do I need a cheatsheet if MDX is just Markdown plus JSX?
Roughly, yes. Frontmatter parsing depends on a remark plugin, JSX adjacent to Markdown doesn't render the way you'd expect, and code-block meta strings vary by toolchain. This page exists because those edges cost an hour the first time you hit them.

Maintained by Jamdesk · Last reviewed