95

Let's say I want to dynamically create a new DOM element and fill up its textContent/innerText with a JS string literal.
The string is so long I would like to split it into three chunks:

var h1 = document.createElement("h1");

h1.textContent = "This is a very long string and I would like to insert a carriage return HERE...
moreover, I would like to insert another carriage return HERE... 
so this text will display in a new line";

The problem is, if i write

h1.textContent = "...I would like to insert a carriage return here... \n";

it doesn't work, probably because the browser considers the '\n' to be pure text and displays it as such (the \r doesn't work either).

On the other hand, I could change the h1.innerHTML instead of the textContent and write:

h1.innerHTML = "...I would like to insert a carriage return here...<br />";

Here the <br /> would do the job, but doing so would replace not just the text content but all the HTML content of my h1, which is not quite what I want.

Is there a simple way to solve my problem?
I wouldn't resort to creating multiple block elements just to have the text on different lines.

starball
  • 20,030
  • 7
  • 43
  • 238
user1236489
  • 997
  • 1
  • 6
  • 5

14 Answers14

179

I know this question posted long time ago.

I had similar problem few days ago, passing value from web service in json format and place it in table cell contentText.

Because value is passed in format, for example, "text row1\r\ntext row2" and so on.

For new line in textContent You have to use \r\n and, finally, I had to use css white-space: pre-line; (Text will wrap when necessary, and on line breaks) and everything goes fine.

Or, You can use only white-space: pre; and then text will wrap only on line breaks (in this case \r\n).

So, there is example how to solve it with wrapping text only on line breaks :

var h1 = document.createElement("h1");

//setting this css style solving problem with new line in textContent
h1.setAttribute('style', 'white-space: pre;');

//add \r\n in text everywhere You want for line-break (new line)
h1.textContent = "This is a very long string and I would like to insert a carriage return \r\n...";
h1.textContent += "moreover, I would like to insert another carriage return \r\n...";
h1.textContent += "so this text will display in a new line";

document.body.appendChild(h1);
nelek
  • 4,074
  • 3
  • 22
  • 35
  • 20
    Lol, this answer is the ONLY correct answer to the question, but it is under-voted and had no comments until now... It seems that people here can't read correctly. The question was about using `textContent`. Using CSS is an alternative way to solve it (maybe the cleanest). So perfect answer. Thank you! – StanE Nov 23 '16 at 12:39
  • 3
    Exact this worked like a charm. I have a textarea where to split text with new lines and this is the solution – Robert Feb 28 '19 at 16:34
  • @Barrosy in question that's wasn't named as problem... it's like you tell you don't have access to complete web site at all... million possibilities. This is a specific answer to a specific question. – nelek Dec 20 '22 at 16:30
  • after spending four hours finaly r\n\ solved my problem in subtitle editing . – Preet Singh Jan 07 '23 at 16:52
  • @PreetSingh btw. that's wroted in soludion `//add \r\n in text everywhere You want for line-break (new line)` ;) – nelek Jan 09 '23 at 11:13
  • @nelek i didn't answer the questions actually meant that provided solution solved my problem h nce upvoted the answer;) – Preet Singh Jan 09 '23 at 16:35
  • 1
    Thanks mate, works without any problem! – hhsm95 Jan 28 '23 at 04:24
33

I ran into this a while ago. I found a good solution was to use the ASCII representation of carriage returns (CODE 13). JavaScript has a handy feature called String.fromCharCode() which generates the string version of an ASCII code, or multiple codes separate by a comma. In my case, I needed to generate a CSV file from a long string and write it to a text area. I needed to be able to cut the text from the text area and save it into notepad. When I tried to use the <br /> method it would not preserve the carriage returns, however, using the fromCharCode method it does retain the returns. See my code below:

h1.innerHTML += "...I would like to insert a carriage return here..." + String.fromCharCode(13);
h1.innerHTML += "Ant the other line here..." + String.fromCharCode(13);
h1.innerHTML += "And so on..." + String.fromCharCode(13);
h1.innerHTML += "This prints hello: " + String.fromCharCode(72,69,76,76,79);

See here for more details on this method: w3Schools-fromCharCode()

See here for ASCII codes: ASCII Codes

BenMorel
  • 34,448
  • 50
  • 182
  • 322
