rjprins/markdown-modern

Modern visual styling for Markdown buffers in Emacs (fork of mark-graf)

1

stars

38

commits

Emacs Lisp

primary language

Sep 3, 2026

updated

emacs
emacs-lisp
markdown
markdown-editor
obsidian
text-editor
tree-sitter
wysiwyg
Browse cluster: Markdown Editors and Previews

README

markdown-modern

Modern visual styling for Markdown buffers in Emacs.

markdown-modern rendering a Markdown buffer inline

markdown-modern renders Markdown inline — headings, emphasis, code, tables, images — using text properties and overlays, in the spirit of org-modern. It reveals the raw markup of the element under the cursor for editing, rather than showing raw syntax or a split-pane preview.

markdown-modern is a fork of mark-graf by Marc Ansset.

Features

markdown-modern's own rendering and editing:

  • Inline rendering — headings, bold, italic, inline code, links and images shown in place, via text properties and overlays
  • Reveal-at-point editing — the element under the cursor shows its raw markup (styling preserved) for editing, and re-renders when you move away; a single view mode, no source/rendered toggle
  • Viewport-driven — built on jit-lock, so rendering cost is independent of file size (see Performance)
  • GFM constructs — tables, task lists, fenced code blocks, strikethrough, blockquotes, lists, horizontal rules
  • Mermaid diagrams — rendered inline by a built-in, pure-Elisp SVG renderer (no Node or external CLI)
  • LaTeX math — inline and display math via a built-in LaTeX → Unicode converter
  • HTML export — built in, with no external dependencies

Wired up from Emacs built-ins or external tools:

  • Code-block syntax highlighting — uses the language's own major mode (python-mode, rust-ts-mode, …); requires that mode to be installed
  • Inline image display — Emacs's built-in image support, with scaling
  • SVG math — optional, via the external tex2svg (MathJax-node)
  • PDF / DOCX / other export — optional, via the external pandoc

Keybindings mirror markdown-mode's C-c C-s … conventions for familiarity — though markdown-modern is its own major mode (derived from text-mode), not built on markdown-mode.

Performance

Rendering is driven by jit-lock, so only the visible region is rendered — open and scroll cost is independent of file size, not proportional to it. On a 25,000-line (~600 KB) Markdown file, rendering a screenful takes about 3 ms with the tree-sitter parser, and reveal-at-point is sub-millisecond. Run make bench to measure on your machine.

Requirements

  • Emacs 30.1 or later

Optional Dependencies

  • pandoc - For PDF/DOCX export

Installation

markdown-modern is not on MELPA; install it directly from this repository.

M-x package-vc-install RET https://github.com/rjprins/markdown-modern RET

Or in your init file:

(package-vc-install "https://github.com/rjprins/markdown-modern")

With use-package (Emacs 30+):

(use-package markdown-modern
  :vc (:url "https://github.com/rjprins/markdown-modern"))

Manual

