Skip to content

Fix getMarkdown() returning   instead of empty string#7497

Merged
bdbch merged 3 commits intomainfrom
claude/tiptap-issue-resolver-5Fueh
Feb 13, 2026
Merged

Fix getMarkdown() returning   instead of empty string#7497
bdbch merged 3 commits intomainfrom
claude/tiptap-issue-resolver-5Fueh

Conversation

@bdbch
Copy link
Copy Markdown
Member

@bdbch bdbch commented Feb 3, 2026

Changes Overview

Fixed getMarkdown() returning   instead of empty string when the editor is empty, ensuring consistent behavior with other output methods like getText().

Implementation Approach

Modified the MarkdownManager.serialize() method to detect when the serialized output contains only whitespace entities (  or non-breaking space characters) and return an empty string in those cases.

Added a private helper method isEmptyOutput() that:

  • Checks if the markdown string is empty or contains only whitespace
  • Strips all   entities and Unicode non-breaking spaces
  • Returns true if the cleaned output is empty

This approach preserves the existing blank-line preservation functionality (where   is intentionally used between content paragraphs) while fixing the empty document case.

Testing Done

Added comprehensive test coverage in packages/markdown/__tests__/manager.spec.ts:

  1. Empty document test: Verifies that a document with only an empty paragraph returns an empty string
  2. Blank line preservation test: Confirms that blank lines between paragraphs with content still render as  

Example test case:

it('should return empty string when serializing empty document', () => {
  const emptyDoc = {
    type: 'doc',
    content: [{ type: 'paragraph', content: [] }]
  }
  
  const markdown = markdownManager.serialize(emptyDoc)
  expect(markdown).toBe('')
})

Verification Steps

  1. Create an empty Tiptap editor
  2. Call editor.getMarkdown()
  3. Verify it returns "" (empty string) instead of  
  4. Add content, then clear it completely
  5. Verify getMarkdown() returns empty string
  6. Test with multiple paragraphs containing blank lines to ensure blank line preservation still works

Additional Notes

  • This fix maintains backward compatibility with all existing markdown serialization behavior
  • The paragraph extension's renderMarkdown implementation remains unchanged
  • Empty paragraph rendering is handled at the serialization layer, not at the extension level
  • Fixes issue getMarkdown returns   when editor is empty #7495

Checklist

  • I have created a changeset for this PR if necessary.
  • My changes do not break the library.
  • I have added tests where applicable.
  • I have followed the project guidelines.
  • I have fixed any lint issues.

Related Issues

Fixes #7495

Fixes issue where getMarkdown() returns ' ' when the editor is empty,
instead of returning an empty string as expected. This behavior was inconsistent
with getText() which correctly returns an empty string.

Changes:
- Added isEmptyOutput() helper method to detect empty documents
- Modified serialize() to check if output is only whitespace entities
- Empty documents now return empty string, preserving blank lines between content
- Added comprehensive tests for empty document and blank line preservation

All existing functionality for blank line preservation remains intact.

https://claude.ai/code/session_013q4GkzGgcDFg6oc4LwYo6y
Copilot AI review requested due to automatic review settings February 3, 2026 17:52
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 3, 2026

🦋 Changeset detected

