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/uiThe 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:
@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:
:root {
--fde-background: var(--color-fd-background);
--fde-primary: var(--color-fd-primary);
/* ... */
}Render it
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:
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:
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/ui | The React editor. The only package you install directly. |
@fumadocs-editor/core | Parse, serialize, specs, file sync, collab, auth. Pulled in by ui. |
@fumadocs-editor/studio | Standalone app: edit a Fumadocs site's documents from the terminal. |
Next steps
Last updated on