Skip to main content

React Markdown Kit editor vs MDXEditor

MDXEditor is a React component for editing Markdown and MDX, built on Lexical, MIT licensed, with a plugin for every feature. This page compares it with @react-markdown-kit/editor, which is also built on Lexical and edits Markdown only.

The short version: if your content is MDX with JSX components in it, use MDXEditor. If your content is Markdown and the files must come back unchanged, read on.

Facts about MDXEditor come from its documentation and its repository. Facts about this editor link to the code or the test that backs them.

MDXEditorReact Markdown Kit editor
ContentMarkdown and MDX, including JSX componentsMarkdown: CommonMark, plus GFM through a preset
Editing engineLexicalLexical
Value in and outMarkdown stringMarkdown string
CompositionPlugins passed in a plugins arrayA preset shared with the renderer, plus extensions
Round tripNo published byte-identity corpus found22 of 22 byte-identical (test)
Gzipped JS for the entry163.1 KB (4.2.5)110.3 KB (0.1.0)
Server renderingClient componentClient component; the renderer is a separate package that server-renders
LicenceMITMIT

Editing model

Both editors put a Lexical surface in front of the user, and both keep the document as Markdown in your state.

MDXEditor composes features as plugins: headingsPlugin(), listsPlugin(), tablePlugin(), jsxPlugin() and so on, passed in a plugins array. Nothing is on until you turn it on, and the toolbar is itself a plugin.

<MDXEditor markdown={value} onChange={setValue} plugins={[headingsPlugin(), listsPlugin()]} />

React Markdown Kit composes the dialect instead, in a preset that the renderer and the editor share, so the editor writes exactly what your pages read.

import { defineMarkdownPreset, gfm } from '@react-markdown-kit/renderer'

const appMarkdown = defineMarkdownPreset({ extensions: [gfm()] })

<MarkdownEditor preset={appMarkdown} value={value} onChange={setValue} />

The editing surface then follows the dialect. There is no list of features to keep in sync with the renderer, because there is one preset and one parser for both.

The practical difference: MDXEditor gives you finer control over which editing features exist; this kit gives you a guarantee that preview and production render the same way, since preview delegates to @react-markdown-kit/renderer rather than a second renderer.

Loading editor

Output format

Both hand back a Markdown string, so neither locks your content into editor JSON.

The difference is what counts as valid content. MDXEditor accepts MDX: JSX elements, import and export statements, and expressions, with JSX handled by its JSX plugin and described by a component descriptor you supply. This kit has no MDX support and no plan for one. A JSX element in the source is not a component here; it is an HTML block, preserved as an opaque node and written back as the bytes it came from.

If your documents are .mdx files with components inside them, that is the deciding line and MDXEditor is the right tool.

Round trip

This is the section the kit exists for.

Open a document, switch modes, close it without typing. The file must be identical. The kit keeps the original source and the byte span of every top-level block, and writes unchanged blocks back from those bytes instead of re-serializing them.

The corpus is 22 documents that a line-oriented editor damaged on save, from docs/AUDIT.md:

We found no equivalent published corpus for MDXEditor, so this table says "not found", not "fails". The fixture is plain JSON with a cases array of { name, source, why }, and nothing in it is specific to this package, so you can run it against MDXEditor in an afternoon and publish the result. How to run the suite on your own documents

Bundle

Measured by scripts/compare-bundles.mjs and stored in docs/data/bundle-sizes.json, on 2026-09-20. Each row is the whole import closure of the recorded entry, bundled with esbuild 0.27.7, minified, tree-shaken, with React and React DOM external. 1 KB is 1024 bytes.

PackageVersionMinifiedGzipped
@react-markdown-kit/editor0.1.0349.7 KB110.3 KB
@mdxeditor/editor4.2.5511.3 KB163.1 KB

That is 52.8 KB less gzipped JavaScript for the kit's entry. Two caveats keep the number honest. The kit's row includes @react-markdown-kit/renderer, which is bundled in because the editor imports it. Neither row includes CSS: both packages ship an optional stylesheet that the measured entry does not import, and the generator records CSS separately when a bundle emits any.

The row that matters more for most applications is the one that is not here. A page that only displays Markdown imports the renderer and never loads the editor: 36.8 KB gzipped for CommonMark, 48.5 KB with the GFM preset. The renderer

Server rendering

Neither rich surface server-renders. Selection, undo history and keyboard handling need a DOM, so both components are client components, and MDXEditor's Next.js instructions load it through dynamic() with ssr: false.

Where the two differ is what a server page has to import. In this kit the renderer and the editor are separate packages with separate installs, so a server-rendered document page imports @react-markdown-kit/renderer, carries no "use client" boundary, and pulls no Lexical into the server bundle. Server rendering

