rich-text: Missing converted line breaks in rich-text-html-renderer

When I’m using the rich-text-html-renderer I expect that also the line breaks are converted to HTML
also. Currently when I’ve some manual line breaks in a paragraph they are ignored completely.

Line1
Line2

should be converted to

<p>
Line1<br />
Line2
</p>

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 23

Most upvoted comments

@quinnmyers The above comments and examples are mainly referring to using rich-text-html-renderer, not rich-text-react-renderer. That’s why these examples use next rather than children.

The documentation for rich-text-react-renderer actually gives an example for how to use the renderText option to replace \n line breaks with <br />.

Try using this options definition:

const options = {
  renderText: text => text.split('\n').flatMap((text, i) => [i > 0 && <br />, text])
}

You can see a working example on codesandbox.io.

Thank you, @sbezludny for your code snipped above. It helped us allot See

renderNode: {
    [BLOCKS.PARAGRAPH]: (node, next) => next(node.content).replace('\n', '<br/>')
  }

I enhenced it a little bit, because your example stripped away the <p /> and only converted the first \n' into <br />

Maybe this is helpful for others as well

renderNode: {
  [BLOCKS.PARAGRAPH]: (node, next) => `<p>${next(node.content).replace(/\n/g, '<br/>')}</p>`,
}

Hey there,

for me works an ordinary white-space: pre-line; on the <p> which renders line breaks perfectly without adding <br>s to the DOM.

Like:

const Text = ({ children }) => (
  <p style={{ whiteSpace: 'pre-line' }}>{children}</p>
)

const renderOptions = {
  renderNode: {
    [BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,
  },
}

Hey @xyNNN, line breaks stored as new line separators within a text node.

"Before publishing your content, you can preview it using the Content Preview A\nPI."

However, unlike react-renderer, html-renderer does not expose renderText method to control the presentation of the text nodes.

The same behaviour could be achieved by hooking into renderNode renderer e.g.:

renderNode: {
    [BLOCKS.PARAGRAPH]: (node, next) => next(node.content).replace('\n', '<br/>')
  }

It is absolutely ridiculous why contentful makes it so hard to write content on the platform. Very frustrated

@arhoy Do you have any constructive feedback? We have thousands of users producing content each day, so not sure what exactly you find ridiculous.

My workaround for this was treating empty paragraph blocks as <br />. Leaving incase it helps anyone!

renderText: (text) => {
    if (!text) return <br />; // <-- THIS
    return text.split("\n").flatMap((text, i) => [i > 0 && <br />, text]);
  },

I had the problem that flatMap is not supported in my deployment. This is my hacky alternative that worked for me:

renderText: text =>
    text.split('\n').map((t, i) =>
      i > 0 ? (
        <React.Fragment key={`${i}-${t. slice(0, 5)}`}>
          <br />
          {t}
        </React.Fragment>
      ) : (
        t
      ),
    ),

Edit: using React.Fragment from the comment below

I’m using @DanweDE 's above solution in @contentful/rich-text-react-renderer at 13.4.0.

In Safari and Firefox, my content looks fine.

In Chrome, my line breaks are appearing as a strange missing character:

image

Turns out the culprit is U+2028 (Line separator).

See Chromium bug: https://bugs.chromium.org/p/chromium/issues/detail?id=550275

My hacky solution is:

renderText: (text) =>
  text
    .replace(/\u2028/g, "")
    .split("\n")
    .flatMap((text, i) => [i > 0 && <br />, text])

My constructive feedback 😉 would be to make it easy and simple to configure either the RTE and/or Content Model and/or rich-text-react-renderer to display line breaks as break elements. Either through some UI checkbox or some options key like renderNewlinesAsBreaks: true. Or all of the above.

Hope this helps someone.

Having line breaks should be the default or at least an option so we dont need to call string.replace() for each text on each render call…

I think I had the same problem with the linter. Mine also warned about the index in the key: react/no-array-index-key

<React.Fragment key={`${i}-${t. slice(0, 5)}`}>

This way the key should be pretty unique across the DOM