MDX Formatter

A Markdown file always renders. An MDX file compiles or fails, because every angle bracket and every curly brace is handed to a JavaScript parser. Paste your document to get consistent JSX indentation, one clean import block, and a plain list of the things the compiler will reject.

MDX formatting workspace

Source

Formats in place. Nothing is uploaded.

Press Ctrl + S to format. The editor keeps its undo history, so one Ctrl + Z returns the original.

Compile risks

nothing blocking

    Document shape

    • 0Imports
    • 0Components
    • 0JSX blocks
    • 0Expressions
    • 0Headings
    • 0Code fences
    • 0Max nesting
    • 0Words

    Markdown forgives. MDX compiles.

    Write a stray angle bracket in a Markdown file and the renderer prints something reasonable. Write the same character in MDX and the build stops with a parse error pointing at a line you thought was ordinary prose. The reason is structural: MDX hands your document to a JavaScript parser, so a document is also a module. Formatting here means two jobs at once, making the JSX readable and telling you which characters the parser will refuse.

    The angle bracket that ends a build

    Any < followed by a letter starts a tag. Follow one with a space or a digit and the parser still tries, then reports an unexpected character further down the file. Comparisons in prose are where this bites most often, because nothing looks wrong while you type.

    Fails to compile
    Any cost below 100 is fine,so treat 40 < 100 as a pass.
    Compiles
    Any cost below 100 is fine,so treat `40 < 100` as a pass.

    Backticks are the fix worth reaching for first, since inline code is exempt from JSX parsing and reads better anyway. The HTML entity works too. The checks panel flags bare brackets with a line number rather than rewriting them, because a bracket in prose might be a tag you forgot to finish, and guessing between those two would corrupt your document.

    Curly braces are executable

    In MDX a brace opens a JavaScript expression, in prose as much as inside a tag. That makes {count} a variable lookup and {use the flag} a syntax error. Documentation about templating languages, shell scripts, or CSS suffers the most here, since those subjects put braces in sentences constantly.

    Escape a literal brace with a backslash, written as \{, or wrap the passage in backticks. The panel above reads the contents of every brace pair and only warns when what is inside fails to look like an expression. A brace holding props.title passes without comment. A brace holding a sentence gets flagged.

    Comments changed spelling in MDX 2

    The HTML comment syntax was valid in MDX 1 and is a parse error in MDX 2, which is the single most common breakage when an old docs folder moves to a current toolchain. JSX comments live inside an expression instead.

    <!-- migrated from the old docs site -->{}

    Leave the first toggle on and every comment converts during formatting, with a count in the checks list so you know how many the file carried.

    Imports belong at column one

    An import statement is only a statement when nothing precedes on the line. Indent one by two spaces, drop one inside a list item, and MDX treats the line as paragraph text. Your component then renders as literal characters, or the page fails on a missing reference, with no error naming the import.

    Formatting collects every single line import and export, dedupes them, normalises the specifier spacing and quote style, then places the block directly under the frontmatter. Order is preserved rather than sorted alphabetically, because import order carries meaning when a module has side effects.

    A statement spread across several lines stays exactly where you wrote it, character for character. Collapsing one onto a single line would destroy a trailing comment inside the braces, and no amount of tidy import blocks is worth that.

    Attributes are props with JavaScript names

    Anything inside a tag follows JSX naming, not HTML naming. These four rewrites happen automatically. The fifth needs a human, since converting a CSS string into an object involves choices a text pass should not make on your behalf.

    Written as HTMLRequired by MDXWhat happens otherwise
    class="grid"className="grid"React drops the attribute and logs a warning
    for="email"htmlFor="email"The label stops pointing at its field
    tabindex="0"tabIndex="0"Keyboard focus order silently ignores the element
    <br><br />Parse error, since JSX has no void tags
    style="gap: 12px"style={{ gap: 12 }}Flagged for you to convert, never rewritten

    Why prose stays flush left

    Most formatters indent everything inside a component, prose included. That reads nicely until nesting reaches two levels, where four leading spaces turn a paragraph into an indented code block. Markdown rules still apply inside MDX, so the text renders in a grey box and nobody knows why.

    This formatter indents structural lines only, meaning tags and expressions. Paragraphs, list items and headings inside a component stay at column one. Diffs come out smaller and no amount of nesting depth changes how your prose renders. If your team runs Prettier on MDX in CI, expect a difference on exactly this point and pick one of the two rather than alternating.

    What the checks panel reports

    Where this page stops

    Format before the commit rather than while writing. Reformatting a file a teammate has open produces a conflict on every line, and MDX diffs are already noisier than Markdown diffs because of the tag indentation. Agree on the indent width once per repository and leave the setting alone after that.

    MDX formatting questions

    What the formatter rewrites, what refuses to be automated, and how the checks differ from a real build.

    Why does my file work on the docs site but fail here, or the other way round?

    Every MDX setup is a compiler plus a plugin list. Docusaurus, Next.js and Astro each ship a different default set, so admonition syntax, directives and math blocks are valid in one and unknown in another. This page assumes plain MDX 2 with frontmatter. Anything your plugins add passes through as text and shows up in the checks panel as a brace or bracket warning. Read those entries against your own config before acting on them.

    What broke when we upgraded from MDX 1 to MDX 2?

    Four changes account for most of the failures. HTML comments became invalid. Bare angle brackets and stray braces in prose became parse errors instead of text. JSX and Markdown stopped mixing on the same line without a blank line between blocks. Imports stopped working when indented. Load the Legacy MDX 1 sample above to see all four in one file, then press Format to watch which of them repair automatically and which need a decision from you.

    Does formatting change what the page renders?

    Indentation, import spacing and quote style are invisible to the output. Two repairs do alter rendering, both for the better: a comment that failed to compile starts working, and a void tag that failed to parse starts rendering. The blank line inserted between prose and a top level component changes nothing visually while making the block boundary explicit for the parser.

    Why does it write over my source instead of showing output in a second pane?

    MDX documents are long, and comparing two scrolling panes to find three changed lines is slower than reading a status line saying how many lines moved. The editor keeps full undo history, so Ctrl+Z restores the original in one keystroke. Copy the source out first if you want to diff the two versions in your own editor.

    A component of mine is flagged as never imported, but the page works.

    Components provided globally through an MDXProvider or a components prop are resolved at render time rather than in the file, so no import exists to find. That warning is expected on any project using a shared component layer. Treat it as a reminder of which tags depend on the provider being wired up, which matters when the file moves to another site.

    Can I keep prose indented inside my components?

    Not through this page. Structural lines get indented and text lines stay at column one, with no setting to change the behaviour. The reasoning is in the section above: indented paragraphs inside nested components become Markdown code blocks at four spaces. Prettier makes the opposite choice and manages the risk differently. Pick whichever tool your CI runs and stay with it.

    Is my content sent anywhere?

    No. The parser, the checks and the statistics are JavaScript running in this tab. The only network requests happen at page load, for the editor library. Once the page is open you could disconnect and every button still works. Nothing persists between visits, so closing the tab discards what you pasted.

    What is the difference between this and the Markdown formatter?

    The Markdown formatter normalises bullets, renumbers lists, aligns table pipes and reports heading and anchor problems, treating any tag as opaque text. This page parses tags, tracks nesting, resolves component names against imports and reports the errors that stop a build. Use the Markdown formatter on a README. Use this one on any file where a component appears.

    Why did my import move above a paragraph I had it under?

    Single line imports are hoisted into one block below the frontmatter. Position has no effect on behaviour at the top level, and a single block is faster to audit than statements scattered through 300 lines. Relative order is preserved, so a module imported for its side effects still runs in sequence. Anything spanning multiple lines stays where you put it, which is the safe choice when braces hold comments.