Latest commit: 6f583fa

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 72 packages
Name Type
@tiptap/markdown Patch
@tiptap/core Patch
@tiptap/extension-audio Patch
@tiptap/extension-blockquote Patch
@tiptap/extension-bold Patch
@tiptap/extension-bubble-menu Patch
@tiptap/extension-bullet-list Patch
@tiptap/extension-code-block-lowlight Patch
@tiptap/extension-code-block Patch
@tiptap/extension-code Patch
@tiptap/extension-collaboration-caret Patch
@tiptap/extension-collaboration Patch
@tiptap/extension-color Patch
@tiptap/extension-details Patch
@tiptap/extension-document Patch
@tiptap/extension-drag-handle-react Patch
@tiptap/extension-drag-handle-vue-2 Patch
@tiptap/extension-drag-handle-vue-3 Patch
@tiptap/extension-drag-handle Patch
@tiptap/extension-emoji Patch
@tiptap/extension-file-handler Patch
@tiptap/extension-floating-menu Patch
@tiptap/extension-font-family Patch
@tiptap/extension-hard-break Patch
@tiptap/extension-heading Patch
@tiptap/extension-highlight Patch
@tiptap/extension-horizontal-rule Patch
@tiptap/extension-image Patch
@tiptap/extension-invisible-characters Patch
@tiptap/extension-italic Patch
@tiptap/extension-link Patch
@tiptap/extension-list Patch
@tiptap/extension-mathematics Patch
@tiptap/extension-mention Patch
@tiptap/extension-node-range Patch
@tiptap/extension-ordered-list Patch
@tiptap/extension-paragraph Patch
@tiptap/extension-strike Patch
@tiptap/extension-subscript Patch
@tiptap/extension-superscript Patch
@tiptap/extension-table-of-contents Patch
@tiptap/extension-table Patch
@tiptap/extension-text-align Patch
@tiptap/extension-text-style Patch
@tiptap/extension-text Patch
@tiptap/extension-twitch Patch
@tiptap/extension-typography Patch
@tiptap/extension-underline Patch
@tiptap/extension-unique-id Patch
@tiptap/extension-youtube Patch
@tiptap/extensions Patch
@tiptap/html Patch
@tiptap/pm Patch
@tiptap/react Patch
@tiptap/starter-kit Patch
@tiptap/static-renderer Patch
@tiptap/suggestion Patch
@tiptap/vue-2 Patch
@tiptap/vue-3 Patch
@tiptap/extension-character-count Patch
@tiptap/extension-dropcursor Patch
@tiptap/extension-focus Patch
@tiptap/extension-gapcursor Patch
@tiptap/extension-history Patch
@tiptap/extension-list-item Patch
@tiptap/extension-list-keymap Patch
@tiptap/extension-placeholder Patch
@tiptap/extension-table-cell Patch
@tiptap/extension-table-header Patch
@tiptap/extension-table-row Patch
@tiptap/extension-task-item Patch
@tiptap/extension-task-list Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@netlify
Copy link
Copy Markdown

netlify Bot commented Feb 3, 2026

Deploy Preview for tiptap-embed ready!

Name Link
🔨 Latest commit 6f583fa
🔍 Latest deploy log https://app.netlify.com/projects/tiptap-embed/deploys/698242b6c1514500080f5a84
😎 Deploy Preview https://deploy-preview-7497--tiptap-embed.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where getMarkdown() was returning the HTML entity   instead of an empty string when the editor contains an empty document. The fix adds logic to detect when the serialized markdown output represents an empty document and returns an empty string in those cases, while preserving the   entities used to maintain blank lines between paragraphs with actual content.

Changes:

  • Added a new private method isEmptyOutput() to detect empty markdown output consisting only of whitespace entities
  • Modified serialize() method to check for empty output and return empty string when appropriate
  • Added two test cases to verify empty document handling and blank line preservation
  • Added a changeset for the fix

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/markdown/src/MarkdownManager.ts Added isEmptyOutput() helper method and integrated it into serialize() to detect and handle empty document output
packages/markdown/tests/manager.spec.ts Added tests for empty document serialization and blank line preservation between paragraphs
.changeset/fix-empty-document-markdown.md Added changeset documenting the bug fix for release notes

Comment thread packages/markdown/src/MarkdownManager.ts
Simplified serialize() method by removing redundant array/single-node branches.
The renderNodes() method already handles both cases internally, making the
conditional check unnecessary.

This addresses Copilot review feedback about code duplication.

https://claude.ai/code/session_013q4GkzGgcDFg6oc4LwYo6y
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Feb 3, 2026

Open in StackBlitz

@tiptap/core

npm i https://pkg.pr.new/@tiptap/core@7497

