codemirror-live-markdown

March 3, 2026 · View on GitHub

npm version npm downloads CI License: MIT

Obsidian-style Live Preview for CodeMirror 6 — A modular plugin collection that hides Markdown syntax when you're not editing it.

English | 简体中文

Live Demo · Documentation · Roadmap


Why This Library?

Most Markdown editors force you to choose: either see raw syntax or rendered output. Live Preview gives you both — syntax fades in only when your cursor enters, letting you edit naturally while seeing formatted results.

Key differentiators:

  • Modular — Import only what you need (math? tables? code blocks?)
  • Zero lock-in — Works with any CodeMirror 6 setup
  • Lightweight — No heavy dependencies forced on you

Features

FeatureDescriptionSince
✨ Live PreviewHide markers when not editingv0.1.0
📝 Inline FormattingBold, italic, strikethrough, inline codev0.1.0
📑 Block ElementsHeaders, lists, blockquotesv0.1.0
🧮 MathKaTeX rendering (inline & block)v0.2.0
📊 TablesGFM table renderingv0.3.0
💻 Code BlocksSyntax highlighting via lowlightv0.4.0
🖼️ ImagesImage preview with loading statesv0.5.0
🔗 LinksClickable link renderingv0.5.0
🧩 Editable Tables (Advanced)Optional table editor with inline cells + source togglev0.5.1

Installation

npm install codemirror-live-markdown

Peer dependencies:

npm install @codemirror/state @codemirror/view @codemirror/lang-markdown @codemirror/language @lezer/markdown

Optional dependencies (install only what you need):

npm install katex      # For math formulas
npm install lowlight   # For code syntax highlighting

Quick Start

import { EditorState } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { markdown } from '@codemirror/lang-markdown';
import {
  livePreviewPlugin,
  markdownStylePlugin,
  editorTheme,
  mouseSelectingField,
  collapseOnSelectionFacet,
  setMouseSelecting,
} from 'codemirror-live-markdown';

const view = new EditorView({
  state: EditorState.create({
    doc: '# Hello World\n\nThis is **bold** and *italic* text.',
    extensions: [
      markdown(),
      collapseOnSelectionFacet.of(true),
      mouseSelectingField,
      livePreviewPlugin,
      markdownStylePlugin,
      editorTheme,
    ],
  }),
  parent: document.getElementById('editor')!,
});

// Required: Track mouse selection state
view.contentDOM.addEventListener('mousedown', () => {
  view.dispatch({ effects: setMouseSelecting.of(true) });
});
document.addEventListener('mouseup', () => {
  requestAnimationFrame(() => {
    view.dispatch({ effects: setMouseSelecting.of(false) });
  });
});

Documentation

Adding Optional Features

Each feature is a separate plugin. Import and add only what you need:

import { Table } from '@lezer/markdown';
import {
  mathPlugin,
  blockMathField,
  tableField,
  tableEditorPlugin,
  codeBlockField,
  codeBlockEditorPlugin,
  imageField,
  linkPlugin,
} from 'codemirror-live-markdown';

const extensions = [
  markdown({ extensions: [Table] }), // Enable GFM tables in parser
  // ... core extensions from Quick Start
  
  // Optional features:
  mathPlugin,                        // Inline math: `$E=mc^2$`
  blockMathField,                    // Block math: ```math
  tableField,                        // GFM tables
  tableEditorPlugin(),               // Editable tables with source toggle
  codeBlockField({ copyButton: true }), // Code blocks with syntax highlighting
  codeBlockEditorPlugin({ copyButton: true }), // Code blocks with MD/Code toggle
  imageField(),                      // Image preview
  linkPlugin(),                      // Link rendering
];

Code Block Options

codeBlockField({
  lineNumbers: false,      // Show line numbers
  copyButton: true,        // Show copy button
  defaultLanguage: 'text', // Fallback language
  interaction: 'auto',     // 'auto' | 'toggle'
})
  • interaction: 'auto' (default): enter source mode when cursor enters code block.
  • interaction: 'toggle': keep rendered mode by default and switch with MD / Code buttons.

Code Block Editor Plugin

codeBlockEditorPlugin({
  copyButton: true,
  lineNumbers: false,
  defaultLanguage: 'text',
})

codeBlockEditorPlugin() is a non-breaking convenience API for codeBlockField({ interaction: 'toggle' }).

Registering Additional Languages

import { registerLanguage, initHighlighter } from 'codemirror-live-markdown';
import rust from 'highlight.js/lib/languages/rust';

// Initialize highlighter (required before first use)
await initHighlighter();

// Register additional languages
registerLanguage('rust', rust);

Theming

Customize with CSS variables:

:root {
  --md-heading: #1a1a1a;
  --md-bold: #1a1a1a;
  --md-italic: #1a1a1a;
  --md-link: #2563eb;
  --md-code-bg: #f5f5f5;
}

API Reference

Core Extensions

ExportDescription
livePreviewPluginMain live preview behavior
markdownStylePluginStyling for headers, bold, italic, etc.
editorThemeDefault theme with animations
mouseSelectingFieldTracks drag selection state
collapseOnSelectionFacetEnable/disable live preview

Feature Extensions

ExportDescriptionRequires
mathPluginInline math renderingkatex
blockMathFieldBlock math renderingkatex
tableFieldTable rendering@lezer/markdown Table
tableEditorPlugin()Editable table rendering@lezer/markdown Table
codeBlockField(options?)Code block highlightinglowlight
codeBlockEditorPlugin(options?)Code block editable preview with MD/Code togglelowlight
setCodeBlockSourceModeToggle code block source mode via effect
imageField(options?)Image preview
linkPlugin(options?)Link rendering

Utilities

ExportDescription
shouldShowSource(state, from, to)Check if range should show source
renderMath(source, displayMode)Render LaTeX to HTML
highlightCode(code, lang?)Highlight code string
initHighlighter()Initialize syntax highlighter
isHighlighterAvailable()Check if highlighter is ready

Development

git clone https://github.com/blueberrycongee/codemirror-live-markdown.git
cd codemirror-live-markdown
npm install
npm run dev      # Watch mode
npm test         # Run tests
npm run build    # Production build

Run the demo:

cd demo
npm install
npm run dev

Contributing

Contributions are welcome! Please read our contributing guidelines before submitting a PR.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT © blueberrycongee

Acknowledgments