There is also a Node path for the editor itself, with no DOM at all:

import { createMarkdownBridge } from '@react-markdown-kit/editor'

const bridge = createMarkdownBridge({ preset: appMarkdown, headless: true })
bridge.load(source)
const saved = bridge.getMarkdown()

That is the pipeline the React editor runs, on @lexical/headless. It is how the round trip is tested, and it is available for a migration script or a content check in CI.

Lexical versus Lexical

Both editors chose the same engine, so the engine is not the difference. Two things about how each wraps it are.

Where Markdown is parsed. This kit parses with micromark into mdast, the same pipeline the renderer uses, and keeps mdast as the document representation. @lexical/markdown and its line-oriented transformer protocol are not used anywhere in the package, because that protocol is the root cause listed in the audit.

Whether Lexical is in your types. Nothing the root entry exports requires a Lexical type. A test asserts that src/index.ts and src/types.ts import nothing from lexical or @lexical/* (test). The opt-in @react-markdown-kit/editor/lexical entry is the exception, for extension authors. The single escape hatch, editor.getNativeEditor(), returns unknown, so you cast it yourself and the engine never leaks into your types by accident. That keeps the door open to replacing the engine later without a breaking change to the rest of the API. How the kit wraps Lexical

Migration

The component boundary is small, so the swap is mostly mechanical.

// before
import { MDXEditor, headingsPlugin, listsPlugin, quotePlugin } from '@mdxeditor/editor'
import '@mdxeditor/editor/style.css'

<MDXEditor markdown={value} onChange={setValue} plugins={[headingsPlugin(), listsPlugin(), quotePlugin()]} />
// after
import { MarkdownEditor } from '@react-markdown-kit/editor'
import { defineMarkdownPreset, gfm } from '@react-markdown-kit/renderer'
import '@react-markdown-kit/editor/styles.css'

const appMarkdown = defineMarkdownPreset({ extensions: [gfm()] })

<MarkdownEditor preset={appMarkdown} value={value} onChange={setValue} />

Four things to check before you commit:

  1. MDX content. If any document contains a JSX element you expect to keep editing as a component, stop here. It will be preserved as an opaque block, not edited.
  2. Plugins to preset. The feature plugins have no one-to-one mapping. Decide the dialect instead: CommonMark, or CommonMark plus gfm(), plus any extension you render with. Presets
  3. Toolbar. The default toolbar is on by default here. toolbar={false} removes it, and a render prop keeps the command items while you supply the markup. Editor basics
  4. Image uploads. onUploadImage(file, { signal, documentKey }) resolves with { src, alt, title }. Your storage, your endpoint. Images

Run the round-trip script over your content directory first. It tells you in one pass whether the new dialect reads everything you already have. The script

Who should stay with MDXEditor

  • Your content is MDX, or you want JSX components editable in place.
  • You want to choose each editing feature independently through plugins, including turning most of them off.
  • You rely on a feature this kit does not have, such as its diff and source view plugin set or its sandpack code blocks.

Who should try this one

  • Your content is Markdown files or Markdown in a database, and a diff of only what the author changed matters to your team.
  • You already render Markdown with React and want the editor to write exactly that dialect.
  • You want the editor package out of the server bundle and out of the pages that only display content.
  • You want the round trip to be a test you can run, not a promise.

FAQ

Is there an alternative to MDXEditor for React?

Yes. @react-markdown-kit/editor is a rich, source and preview Markdown editor for React, also built on Lexical. It edits CommonMark and GFM, not MDX, and it asserts byte identity for 22 audited documents opened and saved without an edit.

Does React Markdown Kit edit MDX and JSX components?

No. It edits Markdown. MDXEditor parses and edits MDX, including JSX components and imports, which is what its name and its JSX plugin are for. If your content is MDX, that is a reason to stay with MDXEditor.

Which editor bundle is smaller?

The measured import closure of @react-markdown-kit/editor 0.1.0 is 110.3 KB gzipped against 163.1 KB for @mdxeditor/editor 4.2.5, a difference of 52.8 KB, with React external. Both rows come from scripts/compare-bundles.mjs.

Can either editor render on the server?

Neither rich editing surface renders on a server, because both need a DOM for selection and keyboard handling. React Markdown Kit splits the packages, so a server-rendered page that only displays Markdown imports the renderer and never loads editor code or Lexical.

Next

Try the editor demo · @react-markdown-kit/editor on npm · @mdxeditor/editor on npm · Source on GitHub

React Markdown editor · Lossless Markdown editing · Compared with Milkdown · Lexical Markdown editor guide