yoursweater
yoursweater

Reputation: 2029

How do you put a line break in a React string?

I have a text file that I'm reading as a string, and then inserting into the DOM like so:

//the state gets set with the contents of a text file that has proper indentation
  state = {
    parsedText: null
  }
//in the render function, this is how the text comes in
<p>{this.state.parsedText}</p>

When I iterate through the character codes, I can see that the 'enter' codes (i.e., 13) seem to work when I console.log the file (the indentation looks correct). Unfortunately, those character codes don't translate to HTML - the entire string just comes out as one solid chunk of text. So, what I'm trying to do is insert either <br> tags or \n characters or &nbsp; in order to make the breaks work in the HTML.

Here's what that looks like:

rawFile.onreadystatechange = () => {
    if (rawFile.readyState === 4) {
        if (rawFile.status === 200 || rawFile.status == 0) {
            let allText = rawFile.responseText;
            for (let i = 0; i < allText.length; i++) {
              let uni = allText.charCodeAt(i)
              if (uni === 13) {
                console.log('enter!!')
                allText = allText.substring(0, i) + "\n" + allText.substring(i + 1, allText.length - 1)
              }
            }
            console.log("allText: ", allText);
            console.log(typeof allText)
            this.setState({
                parsedText: allText
            });
        }
    }
};
rawFile.send(null);

}

The \n insertions show up in the text string but are seemingly just ignored in the DOM. Is there a way to make this work? I've tried dangerouslySetInnerHTML and that does nothing.

Any ideas on how to make this work?

Upvotes: 8

Views: 31846

Answers (4)

Ido Cohen
Ido Cohen

Reputation: 800

Had the same issue. just solved it.

All you need to do is to save the string as array. like so:

let text = "this is text without break down \n this won't work but will be one line"

let text = ["this is text with breakdown",
 <br/>,
 "this is the second line"];

You can also write utility function to do that for you:

const addLineBreak = (str: string) =>
  str.split('\n').map((subStr) => {
    return (
      <>
        {subStr}
        <br />
      </>
    );
  });

And use it:

<p>{addLineBreak("Hello \n World"}</p>

Here's an example on StackBlitz for your reference.

Hope that helps

Upvotes: 24

CodingYourLife
CodingYourLife

Reputation: 8626

If you want to print a <br/> tag in react I wanted to point out that a neat workaround is to use the <Trans> component from i18next.

If you have a variable like this:

const customInviteMessageByCreator = "DEMO APPOINTMENT<br/>This room is to test your video room.";

You can write your variable wrapped in a Trans component like so:

<Trans>{customInviteMessageByCreator}</Trans>

And then it replaces the whitelisted html elements that you can configure in your i18n.js file like this:

transKeepBasicHtmlNodesFor: ["br", "strong", "b", "i"],

I didn't read that this is possible but I was curious if it works because i18next also translates our linebreaks in the translation.json and indeed it does.

I think it is a less hacky and more reliable method than what I've found so far like doing a map on <br> where there could be a / before the >. Plus you can whitelist more than just linebreaks. And of course a smarter choice over dangerouslySetInnerHtml.

Upvotes: 0

Neil
Neil

Reputation: 2058

If possible, avoid using dangerouslySetInnerHTML.

An alternate solution could be splitting your text into an array then rendering a new div for each "newline".

Of course, you would need to come up with a better key for the text, as there could be duplicate text - though that is a separate question in and of itself.

class Hello extends React.Component {
  constructor(props) {
  	super(props)
    this.state = {
      parsedText: [
        "Some text",
        "More text",
        "Keep on texting"
      ]
    }
  }
	
  render() {
    return <div>{this.state.parsedText.map(text => <div key={text}>{text}</div>)}</div>;
  }
}

ReactDOM.render(
  <Hello/>,
  document.getElementById('container')
);
<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="container">
    <!-- This element's contents will be replaced with your component. -->
</div>

Upvotes: 2

yoursweater
yoursweater

Reputation: 2029

So you need to dangerouslySetInnerHTML, and as was pointed by FrV, the answer is to insert a <br /> ... turns out I was missing the closing "/". Whoops. Hope this helps somebody running into a similar problem.

Upvotes: -1

Related Questions