@tiptap/extension-audio

npm i https://pkg.pr.new/@tiptap/extension-audio@7497

@tiptap/extension-blockquote

npm i https://pkg.pr.new/@tiptap/extension-blockquote@7497

@tiptap/extension-bold

npm i https://pkg.pr.new/@tiptap/extension-bold@7497

@tiptap/extension-bullet-list

npm i https://pkg.pr.new/@tiptap/extension-bullet-list@7497

@tiptap/extension-bubble-menu

npm i https://pkg.pr.new/@tiptap/extension-bubble-menu@7497

@tiptap/extension-code

npm i https://pkg.pr.new/@tiptap/extension-code@7497

@tiptap/extension-code-block

npm i https://pkg.pr.new/@tiptap/extension-code-block@7497

@tiptap/extension-code-block-lowlight

npm i https://pkg.pr.new/@tiptap/extension-code-block-lowlight@7497

@tiptap/extension-collaboration

npm i https://pkg.pr.new/@tiptap/extension-collaboration@7497

@tiptap/extension-collaboration-caret

npm i https://pkg.pr.new/@tiptap/extension-collaboration-caret@7497

@tiptap/extension-color

npm i https://pkg.pr.new/@tiptap/extension-color@7497

@tiptap/extension-details

npm i https://pkg.pr.new/@tiptap/extension-details@7497

@tiptap/extension-document

npm i https://pkg.pr.new/@tiptap/extension-document@7497

@tiptap/extension-drag-handle-react

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-react@7497

@tiptap/extension-drag-handle

npm i https://pkg.pr.new/@tiptap/extension-drag-handle@7497

@tiptap/extension-drag-handle-vue-2

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-2@7497

@tiptap/extension-drag-handle-vue-3

npm i https://pkg.pr.new/@tiptap/extension-drag-handle-vue-3@7497

@tiptap/extension-file-handler

npm i https://pkg.pr.new/@tiptap/extension-file-handler@7497

@tiptap/extension-emoji

npm i https://pkg.pr.new/@tiptap/extension-emoji@7497

@tiptap/extension-floating-menu

npm i https://pkg.pr.new/@tiptap/extension-floating-menu@7497

@tiptap/extension-font-family

npm i https://pkg.pr.new/@tiptap/extension-font-family@7497

@tiptap/extension-hard-break

npm i https://pkg.pr.new/@tiptap/extension-hard-break@7497

@tiptap/extension-heading

npm i https://pkg.pr.new/@tiptap/extension-heading@7497

@tiptap/extension-highlight

npm i https://pkg.pr.new/@tiptap/extension-highlight@7497

@tiptap/extension-image

npm i https://pkg.pr.new/@tiptap/extension-image@7497

@tiptap/extension-horizontal-rule

npm i https://pkg.pr.new/@tiptap/extension-horizontal-rule@7497

@tiptap/extension-invisible-characters

npm i https://pkg.pr.new/@tiptap/extension-invisible-characters@7497

@tiptap/extension-italic

npm i https://pkg.pr.new/@tiptap/extension-italic@7497

@tiptap/extension-link

npm i https://pkg.pr.new/@tiptap/extension-link@7497

@tiptap/extension-list

npm i https://pkg.pr.new/@tiptap/extension-list@7497

@tiptap/extension-mathematics

npm i https://pkg.pr.new/@tiptap/extension-mathematics@7497

@tiptap/extension-mention

npm i https://pkg.pr.new/@tiptap/extension-mention@7497

@tiptap/extension-node-range

npm i https://pkg.pr.new/@tiptap/extension-node-range@7497

@tiptap/extension-ordered-list

npm i https://pkg.pr.new/@tiptap/extension-ordered-list@7497

@tiptap/extension-paragraph

npm i https://pkg.pr.new/@tiptap/extension-paragraph@7497

@tiptap/extension-strike

npm i https://pkg.pr.new/@tiptap/extension-strike@7497

@tiptap/extension-subscript

