Fumadocs Editor

Quick Start

A WYSIWYG editor for Fumadocs MDX

Experimental

This project is still in early stage, breaking changes expected for future v1 release.

Fumadocs Editor renders an MDX file as an editable page. Prose, code blocks, tables and MDX components are all edited in place, and the file stays the source of truth: blocks you did not touch serialize byte-for-byte, so a one-line edit stays a one-line diff.

Installation

Try it without code

npx @fumadocs-editor/studio opens an editor for the documents of a Fumadocs app from the terminal. See Studio.

Install the package

npm install @fumadocs-editor/ui

The editor needs React 19. It is a client component: in a server-rendered app, mount it from a file marked 'use client'.

Add the styles

One stylesheet, no build plugin. The editor is styled with StyleX, compiled ahead of time, and never depends on your CSS setup:

app.css
@import "@fumadocs-editor/ui/styles.css";

It ships a neutral palette as --fde-* variables, with a .dark block for the dark theme. To match a Fumadocs site, alias them to the site's tokens after the import:

app.css
:root {
  --fde-background: var(--color-fd-background);
  --fde-primary: var(--color-fd-primary);
  /* ... */
}

Render it

editor.tsx
import { MdxEditor } from "@fumadocs-editor/ui";

export function EditorPage({ source }: { source: string }) {
  return (
    <MdxEditor
      defaultValue={source}
      onChange={(markdown) => {
        // persist it wherever your content lives
        console.log(markdown);
      }}
    />
  );
}

defaultValue is the initial MDX; the editor is uncontrolled after that, like <textarea defaultValue>. onChange receives the serialized MDX, debounced. Prefer pulling? Call ref.getMarkdown() instead.

What is editable

Out of the box the editor knows the fumadocs-ui components: Callout, Cards, Tabs, Steps, Accordions, Files, TypeTable, GithubInfo and <include>. Each renders in place with its own editable regions, a slash-menu entry and an attributes panel. Code blocks are highlighted, a mermaid fence renders its diagram below the source, and frontmatter is edited in place as YAML.

Anything else still round-trips. A component without a spec shows as a neutral card and is edited as source. Syntax the editor does not understand is preserved verbatim rather than reformatted.

Saving to disk

onChange is enough when you own the persistence. If your documents are files in a repository, sync runs the read, autosave and merge loop for you:

editor.tsx
import { MdxEditor } from "@fumadocs-editor/ui";

export function SyncedEditor({ path }: { path: string }) {
  return <MdxEditor sync={{ path }} />;
}

Theming

The --fde-* tokens follow a .dark class on an ancestor, so a Fumadocs or next-themes site themes the editor with no extra setup. Standalone, wrap it in EditorThemeProvider:

standalone.tsx
import { EditorThemeProvider, MdxEditor } from "@fumadocs-editor/ui";

export function StandaloneEditor({ source }: { source: string }) {
  return (
    <EditorThemeProvider>
      <MdxEditor defaultValue={source} />
    </EditorThemeProvider>
  );
}

The provider tracks light | dark | system, persists the choice to localStorage and sets the class on a wrapper. Pin a single editor with theme="light" or theme="dark".

Packages

Package
@fumadocs-editor/uiThe React editor. The only package you install directly.
@fumadocs-editor/coreParse, serialize, specs, file sync, collab, auth. Pulled in by ui.
@fumadocs-editor/studioStandalone app: edit a Fumadocs site's documents from the terminal.

Next steps

Last updated on

On this page