(add-to-list 'load-path "/path/to/markdown-modern/lisp")
(require 'markdown-modern)

Usage

Enable markdown-modern for markdown files by adding to your init file:

(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-modern-mode))

Or activate manually with M-x markdown-modern-mode in any markdown buffer.

Quick Start

KeyCommandDescription
C-c C-s bmarkdown-modern-insert-boldInsert/toggle bold
C-c C-s imarkdown-modern-insert-italicInsert/toggle italic
C-c C-s cmarkdown-modern-insert-codeInsert/toggle code
C-c C-t 2markdown-modern-insert-heading-2Insert ## heading
C-c C-lmarkdown-modern-insert-linkInsert link
C-c C-imarkdown-modern-insert-imageInsert image
C-c C-e hmarkdown-modern-export-htmlExport to HTML

Editing Model

markdown-modern has a single view mode. Markdown is always rendered inline; when the cursor enters the scope of a markup element, that element's raw markup is revealed so you can edit it in place, and re-rendered once the cursor leaves:

  • On a heading line, the # markers appear (at the heading's size).
  • Inside (or right next to) emphasis, a code span, or a link, that element's delimiters appear.
  • On a list item or blockquote, the leading marker (- , 1. , > ) appears.
  • Inside a fenced code block or table, the raw block is shown.

Task checkboxes are the exception: they are treated as interactive widgets, not markup to reveal. Point on a checkbox keeps the rendered /; SPC toggles it, and Backspace/Delete on it removes the checkbox, leaving a plain list item.

Plain prose is never disturbed, so moving the cursor through ordinary text does no work. There is no source/rendered toggle to manage.

You can also reveal the element at point on demand with markdown-modern-toggle-element-at-point (C-c C-v e).

KeyCommandDescription
C-c C-nmarkdown-modern-next-headingNext heading
C-c C-pmarkdown-modern-prev-headingPrevious heading
C-c C-umarkdown-modern-up-headingParent heading
TABContext-sensitiveCycle visibility / table nav

Lists

KeyCommandDescription
M-RETmarkdown-modern-insert-list-itemNew list item
C-c <up/down>Move itemReorder list items
C-c <left/right>Promote/demoteChange indentation
C-c C-x C-bmarkdown-modern-toggle-checkboxToggle task checkbox
SPC (on a checkbox)markdown-modern-space-or-toggle-checkboxToggle the checkbox under point
Backspace/Delete (on a checkbox)markdown-modern-checkbox-delete-{backward,forward}Remove the checkbox, keep the list item

Tables

KeyCommandDescription
C-c |markdown-modern-insert-tableInsert new table
TABmarkdown-modern-table-next-cellNext cell
S-TABmarkdown-modern-table-prev-cellPrevious cell

Export

;; Built-in HTML export (no dependencies)
M-x markdown-modern-export-html

;; Preview in browser
M-x markdown-modern-preview-html

;; Export via Pandoc (requires pandoc)
M-x markdown-modern-export-pdf
M-x markdown-modern-export-docx

Customization

All options are under M-x customize-group RET markdown-modern RET. The faces (markdown-modern-heading-1-6, -bold, -italic, -inline-code, -code-block, -table, …) are under markdown-modern-faces.

Appearance

VariableDefaultDescription
markdown-modern-heading-scale(1.8 1.5 1.3 1.1 1.05 1.0)Height scale factors for heading levels 1–6
markdown-modern-heading-use-variable-pitchtHeadings use a variable-pitch font
markdown-modern-variable-pitchtEnable variable-pitch-mode (proportional prose; code/tables stay fixed-pitch)
markdown-modern-visual-linetEnable visual-line-mode (soft word-wrap)
markdown-modern-left-margin4Left margin width, in characters

Reading width

VariableDefaultDescription
markdown-modern-manage-text-widthnilLet markdown-modern constrain the reading width; when nil it leaves fill-column and wrapping to your config
markdown-modern-text-width90Reading width in characters (used only when manage-text-width is non-nil)
markdown-modern-table-max-widthnilCap rendered table width; nil = natural width (scroll over-wide tables with C-c C-v t)

Code blocks

VariableDefaultDescription
markdown-modern-code-block-syntax-highlighttSyntax-highlight code blocks via the language's major mode
markdown-modern-code-block-full-widthtExtend the code-block background to the window edge

Images & diagrams

VariableDefaultDescription
markdown-modern-display-imagestDisplay images inline
markdown-modern-image-max-width600Maximum inline-image width, in pixels
markdown-modern-image-max-height400Maximum inline-image height, in pixels
markdown-modern-cache-directory~/.cache/markdown-modernDirectory for cached rendered diagrams

Math

VariableDefaultDescription
markdown-modern-math-renderertextHow to render LaTeX math: text (Unicode) or svg (via tex2svg)
markdown-modern-math-block-scale1.4Scale of display-math text relative to normal
markdown-modern-tex2svg-executable"tex2svg"Path to tex2svg (MathJax-node), for SVG math

Export

VariableDefaultDescription
markdown-modern-use-pandocnilUse Pandoc for export when available
markdown-modern-pandoc-executable"pandoc"Path to the Pandoc executable
markdown-modern-export-embed-imagesnilEmbed images as base64 in HTML export
markdown-modern-export-html-template(built-in)HTML template used by the built-in HTML export
markdown-modern-export-html-css(built-in)CSS used by the built-in HTML export

Example configuration

(use-package markdown-modern
  :vc (:url "https://github.com/rjprins/markdown-modern")
  :mode ("\\.md\\'" "\\.markdown\\'")
  :custom
  ;; Constrain the reading width (off by default):
  (markdown-modern-manage-text-width t)
  (markdown-modern-text-width 100)
  :config
  (set-face-attribute 'markdown-modern-heading-1 nil :foreground "#2aa198"))

Keybinding Reference

Style Insertion (C-c C-s prefix)

KeyCommand
C-c C-s bBold
C-c C-s iItalic
C-c C-s cInline code
C-c C-s sStrikethrough
C-c C-s qBlockquote
C-c C-s pCode block
C-c C-s k<kbd> tag

Headings (C-c C-t prefix)

KeyCommand
C-c C-t hInsert heading (prompts for level)
C-c C-t 1-6Insert heading level 1-6
C-c C-t !Promote heading
C-c C-t @Demote heading

Reveal (C-c C-v prefix)

KeyCommand
C-c C-v eReveal raw markup for the element at point
C-c C-v tToggle horizontal-scroll view (for tables wider than the window)

Export (C-c C-e prefix)

KeyCommand
C-c C-e hExport to HTML
C-c C-e pExport to PDF (Pandoc)
C-c C-e dExport to DOCX (Pandoc)
C-c C-c pPreview in browser

Known Limitations

  • Setext-style headings (underlines) are not supported
  • Math rendering requires external tools for SVG output
  • Some complex nested structures may not render perfectly

License

GPL-3.0-or-later

Credits

markdown-modern is a fork of mark-graf by Marc Ansset; thanks for the original work.

Inspired by:

Contributors

rjprins

33 commits

MarcRohrer

5 commits

rjprins/markdown-modern

Modern visual styling for Markdown buffers in Emacs (fork of mark-graf)

1

stars

38

commits

Emacs Lisp

primary language

Sep 3, 2026

updated

emacs
emacs-lisp
markdown
markdown-editor
obsidian
text-editor
tree-sitter
wysiwyg
Browse cluster: Markdown Editors and Previews

README

markdown-modern

Modern visual styling for Markdown buffers in Emacs.

markdown-modern rendering a Markdown buffer inline

markdown-modern renders Markdown inline — headings, emphasis, code, tables, images — using text properties and overlays, in the spirit of org-modern. It reveals the raw markup of the element under the cursor for editing, rather than showing raw syntax or a split-pane preview.

markdown-modern is a fork of mark-graf by Marc Ansset.

Features

markdown-modern's own rendering and editing:

  • Inline rendering — headings, bold, italic, inline code, links and images shown in place, via text properties and overlays
  • Reveal-at-point editing — the element under the cursor shows its raw markup (styling preserved) for editing, and re-renders when you move away; a single view mode, no source/rendered toggle
  • Viewport-driven — built on jit-lock, so rendering cost is independent of file size (see Performance)
  • GFM constructs — tables, task lists, fenced code blocks, strikethrough, blockquotes, lists, horizontal rules
  • Mermaid diagrams — rendered inline by a built-in, pure-Elisp SVG renderer (no Node or external CLI)
  • LaTeX math — inline and display math via a built-in LaTeX → Unicode converter
  • HTML export — built in, with no external dependencies

Wired up from Emacs built-ins or external tools:

  • Code-block syntax highlighting — uses the language's own major mode (python-mode, rust-ts-mode, …); requires that mode to be installed
  • Inline image display — Emacs's built-in image support, with scaling
  • SVG math — optional, via the external tex2svg (MathJax-node)
  • PDF / DOCX / other export — optional, via the external pandoc

Keybindings mirror markdown-mode's C-c C-s … conventions for familiarity — though markdown-modern is its own major mode (derived from text-mode), not built on markdown-mode.

Performance

Rendering is driven by jit-lock, so only the visible region is rendered — open and scroll cost is independent of file size, not proportional to it. On a 25,000-line (~600 KB) Markdown file, rendering a screenful takes about 3 ms with the tree-sitter parser, and reveal-at-point is sub-millisecond. Run make bench to measure on your machine.

Requirements

  • Emacs 30.1 or later

Optional Dependencies

  • pandoc - For PDF/DOCX export

Installation

markdown-modern is not on MELPA; install it directly from this repository.

M-x package-vc-install RET https://github.com/rjprins/markdown-modern RET

Or in your init file:

(package-vc-install "https://github.com/rjprins/markdown-modern")

With use-package (Emacs 30+):

(use-package markdown-modern
  :vc (:url "https://github.com/rjprins/markdown-modern"))

Manual

(add-to-list 'load-path "/path/to/markdown-modern/lisp")
(require 'markdown-modern)

Usage

Enable markdown-modern for markdown files by adding to your init file:

(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-modern-mode))

Or activate manually with M-x markdown-modern-mode in any markdown buffer.

Quick Start

KeyCommandDescription
C-c C-s bmarkdown-modern-insert-boldInsert/toggle bold
C-c C-s imarkdown-modern-insert-italicInsert/toggle italic
C-c C-s cmarkdown-modern-insert-codeInsert/toggle code
C-c C-t 2markdown-modern-insert-heading-2Insert ## heading
C-c C-lmarkdown-modern-insert-linkInsert link
C-c C-imarkdown-modern-insert-imageInsert image
C-c C-e hmarkdown-modern-export-htmlExport to HTML

Editing Model

markdown-modern has a single view mode. Markdown is always rendered inline; when the cursor enters the scope of a markup element, that element's raw markup is revealed so you can edit it in place, and re-rendered once the cursor leaves:

  • On a heading line, the # markers appear (at the heading's size).
  • Inside (or right next to) emphasis, a code span, or a link, that element's delimiters appear.
  • On a list item or blockquote, the leading marker (- , 1. , > ) appears.
  • Inside a fenced code block or table, the raw block is shown.

Task checkboxes are the exception: they are treated as interactive widgets, not markup to reveal. Point on a checkbox keeps the rendered /; SPC toggles it, and Backspace/Delete on it removes the checkbox, leaving a plain list item.

Plain prose is never disturbed, so moving the cursor through ordinary text does no work. There is no source/rendered toggle to manage.

You can also reveal the element at point on demand with markdown-modern-toggle-element-at-point (C-c C-v e).

KeyCommandDescription
C-c C-nmarkdown-modern-next-headingNext heading
C-c C-pmarkdown-modern-prev-headingPrevious heading
C-c C-umarkdown-modern-up-headingParent heading
TABContext-sensitiveCycle visibility / table nav

Lists

KeyCommandDescription
M-RETmarkdown-modern-insert-list-itemNew list item
C-c <up/down>Move itemReorder list items
C-c <left/right>Promote/demoteChange indentation
C-c C-x C-bmarkdown-modern-toggle-checkboxToggle task checkbox
SPC (on a checkbox)markdown-modern-space-or-toggle-checkboxToggle the checkbox under point
Backspace/Delete (on a checkbox)markdown-modern-checkbox-delete-{backward,forward}Remove the checkbox, keep the list item

Tables

KeyCommandDescription
C-c |markdown-modern-insert-tableInsert new table
TABmarkdown-modern-table-next-cellNext cell
S-TABmarkdown-modern-table-prev-cellPrevious cell

Export

;; Built-in HTML export (no dependencies)
M-x markdown-modern-export-html

;; Preview in browser
M-x markdown-modern-preview-html

;; Export via Pandoc (requires pandoc)
M-x markdown-modern-export-pdf
M-x markdown-modern-export-docx

Customization

All options are under M-x customize-group RET markdown-modern RET. The faces (markdown-modern-heading-1-6, -bold, -italic, -inline-code, -code-block, -table, …) are under markdown-modern-faces.

Appearance

VariableDefaultDescription
markdown-modern-heading-scale(1.8 1.5 1.3 1.1 1.05 1.0)Height scale factors for heading levels 1–6
markdown-modern-heading-use-variable-pitchtHeadings use a variable-pitch font
markdown-modern-variable-pitchtEnable variable-pitch-mode (proportional prose; code/tables stay fixed-pitch)
markdown-modern-visual-linetEnable visual-line-mode (soft word-wrap)
markdown-modern-left-margin4Left margin width, in characters

Reading width

VariableDefaultDescription
markdown-modern-manage-text-widthnilLet markdown-modern constrain the reading width; when nil it leaves fill-column and wrapping to your config
markdown-modern-text-width90Reading width in characters (used only when manage-text-width is non-nil)
markdown-modern-table-max-widthnilCap rendered table width; nil = natural width (scroll over-wide tables with C-c C-v t)

Code blocks

VariableDefaultDescription
markdown-modern-code-block-syntax-highlighttSyntax-highlight code blocks via the language's major mode
markdown-modern-code-block-full-widthtExtend the code-block background to the window edge

Images & diagrams

VariableDefaultDescription
markdown-modern-display-imagestDisplay images inline
markdown-modern-image-max-width600Maximum inline-image width, in pixels
markdown-modern-image-max-height400Maximum inline-image height, in pixels
markdown-modern-cache-directory~/.cache/markdown-modernDirectory for cached rendered diagrams

Math

VariableDefaultDescription
markdown-modern-math-renderertextHow to render LaTeX math: text (Unicode) or svg (via tex2svg)
markdown-modern-math-block-scale1.4Scale of display-math text relative to normal
markdown-modern-tex2svg-executable"tex2svg"Path to tex2svg (MathJax-node), for SVG math

Export

VariableDefaultDescription
markdown-modern-use-pandocnilUse Pandoc for export when available
markdown-modern-pandoc-executable"pandoc"Path to the Pandoc executable
markdown-modern-export-embed-imagesnilEmbed images as base64 in HTML export
markdown-modern-export-html-template(built-in)HTML template used by the built-in HTML export
markdown-modern-export-html-css(built-in)CSS used by the built-in HTML export

Example configuration

(use-package markdown-modern
  :vc (:url "https://github.com/rjprins/markdown-modern")
  :mode ("\\.md\\'" "\\.markdown\\'")
  :custom
  ;; Constrain the reading width (off by default):
  (markdown-modern-manage-text-width t)
  (markdown-modern-text-width 100)
  :config
  (set-face-attribute 'markdown-modern-heading-1 nil :foreground "#2aa198"))

Keybinding Reference

Style Insertion (C-c C-s prefix)

KeyCommand
C-c C-s bBold
C-c C-s iItalic
C-c C-s cInline code
C-c C-s sStrikethrough
C-c C-s qBlockquote
C-c C-s pCode block
C-c C-s k<kbd> tag

Headings (C-c C-t prefix)

KeyCommand
C-c C-t hInsert heading (prompts for level)
C-c C-t 1-6Insert heading level 1-6
C-c C-t !Promote heading
C-c C-t @Demote heading

Reveal (C-c C-v prefix)

KeyCommand
C-c C-v eReveal raw markup for the element at point
C-c C-v tToggle horizontal-scroll view (for tables wider than the window)

Export (C-c C-e prefix)

KeyCommand
C-c C-e hExport to HTML
C-c C-e pExport to PDF (Pandoc)
C-c C-e dExport to DOCX (Pandoc)
C-c C-c pPreview in browser

Known Limitations

  • Setext-style headings (underlines) are not supported
  • Math rendering requires external tools for SVG output
  • Some complex nested structures may not render perfectly

License

GPL-3.0-or-later

Credits

markdown-modern is a fork of mark-graf by Marc Ansset; thanks for the original work.

Inspired by:

Contributors

rjprins

33 commits

MarcRohrer

5 commits

Languages

Emacs Lisp

97.8%

Makefile

2.2%