npm i https://pkg.pr.new/@tiptap/extension-subscript@7497

@tiptap/extension-superscript

npm i https://pkg.pr.new/@tiptap/extension-superscript@7497

@tiptap/extension-table

npm i https://pkg.pr.new/@tiptap/extension-table@7497

@tiptap/extension-table-of-contents

npm i https://pkg.pr.new/@tiptap/extension-table-of-contents@7497

@tiptap/extension-text-align

npm i https://pkg.pr.new/@tiptap/extension-text-align@7497

@tiptap/extension-text

npm i https://pkg.pr.new/@tiptap/extension-text@7497

@tiptap/extension-text-style

npm i https://pkg.pr.new/@tiptap/extension-text-style@7497

@tiptap/extension-twitch

npm i https://pkg.pr.new/@tiptap/extension-twitch@7497

@tiptap/extension-underline

npm i https://pkg.pr.new/@tiptap/extension-underline@7497

@tiptap/extension-typography

npm i https://pkg.pr.new/@tiptap/extension-typography@7497

@tiptap/extension-unique-id

npm i https://pkg.pr.new/@tiptap/extension-unique-id@7497

@tiptap/extension-youtube

npm i https://pkg.pr.new/@tiptap/extension-youtube@7497

@tiptap/html

npm i https://pkg.pr.new/@tiptap/html@7497

@tiptap/extensions

npm i https://pkg.pr.new/@tiptap/extensions@7497

@tiptap/markdown

npm i https://pkg.pr.new/@tiptap/markdown@7497

@tiptap/react

npm i https://pkg.pr.new/@tiptap/react@7497

@tiptap/starter-kit

npm i https://pkg.pr.new/@tiptap/starter-kit@7497

@tiptap/pm

npm i https://pkg.pr.new/@tiptap/pm@7497

@tiptap/suggestion

npm i https://pkg.pr.new/@tiptap/suggestion@7497

@tiptap/static-renderer

npm i https://pkg.pr.new/@tiptap/static-renderer@7497

@tiptap/vue-2

npm i https://pkg.pr.new/@tiptap/vue-2@7497

@tiptap/vue-3

npm i https://pkg.pr.new/@tiptap/vue-3@7497

@tiptap/extension-dropcursor

npm i https://pkg.pr.new/@tiptap/extension-dropcursor@7497

@tiptap/extension-character-count

npm i https://pkg.pr.new/@tiptap/extension-character-count@7497

@tiptap/extension-focus

npm i https://pkg.pr.new/@tiptap/extension-focus@7497

@tiptap/extension-gapcursor

npm i https://pkg.pr.new/@tiptap/extension-gapcursor@7497

@tiptap/extension-history

npm i https://pkg.pr.new/@tiptap/extension-history@7497

@tiptap/extension-list-item

npm i https://pkg.pr.new/@tiptap/extension-list-item@7497

@tiptap/extension-list-keymap

npm i https://pkg.pr.new/@tiptap/extension-list-keymap@7497

@tiptap/extension-placeholder

npm i https://pkg.pr.new/@tiptap/extension-placeholder@7497

@tiptap/extension-table-cell

npm i https://pkg.pr.new/@tiptap/extension-table-cell@7497

@tiptap/extension-table-header

npm i https://pkg.pr.new/@tiptap/extension-table-header@7497

@tiptap/extension-task-item

npm i https://pkg.pr.new/@tiptap/extension-task-item@7497

@tiptap/extension-table-row

npm i https://pkg.pr.new/@tiptap/extension-table-row@7497

@tiptap/extension-task-list

npm i https://pkg.pr.new/@tiptap/extension-task-list@7497

commit: 6f583fa

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@bdbch bdbch requested a review from a team February 4, 2026 11:25
@bdbch bdbch merged commit 6e3a0e8 into main Feb 13, 2026
23 checks passed
@bdbch bdbch deleted the claude/tiptap-issue-resolver-5Fueh branch February 13, 2026 03:11
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.

4 participants