JBausmer
  • 914
  • 9
  • 11
  • 26
    This is just plain wrong, On many levels. 13 is carriage return. It can be equivalently written as `'\r'` (`'\r' === String.fromCharCode(13)` gives true). Unless you are on Classic Mac, it is the wrong character for newline. Newline is ASCII 10, or `'\n'`. However in HTML the only newline is `
    `. Both `\r` and `\n` are rendered as space except in `
    `. The `innerText` and `innerHtml` however convert both characters to `
    ` for convenience, so it happens to work. I have not checked the specification whether it works by design (and I would _not_ believe that much).
    – Jan Hudec Jun 01 '15 at 15:46
  • 8
    Old answer and I might be wrong, but how does this solve the question? I have the same problem and the question was about using `textContent`, not `innerHTML`. – StanE Nov 23 '16 at 12:35
  • 1
    For the specific situation of copying text to the clipboard, this works perfectly in all the browsers I have tested. Using '\n' gives varied results depending on the browser. – Valid Jun 22 '17 at 17:57
  • This was the only thing that worked for me, and I tried all 10 different solutions posted to this question so far. – davea0511 Nov 20 '17 at 22:34
12

nelek's answer is the best one posted so far, but it relies on setting the css value: white-space: pre, which might be undesirable.

I'd like to offer a different solution, which tries to tackle the real question that should've been asked here:

"How to insert untrusted text into a DOM element?"

If you trust the text, why not just use innerHTML?

domElement.innerHTML = trustedText.replace(/\r/g, '').replace(/\n/g, '<br>');

should be sufficient for all the reasonable cases.

If you decided you should use .textContent instead of .innerHTML, it means you don't trust the text that you're about to insert, right? This is a reasonable concern.

For example, you have a form where the user can create a post, and after posting it, the post text is stored in your database, and later on appended to pages whenever other users visit the relevant page.

If you use innerHTML here, you get a security breach. i.e., a user can post something like

<script>alert(1);</script>

which won't trigger an alert if you use innerHTML, but it should give you an idea why using innerHTML can have issues. a smarter user would post

<img src="invalid_src" onerror="alert(1)" />

which would trigger an alert for every other user that visits the page. Now we have a problem. An even smarter user would put display: none on that img style, and make it post the current user's cookies to a cross domain site. Congratulations, all your user login details are now exposed on the internet.

So, the important thing to understand is, using innerHTML isn't wrong, it's perfect if you're just using it to build templates using only your own trusted developer code. The real question should've been "how do I append untrusted user text that has newlines to my HTML document".

This raises a question: which strategy do we use for newlines? do we use
elements?

s or s?

Here is a short function that solves the problem:

function insertUntrustedText(domElement, untrustedText, newlineStrategy) {
    domElement.innerHTML = '';
    var lines = untrustedText.replace(/\r/g, '').split('\n');
    var linesLength = lines.length;
    if(newlineStrategy === 'br') {
        for(var i = 0; i < linesLength; i++) {
            domElement.appendChild(document.createTextNode(lines[i]));
            domElement.appendChild(document.createElement('br'));
        }
    }
    else {
        for(var i = 0; i < linesLength; i++) {
            var lineElement = document.createElement(newlineStrategy);
            lineElement.textContent = lines[i];
            domElement.appendChild(lineElement);
        }
    }
}

You can basically throw this somewhere in your common_functions.js file and then just fire and forget whenever you need to append any user/api/etc -> untrusted text (i.e. not-written-by-your-own-developer-team) to your html pages.

usage example:

insertUntrustedText(document.querySelector('.myTextParent'), 'line1\nline2\r\nline3', 'br');

the parameter newlineStrategy accepts only valid dom element tags, so if you want [br] newlines, pass 'br', if you want each line in a [p] element, pass 'p', etc.

Elijah Mock
  • 587
  • 8
  • 21
Aqo
  • 343
  • 4
  • 16
  • 1
    How can I display additional spaces based on textContent?   does not work here. – krave Jul 29 '19 at 02:54
  • @krave to support more whitespace characters you'll have to extend the function to be familiar with them – Aqo Jul 30 '19 at 18:26
5

Change the h1.textContent to h1.innerHTML and use <br> to go to the new line.

Steven
  • 1,996
  • 3
  • 22
  • 33
atrgn
  • 61
  • 1
  • 3
4

You can concatenate the strings...

h1.innerHTML += "...I would like to insert a carriage return here...<br />";
h1.innerHTML += "Ant the other line here... <br />";
h1.innerHTML += "And so on...<br />";

jsFiddle.

Icarus
  • 63,293
  • 14
  • 100
  • 115
4

You could use regular expressions to replace the '\n' or '\n\r' characters with '<br />'.

you have this:

var h1 = document.createElement("h1");

h1.textContent = "This is a very long string and I would like to insert a carriage return HERE...
moreover, I would like to insert another carriage return HERE... 
so this text will display in a new line";

you can replace your characters like this:

h1.innerHTML = h1.innerHTML.replace(/\r\n?/g, '<br />');

