Skip to content

Multiple consecutive blank lines are collapsed into a single blank line #622

Description

@MrSolimanKing

When rendering markdown with EnrichedMarkdownText, consecutive empty lines in the source text are collapsed and rendered as a single blank line/paragraph break, no matter how many blank lines were actually in the source.

const markdown = `Paragraph one.


Paragraph two (there were 2 blank lines above, but only 1 renders).`;

<EnrichedMarkdownText markdown={markdown} flavor="github" />

Expected

Some way to preserve the actual number of blank lines from the source, either via a prop (e.g. preserveBlankLines) or a documented parsing option.

Current workaround

The only way I have found to preserve blank line count is to pre process the markdown string myself before passing it to markdown, converting every blank line after the first in a run into its own paragraph containing a non-breaking space (\u00A0), so the parser treats it as non-empty content instead of discarding it:

function preserveWhitespace(text: string): string {
  const lines = text.split('\n');
  let inFence = false;
  const output: string[] = [];
  let i = 0;
  while (i < lines.length) {
    const line = lines[i];
    if (/^\s*(```|~~~)/.test(line)) {
      inFence = !inFence;
      output.push(line);
      i++;
      continue;
    }
    if (inFence) {
      output.push(line);
      i++;
      continue;
    }
    if (line.trim() === '') {
      let blankCount = 0;
      let j = i;
      while (j < lines.length && lines[j].trim() === '') {
        blankCount++;
        j++;
      }
      output.push('');
      for (let k = 1; k < blankCount; k++) {
        output.push('\u00A0');
        output.push('');
      }
      i = j;
      continue;
    }
    let result = line.replace(/ {2,}/g, (run) => '\u00A0'.repeat(run.length - 1) + ' ');
    result += '  ';
    output.push(result);
    i++;
  }
  return output.join('\n');
}

This works, but it feels like something the library should handle natively (similar to how some markdown renderers expose a breaks-style option), rather than requiring every consumer to reimplement blank-line preservation by hand.

const finalMarkdown = useMemo(
  () => preserveWhitespace(processedContent),
  [processedContent]
);

Usage:

<EnrichedMarkdownText 
  markdown={finalMarkdown} 
/>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions