Skip to main content

React Markdown Kit editor vs MDXEditor

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

If your content is MDX with JSX components in it, you should probably use MDXEditor. If it's Markdown and you need the files to come back unchanged, the rest of this page is for you.

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. Everything is off until you turn it on, and the toolbar is a plugin too.

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

React Markdown Kit configures the dialect instead, in a preset the renderer and the editor share, so the editor writes the same Markdown 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 follows from the dialect. You don't have a list of features to keep in sync with the renderer, since both use the same preset and parser.

In practice, MDXEditor gives you finer control over which editing features exist, and this kit makes sure preview and production render the same way, because preview uses @react-markdown-kit/renderer instead of a second renderer.

Loading editor

Output format​

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

Where they differ 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 doesn't support MDX and there's no plan to. A JSX element in the source is treated as an HTML block, kept as an opaque node and written back as the bytes it came from.

If your documents are .mdx files with components inside them, that pretty much decides it and MDXEditor is the right tool.

Round trip​

This is the main reason the kit's editor exists.

If you open a document, switch modes and close it without typing, the file should 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 couldn't find an equivalent published corpus for MDXEditor, so the table says "not found" (we're not saying it 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's 52.8 KB less gzipped JavaScript for the kit's entry, with two caveats. The kit's row includes @react-markdown-kit/renderer, which is bundled in because the editor imports it. And neither row includes CSS, since both packages ship an optional stylesheet that the measured entry does not import, and the generator records CSS separately when a bundle emits any.

For most applications the more relevant number isn't in this table. A page that only displays Markdown imports the renderer and never loads the editor, which is 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

The editor also has a Node path that needs 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's the same pipeline the React editor runs, on @lexical/headless. The round-trip tests use it, and you can use it for a migration script or a content check in CI.

Lexical versus Lexical​

Both editors use the same engine, so the differences are in how each one wraps it. There are two worth knowing about.

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 doesn't end up in your types by accident. That should let us replace the engine later without a breaking change to the rest of the API. How the kit wraps Lexical

Migration​

The component API 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'll be kept as an opaque block and you won't be able to edit it.
  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 }, using whatever storage and endpoint you already have. Images

I'd 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 backed by a test you can run yourself.

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 (no MDX), and its tests check byte identity for 22 audited documents opened and saved without an edit.

Does React Markdown Kit edit MDX and JSX components?

No, it only edits Markdown. MDXEditor parses and edits MDX, including JSX components and imports (that's what its JSX plugin is for). If your content is MDX, I'd 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, since both need a DOM for selection and keyboard handling. React Markdown Kit ships the renderer and editor as separate 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