# How to preserve \<br\> tags in empty paragraphs

**URL:** https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051
**Category:** Uncategorized
**Created:** [July 1, 2019, 2:38pm UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051 "2019-07-01T14:38:53Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![cellux](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/c/bc8723/32.png) [@cellux](https://discuss.prosemirror.net/u/cellux)
#### Post date: [July 1, 2019, 2:38pm UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/1 "2019-07-01T14:38:53Z")

</div>

Hi.

In the app I’m working on, the user can click on various HTML elements (currently P and H1-H6) to edit their contents. When the user clicks on element E, I parse the contents of E into a ProseMirror document, set up a state and a view, then render the view into E. When the user blurs the editor, I serialize the ProseMirror document and replace the contents of E with the resulting fragment.

This works as expected, with one glitch: if I append empty paragraphs (`<p></p>`) to the end of the edited content (by pressing Enter a number of times at the end of the text), ProseMirror renders these empty paragraphs as `<p><br></p>` which looks alright while the editor is active, but as soon as I blur the editor, these turn into actual empty paragraphs (`<p></p>`) which are not displayed by the browser.

Blurring (unmounting) the editor and then focusing (mounting) it again thus makes the empty paragraphs disappear then reappear which is not too pretty.

Do you have any pointers on how this problem could be solved? (I’d prefer not to apply any modifications to the CSS of the page.)

---

<div class="post-metadata">

### Author: ![cellux](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/c/bc8723/32.png) [@cellux](https://discuss.prosemirror.net/u/cellux)
#### Post date: [July 2, 2019, 1:32pm UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/2 "2019-07-02T13:32:43Z")

</div>

I managed to solve my problem.

If I represent empty paragraphs in the DOM as `<p>&nbsp;</p>`, these show up in the browser as expected (they do not collapse). When I parse this DOM into a ProseMirror document, I use a paragraph rule like this:

```auto
const EMPTY_PARAGRAPH_CONTENT = '\u00A0'; // non-breaking space (&nbsp;)

paragraph: {
	content: 'inline*',
	group: 'block',
	parseDOM: [
		// rule to identify empty paragraphs
		{
			tag: 'p',
			priority: 51, // try to match this first
			getAttrs(value) {
				let el = value;
				// empty paragraphs are stored with a non-visible marker
				// inside them to prevent collapse by Firefox and Chrome
				if (el.textContent !== EMPTY_PARAGRAPH_CONTENT) {
					return false; // skip this rule
				}
				// match
				return null;
			},
			getContent() {
				// remove marker while editing
				//
				// ProseMirror will add <br> tags inside <p></p> to ensure
				// that empty paragraphs show up inside the contenteditable
				//
				// we will re-add the marker when the editor is closed
				return Model.Fragment.empty;
			},
		},
		// rule to identify generic paragraphs
		{
			tag: 'p',
		},
	],
	toDOM: (node) => ['p', 0]
},

```

When the user leaves the contenteditable, I serialize the ProseMirror document and do an extra conversion step on the resulting DocumentFragment:

```auto
function fixEmptyParagraphs(fragment) {
	// add a non-visible marker to all empty paragraphs to prevent
	// visual collapse of the paragraphs in Firefox and Chrome
	function fix(node) {
		if (node.hasChildNodes()) {
			node.childNodes.forEach(fix);
		} else if (node instanceof HTMLElement && node.tagName === 'P') {
			node.appendChild(document.createTextNode(EMPTY_PARAGRAPH_CONTENT));
		}
	}

	fix(fragment);
}

```

This way the `&nbsp;` is only present in the saved data, ProseMirror does not see it and can employ its BR hacks to ensure empty paragraphs are shown as intended internally.

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [July 3, 2019, 10:55am UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/3 "2019-07-03T10:55:01Z")

</div>

The `<br>` nodes in empty textblocks are a standard kludge in editable content to make sure empty blocks show up and avoid weird cursor issues. ProseMirror doesn’t add them to the actual document content, but just renders them in the editable view. Making the paragraphs show up when rendered outside the editor is a separate problem, which you could fix with, for example, a css rule using the `:empty` pseudoselector.

---

<div class="post-metadata">

### Author: ![amk221](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/amk221/32/2076_2.png) [@amk221](https://discuss.prosemirror.net/u/amk221)
#### Post date: [July 29, 2021, 12:13pm UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/4 "2021-07-29T12:13:28Z")

</div>

I am also hoping to keep the `br`'s that ProseMirror adds (but then takes away).

By doing this:

```auto
toDOM(node) {
  return node.content.size === 0 ? ['p', ['br']] : ['p', 0];
}

```

But there is no way to allow `['p', ['br']]` to have a hole. So when the empty paragraph is created, it’s uneditable.

Any ideas? 🤔

(p.s. I’m actually using divs, not p’s)

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [July 30, 2021, 10:40am UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/5 "2021-07-30T10:40:37Z")

</div>

> [@amk221](#):
>
> But there is no way to allow `['p', ['br']]` to have a hole. So when the empty paragraph is created, it’s uneditable.

Definitely don’t use a `toDOM` like that in your editor. It’s possible to create a custom `DOMSerializer` for serialization outside of the editor.

---

<div class="post-metadata">

### Author: ![amk221](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/amk221/32/2076_2.png) [@amk221](https://discuss.prosemirror.net/u/amk221)
#### Post date: [July 30, 2021, 11:01am UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/6 "2021-07-30T11:01:27Z")

</div>

Thanks, worked a treat

---

<div class="post-metadata">

### Author: ![leedalei](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/leedalei/32/2321_2.png) [@leedalei](https://discuss.prosemirror.net/u/leedalei)
#### Post date: [February 22, 2022, 6:52am UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/7 "2022-02-22T06:52:31Z")

</div>

It works for me, thanks a lot~

---

<div class="post-metadata">

### Author: ![xyz](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/x/b5a626/32.png) [@xyz](https://discuss.prosemirror.net/u/xyz)
#### Post date: [March 23, 2023, 2:03pm UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/8 "2023-03-23T14:03:51Z")

</div>

Hi, sorry to bump this old topic. I too want the output HTML to look the same as in the editor-view. But I cannot get this to work. Modifying the DOMSerializer would be perfect. That way I could just modify this function provided by the TipTap team:

```auto
import { DOMSerializer, Node, Schema } from '@tiptap/pm/model'
import { createHTMLDocument, VHTMLDocument } from 'zeed-dom'

export function getHTMLFromFragment(doc: Node, schema: Schema): string {
  const document = DOMSerializer.fromSchema(schema).serializeFragment(doc.content, {
    document: createHTMLDocument() as unknown as Document,
  }) as unknown as VHTMLDocument

  return document.render()
}

```

But I cannot figure out where/how I should modify it. Thanks for any efforts!

---

<div class="post-metadata">

### Author: ![marijn](https://discuss.prosemirror.net/user_avatar/discuss.prosemirror.net/marijn/32/15_2.png) [@marijn](https://discuss.prosemirror.net/u/marijn)
#### Post date: [March 23, 2023, 2:29pm UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/9 "2023-03-23T14:29:01Z")

</div>

You’ll want to adjust the serializer. Something like…

```auto
let base = DOMSerializer.fromSchema(schema)
let serializer = new DOMSerializer({
  ...base.nodes,
  paragraph(node) { return ... }
}, base.marks)

```

---

<div class="post-metadata">

### Author: ![xyz](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/x/b5a626/32.png) [@xyz](https://discuss.prosemirror.net/u/xyz)
#### Post date: [March 25, 2023, 2:10pm UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/10 "2023-03-25T14:10:02Z")

</div>

Thank you!

Because this ranks high in Google. Here is a [package](https://www.npmjs.com/package/pm2html) that I created to manipulate the DOMSerializer to create your own serialisation-logic in node.

It comes with a Transformer to add a `<br>` to all empty Textblocks

---

<div class="post-metadata">

### Author: ![kaes\_vorelay](https://discuss.prosemirror.net/letter_avatar_proxy/v4/letter/k/48db29/32.png) [@kaes\_vorelay](https://discuss.prosemirror.net/u/kaes_vorelay)
#### Post date: [August 22, 2024, 12:35am UTC](https://discuss.prosemirror.net/t/how-to-preserve-br-tags-in-empty-paragraphs/2051/11 "2024-08-22T00:35:18Z")

</div>

Hi guys) There is a simple way. Just add the following CSS code, it solves the problem with the disappearing br tag

```auto
.content p:empty {
    min-height: 20px;
}

```
