flashman
← All posts

Markdown single-newline preview debugging

Debug a Markdown preview that breaks on a single newline: one line break becomes br, a trailing newline does not, and the word count includes the markers.

2026-10-22 · 6 min read · Rahul Chitturi

  • markdown
  • preview
  • debugging

The Markdown editor and the viewer render with marked, GFM on and breaks on. A single newline inside a paragraph becomes a br. A blank line still starts a new paragraph. The preview and the copied HTML are that result after DOMPurify. The word, line, and character counts are taken from the source, not from the HTML.

A box that trims to nothing renders no HTML. The preview then says Nothing to preview yet. The counters still describe the source, so a box of spaces can show 0 words while the line count is not zero.

Read one newline as a break

hello followed by one newline and world becomes a single paragraph, hello, a br, and world. The same letters with a blank line between them become two paragraphs. A CRLF between a and b is also one br. A trailing newline after flashman does not add a br. The HTML is a paragraph containing flashman, and the line count is 2 because the source still contains that newline.

A list item split onto an indented continuation line puts a br inside the item. para, a blank line, then - item and an indented continued, becomes a paragraph plus a list whose item is item, a br, and continued. Two spaces in the middle of a line stay two spaces in the HTML text. The browser collapses them when it paints.

  • Use a blank line when you want a new paragraph.
  • Expect one newline to become a br.
  • Expect a trailing newline to change the line count only.
  • Expect CRLF and LF to render as the same break.

Count the source, markers included

Words are the trimmed source split on whitespace. # Title is 2 words. - a and - b on two lines is 4 words, because each hyphen is a word. **bold** is 1 word. A fenced block ```js, const x = 1;, and the closing fence is 6 words. one two and three on the next line is 3 words, 2 lines, and 13 characters, which matches the test next to the counter.

Lines are split on \n only. a, a CR, a newline, and b is 2 lines and 4 characters. Characters are the raw length, including spaces and the CR. Trim is used for the word count and for the empty preview. It is not used for lines or characters.

Copy the HTML the sanitizer kept

Copy HTML on the editor copies the sanitized HTML, including the trailing newline marked adds. A script tag in the source is removed from that HTML, and the following paragraph remains. An image onerror attribute is removed. A javascript: link keeps the anchor and loses the href. The viewer copies the Markdown source, not the HTML.

Use the Markdown editor when you want both source and HTML, the viewer when you are reading a file, and diff when two previews disagree. Compare the source newline with the br before you call the wrap a bug. The counters are a view of the box, not of the rendered text.

Try these tools