check the javascript reference for the String and Regex objects:

http://www.w3schools.com/jsref/jsref_replace.asp

http://www.w3schools.com/jsref/jsref_obj_regexp.asp

Rodrigo
  • 400
  • 3
  • 7
3

Use element.innerHTML="some \\\\n some";.

Marlon
  • 19,924
  • 12
  • 70
  • 101
martin
  • 47
  • 1
3

None of the above solutions worked for me. I was trying to add a line feed and additional text to a <p> element. I typically use Firefox, but I do need browser compatibility. I read that only Firefox supports the textContent property, only Internet Explorer supports the innerText property, but both support the innerHTML property. However, neither adding <br /> nor \n nor \r\n to any of those properties resulted in a new line. The following, however, did work:

<html>
<body>
<script type="text/javascript">
  function modifyParagraph() {

  var p;
  p=document.getElementById("paragraphID");
  p.appendChild(document.createElement("br"));
  p.appendChild(document.createTextNode("Additional text."));
}    
</script>

<p id="paragraphID">Original text.</p>

<input type="button" id="pbutton" value="Modify Paragraph" onClick="modifyParagraph()" />
</body>
</html>
  • 2
    as you can see, if you read question again, it's not about `innerHTML` but **`textContent`** ... user doesn't have problem with `innerHTML` ... so, how this solution is correct? All solutions are based on `innerHTML` but none of `textContent` ... they are not the same. – nelek Dec 15 '16 at 16:11
  • I didn't think the problem was solvable using textContent, so instead of providing evidence and documentation proving the problem could not be solved, I provided an alternative. In my opinion, questions are useless without answers, and often the answer is not where we think it is. – Slogmeister Extraordinaire Dec 26 '16 at 01:04
  • 2
    Why isn't solvable? Imagine this: I want to set `contenteditable` for `div` element (now it's no matter why)... how You gonna solve this problem with new line using `javascript`? And, what is the purpose of `innerHTML` in that case? That's why some people use `textContent/innerText` and everything about `innerHTML` doesn't have any purpose anymore. That is the point about `textContent/innerText`. And, anyway, like You can see, it's solvable. – nelek Jan 26 '17 at 12:28
1

I found that inserting \\n works. I.e., you escape the escaped new line character

Lenka Pitonakova
  • 979
  • 12
  • 14
1

I was having this problem, and after adding the css styling as Nelek answer suggests, I managed to get it working with template string. I wanted to use the template strings as I was pulling and displaying data from other elements.

var h1 = document.createElement("h1");

//setting this css style solving problem with new line in textContent.  

    h1.setAttribute('style', 'white-space: pre;');

// Using backticks worked for me after adding the css styling

    h1.textContent = `
       Hello, my name is
       ${name.firstName()} ${name.lastName()}.
       Today is
       ${date}.
    `;

document.body.appendChild(h1);
10 Rep
  • 2,217
  • 7
  • 19
  • 33
Pazoia
  • 21
  • 2
1

By Using the pre tag in HTML we can directly format by using standard escape sequence strings like '\n' or '\r';

HTML:

<pre id="identifier"></pre>

JS:

const identifierDisplay = document.getElementById("identifier");
const identifierS = "Data to display. \n Some more data"
identifierDisplay.textContent = identifierS;

Take care of the formatting in the string any tabs or spaces are directly reflected.

0

The following code works well (On FireFox, IE and Chrome) :

var display_out = "This is line 1" + "<br>" + "This is line 2";

document.getElementById("demo").innerHTML = display_out;
Apprentice
  • 27
  • 1
0

A way to do it while still being safe from XSS injection is as follows:

function newLines(element, lines, separator = "!newline!") {
    element.textContent = lines.join(separator);
    element.innerHTML = element.innerHTML.replaceAll(separator, "<br>");
}

And you can call it like

newLines(h1, ["a", "b", "c", "<script>alert(2)</script>"])

The idea is to first put all the content into textContent, injecting the separator into the appropriate places and then replacing the separator with <br>

Lajos Arpad
  • 64,414
  • 37
  • 100
  • 175
0

Nelek's answer up top is a great answer for multi line textContent. Just adding the use of template literals. With Template Literals \r\n not required.

var h1 = document.createElement("h1");

// setting white-space css property to get new line in textContent
h1.setAttribute('style', 'white-space: pre-line;');

// use template literals `` to add carriage returns directly in script
// new lines in script will be matched with new lines in textContent
h1.textContent = `This is a very long string and I would like to insert a carriage return
moreover, I would like to insert another carriage return
so this text will display in a new line`;

document.body.appendChild(h1);
Fitz
  • 1
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 04 '23 at 16:20