Dario Ghilardi

Dario Ghilardi

Stories, articles and tips for frontend developers.

Handling newlines with React

Suppose you have a Javascript variable containing multiple lines of text that you want to render in your React component. More or less you would have the following code:

const text = `This is a long string of text and it
  includes new line characters. We want this text
  to display properly using React.
`;

function App() {
  return (
    <p>{text}</p>
  );
}

If you try to run this example you will easily notice that, despite the text being on multiple lines, the output is displayed on one single line:

This is a long string of text and it includes new line characters. We want this text to display properly using React.

This might look unexpected at first, but it’s actually how text is displayed as default in HTML documents. In fact, text inside a container element is displayed following these rules:

  • multiple white spaces will be collapsed
  • newline characters will be handled the same as white spaces
  • lines will be broken as necessary to fill line boxes

This is also the reason why we use <br /> so often in our code to force a line break.
Let’s see how we can instead display the string above respecting line breaks.

Method 1 - Replace /n with <br />

The probably most intuitive solution consists into replacing the newline characters (\n, \r, \r\n depending on the operative system) with <br /> before printing the string. For example, using a the replace method and a regexp:

const printableText = text.replace(/(?:\r\n|\r|\n)/g, '<br />')

function App() {
  return (
    <p>{printableText}</p>
  );
}

Unfortunately, as you can see in this codesandbox, this won’t work as expected, because our variable now includes HTML tags that React will escape during rendering for security reasons.
This is what you will see in your page source code:

This is a long string of text and it&lt;br /&gt;  includes new line characters. We want this text&lt;br /&gt;  to display properly using React.&lt;br /&gt;

A little note about escaping: in some forums you might have read that you can avoid the escape of variable in React using dangerouslySetInnerHTML. Please, don’t do it.
It’s true, as shown in this codesandbox, that the following implementation will work fine:

const text = `This is a long string of text and it
  includes new line characters. We want this text
  to display properly using React.
`;

const printableText = text.replace(/(?:\r\n|\r|\n)/g, "<br />");

const dangerousText = { __html: printableText };

const App = () => <p dangerouslySetInnerHTML={dangerousText} />;

But it’s also a big risk from the security point of view. Drop this idea unless you really know what you are doing, as you might leave open doors for an XSS attack to your users.
You can read more about the security concerns while using dangerouslySetInnerHtml on the React documentation.

Method 2 - Replace /n with <br /> at render time

Another simple solution for rendering newlines in React consists in replacing the newline characters at runtime with jsx:

const App = () =>
  text.split('\n').map((value, index) => {
    return (
      <span key={index}>
        {value}
        <br />
      </span>
    );
  });

In this example the text is splitted into an array at every occurrence of the \n character, then map renders one <br /> after each line. You can see this solution in this CodeSandbox.

There is a little more logic but this solutions generally works fine.

Method 3 - Using Fragments

If the <span> in the previous example hurts you, React.Fragment (only available starting from React v16.2.0) can help:

import { Fragment } from 'react';

const App = () =>
  text.split("\n").map((value, index) => {
    return (
      <Fragment key={index}>
        {value}
        <br />
      </Fragment>
    );
  });

In this case the output is cleaner, as no wrapper <span> is printed. You can see a demo on this CodeSandbox.

Method 4 - Using CSS

Since the problem originates from how the browser renders the page it’s no surprise that a CSS-only solution is available.

The white-space property can be used to determine how white spaces inside an element are handled. Its default value is normal, which means:

Sequences of white space are collapsed. Newline characters in the source are handled the same as other white space. Lines are broken as necessary to fill line boxes.

This single property is tricky because it actually manages four aspects related to how text is rendered in a HTML container: white spaces/tabs, line breaks, text wrapping and end-of-line spaces.

The default value normal is exactly why our text is rendered on a single line. Changing the value of this property to one of the following values will instead preserve our line breaks:

  • pre
  • pre-wrap
  • pre-line
  • break-spaces

But which one should you choose? It depends on how you want to deal with white spaces, text wrapping and end-of-line spaces. The following table will probably clear the situation a little bit more.

New linesSpaces and tabsText wrappingEnd-of-line spaces
normalCollapseCollapseWrapRemove
nowrapCollapseCollapseNo wrapRemove
prePreservePreserveNo wrapPreserve
pre-wrapPreservePreserveWrapHang
pre-linePreserveCollapseWrapRemove
break-spacesPreserveCollapseWrapWrap

In general you can use pre-line or pre-wrap: spaces will be collapsed in case of pre-line or preserved in case of pre-wrap. You can check here how this two options behave into the interactive demo.

The white-space property is well supported by all major browsers and it’s also good solution for those who want to avoid any additional component logic.

Wrapping up

In this article we explored 4 methods to display line breaks in React, one is a dangerous solution and I it’s usually not worth pursuing, two are based on logic inside our React component and one is CSS-based.

If you think the CSS solution will fit your scenario better, I suggest you to pay attention at how white spaces will be displayed.

If instead you think the Javascript solution is better for you, I suggest you to wrap this logic in a reusable component in order to isolate it, test it and reuse it as much as you want without repeating yourself.

Improve your skills week by week.

Subscribe to my free newsletter to receive original quality content weekly.

By opting in here, you agree to receive value-adding, non-spammy, exclusive content that will help improve your frontend skills, with very few offers, if any. You also agree to the privacy policy.