Skip to content

Repository files navigation

@nkzw/mdx-editor

A fast, polished inline Markdown editor for React. It is a maintained fork of @mdxeditor/editor with upgraded Lexical internals and editing behavior tuned for keyboard-first document and comment authoring.

Install

pnpm add @nkzw/mdx-editor
import { MarkdownEditor } from '@nkzw/mdx-editor'
import '@nkzw/mdx-editor/styles.css'

export function Editor() {
  const [markdown, setMarkdown] = useState('# Hello')

  return <MarkdownEditor onChange={setMarkdown} value={markdown} />
}

The default editor includes headings, lists, quotes, links, tables, thematic breaks, fenced code blocks, Markdown shortcuts, and canonical Markdown serialization. It intentionally has no toolbar.

Embedded editors

<MarkdownEditor
  colorScheme="inherit"
  density="compact"
  onChange={setDraft}
  value={draft}
  variant="embedded"
/>

Use onKeyDown for host application shortcuts and onHeightChange when the editor lives inside a virtualized layout.

Read-only paragraphs and list items use the browser's default wrapping unless you opt into presentation-oriented wrapping:

<MarkdownEditor readOnly readOnlyTextWrap="pretty" value={markdown} />

readOnlyTextWrap is applied only while readOnly is true, so it does not enable optimized paragraph or list wrapping while typing.

Persistence

File and network synchronization are optional:

import {
  PersistentMarkdownEditor,
  type MarkdownPersistenceAdapter
} from '@nkzw/mdx-editor/persistence'

const adapter: MarkdownPersistenceAdapter<Document> = {
  async save({ content, document, keepalive }) {
    // Save with document.version as the optimistic concurrency token.
    return { document: await save(content, document, keepalive), status: 'saved' }
  }
}

The persistence layer includes debounced saves, a maximum save wait, lifecycle flushing, optimistic concurrency, same-content conflict suppression, disk update reconciliation, and default conflict/error UI.

Annotations

Hosts can attach repairable block or exact-text annotations without changing the serialized Markdown:

const editorRef = useRef<MarkdownEditorHandle>(null)

<MarkdownEditor
  activeAnnotationId={activeId}
  annotations={annotations}
  onAnnotationAnchorChange={updateAnchor}
  onAnnotationLayoutChange={updateLayout}
  onCommentTargetChange={setCommentTarget}
  ref={editorRef}
  value={markdown}
/>

Use editorRef.current.createAnnotation(id, target) to capture the current selection or block, focusAnnotation(id) to reveal it, and removeAnnotation(id) to clear its editor metadata. Persist the returned anchors in the host application. Annotation marks are excluded from Markdown export and repair themselves from structural and quoted-text context after the document is replaced.

Styling

Defaults reproduce the original Notes document editor. Override variables on the editor class:

.comment-editor {
  --mdx-editor-bg: transparent;
  --mdx-editor-border: transparent;
  --mdx-editor-font-size: 13px;
  --mdx-editor-line-height: 1.45;
  --mdx-editor-padding: 9px 10px 10px;
}

The primary variables are --mdx-editor-bg, --mdx-editor-border, --mdx-editor-text, --mdx-editor-muted, --mdx-editor-accent, --mdx-editor-accent-contrast, --mdx-editor-accent-soft, --mdx-editor-annotation-bg, --mdx-editor-annotation-active-bg, --mdx-editor-code-bg, --mdx-editor-hover, --mdx-editor-selection, --mdx-editor-table-border, --mdx-editor-table-stripe, --mdx-editor-font, --mdx-editor-mono-font, --mdx-editor-radius, --mdx-editor-padding, --mdx-editor-font-size, --mdx-editor-line-height, and --mdx-editor-read-only-text-wrap.

Advanced API

The complete low-level fork is available from:

import { MDXEditor, realmPlugin } from '@nkzw/mdx-editor/core'

See UPSTREAM.md for the upstream baseline and maintained patch set.

License

MIT. Original MDXEditor copyright and license are retained in LICENSE.

About

A fork of mdxeditor.dev

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages