Skip to content

fix: eliminate rendering pane flash on keypress#1362

Open
iJaack wants to merge 1 commit intoMacDownApp:masterfrom
iJaack:fix/rendering-pane-flash
Open

fix: eliminate rendering pane flash on keypress#1362
iJaack wants to merge 1 commit intoMacDownApp:masterfrom
iJaack:fix/rendering-pane-flash

Conversation

@iJaack
Copy link

@iJaack iJaack commented Feb 20, 2026

Problem

The rendering pane flashes/flickers on almost every keypress (reported in #1104). This happens because renderer:didProduceHTMLOutput: calls [self.preview.mainFrame loadHTMLString:html baseURL:baseUrl] on every content change, which tears down and rebuilds the entire WebView — causing a visible white flash between the old content disappearing and new content appearing.

Previous attempt

The original developer tried DOM replacement via Objective-C DOMDocument APIs (the #if 0 block in MPDocument.m) but abandoned it because JavaScript libraries like MathJax and Prism lost their rendering state after the DOM swap.

PR #1216 proposed a double-buffering approach (rendering into a hidden second WebView and swapping), which adds complexity and memory overhead.

This fix

Takes a simpler approach — in-place DOM updates via JavaScript:

  1. When the document is already loaded and the base URL hasn't changed, extract only the <body> content from the rendered HTML
  2. Replace document.body.innerHTML via stringByEvaluatingJavaScriptFromString:
  3. Re-trigger JavaScript libraries after the DOM swap:
    • Prism.highlightAll() for syntax highlighting
    • MathJax.Hub.Typeset() / MathJax.typeset() for math rendering (v2 + v3)
    • hljs.highlightElement() for highlight.js

This preserves the <head> (stylesheets, scripts already loaded) and only updates body content — no page reload, no flash.

Full page reloads still happen for:

  • Initial document load (first render)
  • Base URL changes (e.g. saving an untitled document for the first time)

Changes

  • MacDown/Code/Document/MPDocument.m — 1 file, +58/-36 lines
  • Replaces the disabled #if 0 DOM replacement block with a working JavaScript-based approach
  • No new files, no new dependencies

Fixes #1104
Supersedes #1216

Replace the full-page reload approach (loadHTMLString:baseURL:) with
in-place DOM updates via JavaScript when updating an already-loaded
document.

The previous code called [self.preview.mainFrame loadHTMLString:html
baseURL:baseUrl] on every content change, which tears down and rebuilds
the entire WebView — causing a visible white flash between renders.

The original developer attempted DOM replacement via Objective-C
DOMDocument APIs (see the removed #if 0 block) but abandoned it because
JavaScript libraries like MathJax and Prism lost their state.

This fix takes a different approach:
1. Extract only the <body> content from the rendered HTML
2. Replace document.body.innerHTML via stringByEvaluatingJavaScriptFromString:
3. Re-trigger Prism.highlightAll(), MathJax.Hub.Typeset(), and
   hljs.highlightElement() after the DOM swap

This preserves the <head> (stylesheets, scripts) and only updates the
body content, avoiding the full page reload. JavaScript libraries are
explicitly re-invoked so syntax highlighting, math rendering, and other
JS-dependent features continue to work.

Full page reloads are still used for:
- Initial document load
- Base URL changes (e.g. saving an untitled document)

Fixes MacDownApp#1104
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Rendering pane flashing

1 participant