# Rendering plain text with paragraphs and line breaks as HTML

I have text inside a variable that I need to separate in paragraphs, and at the same time respect the manual breaklines.

This is my code:

{description.split('\n\n').map(paragraph => (
<p>
{paragraph.split('\n').map(
(line, index) =>
index > 0 ? (
<span>
<br />
{line}
</span>
) : (
line
)
)}
</p>
))}

I am not specially happy with the code. It is not very readable. Any ideas how to improve it?

Two things that help in cases like this (IMHO):

• Extract a function for more complex logic or a Array.map callback (e.g. to give a descriptive name and/or avoid nesting)
• Provide descriptive names for non-obvious stuff (e.g. I'd prefer firstLine and remainingLines (or something similar) over using index)

I'd probably do something like this:

description.split('\n\n').map(renderParagraph)

// If you are in a class, this could be a method on the class
function renderParagraph(paragraph) {
// With fancy ES6:
const [firstLine, ...rest] = paragraph.split('\n')
// Or ES5:
const lines = paragraph.split('\n')
const firstLine = lines[0]
const rest = lines.slice(1)

return (
<p>
{firstLine}
{rest.map(line => (
// React.Fragment doesn’t create a wrapper element in the DOM.
// If you don’t care about that, you can use div instead
<React.Fragment>
<br />
{line}
</React.Fragment>
)}
</p>
)
}
• This looks very readable. Asking because I don't know, why did you use React.Fragment? Is it better than span? – bhathiya-perera Feb 14 '19 at 13:24
• OK I read the documentation reactjs.org/docs/fragments.html, and fragments are clearly better. Because it avoids extra wrapper elements. Could you please add this part to the answer as well. ;) – bhathiya-perera Feb 14 '19 at 13:27
• Good suggestion, thanks. I changed the code comment to clarify my preference of React.Fragment – inyono Feb 14 '19 at 19:46

You almost got it perfectly.

The only bit that could be changed is the part putting <br/> tags between lines. If you want to build a JSX element by putting nodes between each array string, I would recommend using reduce.

Reduce will iterate over your array starting by the indexes 0 and 1. By outputting an array like the following : [total, <br />, line] you can build up your paragraph :

paragraph.split('\n').reduce((total, line) => [total, <br />, line])

Working example :

const text = Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua.

Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo consequat.

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur.Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum

const Renderer = () =>
<div>
{text.split('\n\n').map(paragraph =>
<p>
{paragraph.split('\n').reduce((total, line) => [total, <br />, line])}
</p>
)}
</div>

ReactDOM.render(
<Renderer />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'/>