# Rendering and Sync

This page explains when `MDViewer` re-renders, what a render does, and how scroll sync with the editor works.

## Triggers

| Source | Condition |
|---|---|
| Editor `keyup` | `autosave` is truthy and the key is not an arrow key, `Shift`, `Control`, `Alt`, `CapsLock`, `Escape`, `F1`-`F12` or `Meta` |
| Editor formatting methods (`bold()`, `heading()`, ...) | `autosave` is truthy |
| `undo()`, `redo()` | `autosave` is truthy |
| `clear()`, `openfile()` once the file is read | Always |
| `save()` | When `autosave` is false (`Cmd/Ctrl+S` or the toolbar "save and preview" button) |
| Calling `viewer.init(text)` directly | Always |

With `autosave: false`, typing is not reflected in the preview; only `save()` updates it.

## Render Steps

What `viewer.init(txt)` does:

1. Sets `data-saved="1"` and clears the previous timer
2. Waits `sync.delay` milliseconds (300 by default; passing `0` falls back to 300 because it is falsy)
3. Picks the content: the first non-empty of `txt`, the bound editor's text, `emptyContent`
4. Calls `transToHTML()` (extended mode, with the hashtag settings)
5. Replaces the viewer content wholesale with `replaceChildren()`
6. Binds every code block's copy button to `navigator.clipboard.writeText()`; adds the `success` class for 1 second on success, the `error` class on failure
7. Polls every 50 ms until code-prettify's global `PR` exists; then restores the scroll position, runs `PR.prettyPrint()`, and runs `mermaid.run()` on every `.mermaid` element in the document

Continuous typing keeps resetting the timer, so a render only happens after input pauses for longer than `sync.delay` (debounce).

## Reading Editor Text

The viewer does not receive data through events; at render time it reads the `innerText` of every `<div>` row in the editor container. Blank rows become a single `\n`, non-breaking spaces become plain spaces, and the whole result is trimmed.

## Scroll Sync

With `sync.scroll` truthy, binding the editor sets the editor's `onwheel`: each wheel event adds `deltaY` to the viewer's `scrollTop`.

| Limitation | Detail |
|---|---|
| Wheel only | Dragging the scrollbar, touch swipes and keyboard scrolling are not synced |
| One-way | Only the editor drives the viewer |
| Delta-based | Not proportional; positions drift when the two sides differ greatly in height |
| Overwrites `onwheel` | Replaces any existing `onwheel` handler on the editor container |

## Saved-State Flag

The `data-saved` attribute on the editor and viewer containers tracks whether content is in sync: input sets it to `0` (`unsave()`), the start of a render sets it to `1`. `NanoMD.css` styles this state, and you can use it for a custom "unsaved" indicator.

## Virtual DOM

The `vDOM` class and `#applyPatch()` are still in the source, but rendering currently uses a wholesale `replaceChildren()` for correctness; neither diff nor patch is called.
