How to strip HTML tags from string in JavaScript? [duplicate]
Asked Answered
C

4

319

How can I strip the HTML from a string in JavaScript?

Clouded answered 15/2, 2011 at 9:56 Comment(0)
F
320

Using the browser's parser is the probably the best bet in current browsers. The following will work, with the following caveats:

  • Your HTML is valid within a <div> element. HTML contained within <body> or <html> or <head> tags is not valid within a <div> and may therefore not be parsed correctly.
  • textContent (the DOM standard property) and innerText (non-standard) properties are not identical. For example, textContent will include text within a <script> element while innerText will not (in most browsers). This only affects IE <=8, which is the only major browser not to support textContent.
  • The HTML does not contain <script> elements.
  • The HTML is not null
  • The HTML comes from a trusted source. Using this with arbitrary HTML allows arbitrary untrusted JavaScript to be executed. This example is from a comment by Mike Samuel on the duplicate question: <img onerror='alert(\"could run arbitrary JS here\")' src=bogus>

Code:

var html = "<p>Some HTML</p>";
var div = document.createElement("div");
div.innerHTML = html;
var text = div.textContent || div.innerText || "";
Flaky answered 15/2, 2011 at 10:40 Comment(14)
Nice answer, I didn't know about textContent. How many browsers do textContent + innerText cover? BTW, I've edited my answer to include the jQuery way.Omora
@Felix: All major browsers have at least one of textContent and innerText.Flaky
Doesn't work when the string contains something like <script>alert('hi');</script>. Then it crashes with "illegal token at" etc..Sharolynsharon
Good caveats. In case it is not already clear I wanted to add that Firefox will crash on div.innerHTML = html if the value of html is NULL. Worse, it won't properly report the error (instead says parent function has TypeError). Chrome/IE do not crash.Nutritive
SECURITY ISSUE ... This could be vulnerable as you're setting div.innerHTML ... i'm sure you don't wanted to get some unwanted script executed. ... manual cleanup would be cool.Basion
@alee-sindhu: I think the caveats cover that.Flaky
Elegant solution, but isn't universal. It doesn't work if you use it on node server because of the document dependencyNollie
using React Native 0.51, can't use this solutionEmplane
<p>test</p><p>test</p> gives testtest, should have spave or newline betweenKimura
@eomeroff: That isn't what this question is asking for.Flaky
Literally it is not. But having contents of two paragraphs becoming one word makes no sense.Kimura
@eomeroff: Whether it makes sense depends on the context. What input do you want to accept and what do you require the output to be?Flaky
@TimDown the one that closely corresponds to what is rendered with two <p> tags. For example, you take content from a rich text editor, remove the tags and past it to notepad. Should have the same spaces or/and line breaks.Kimura
var text = new DOMParser().parseFromString("<p>Some HTML</p>", "text/html").body.textContent || ""; one line versionMosemoseley
T
508
cleanText = strInputCode.replace(/<\/?[^>]+(>|$)/g, "");

Distilled from this website (web.achive).

This regex looks for <, an optional slash /, one or more characters that are not >, then either > or $ (the end of the line)

Examples:

'<div>Hello</div>' ==> 'Hello'
 ^^^^^     ^^^^^^
'Unterminated Tag <b' ==> 'Unterminated Tag '
                  ^^

But it is not bulletproof:

'If you are < 13 you cannot register' ==> 'If you are '
            ^^^^^^^^^^^^^^^^^^^^^^^^
'<div data="score > 42">Hello</div>' ==> ' 42">Hello'
 ^^^^^^^^^^^^^^^^^^          ^^^^^^

If someone is trying to break your application, this regex will not protect you. It should only be used if you already know the format of your input. As other knowledgable and mostly sane people have pointed out, to safely strip tags, you must use a parser.

If you do not have acccess to a convenient parser like the DOM, and you cannot trust your input to be in the right format, you may be better off using a package like sanitize-html, and also other sanitizers are available.

Terrorist answered 15/2, 2011 at 10:1 Comment(12)
Sorry, but that would break <img alt="a>b" src="a_b.gif" />Clouded
@Clouded people who make a hobby out of breaking the ill-use of regular expressions for parsing general HTML are great. It is a great hobby.Epaminondas
@Ziggy: That sounds an awful lot like sarcasm...Clouded
@Clouded no! Really! Every time I read one of these comment threads I get a little thrill. "Ho ho ho," I think "<img alt=\"a>b\" src=\"a_b.gif\" />, so clever!"Epaminondas
@Clouded That would be buggy html, it had to be <img alt="a&gt;b" .Lyudmila
Not in HTML5, the syntax can be different. @LyudmilaDotson
using reg is not good approach #1732848Carpal
Could we improve it with <(?:[^><\"\']*?(?:([\"\']).*?\1)?[^><\'\"]*?)+(?:>|$) ?Leveroni
this code will remove <18 as well while <18 is not a tag, it just a stringKind
could somebody please what his regex eliminates and what it keeps? It works great for my needs so need to understand.Morphinism
@Morphinism explained what this regex does in the answer body.Terrorist
Using regexp is a perfectly fine approach if I control everything. Which I sometimes do.Female
F
320

Using the browser's parser is the probably the best bet in current browsers. The following will work, with the following caveats:

  • Your HTML is valid within a <div> element. HTML contained within <body> or <html> or <head> tags is not valid within a <div> and may therefore not be parsed correctly.
  • textContent (the DOM standard property) and innerText (non-standard) properties are not identical. For example, textContent will include text within a <script> element while innerText will not (in most browsers). This only affects IE <=8, which is the only major browser not to support textContent.
  • The HTML does not contain <script> elements.
  • The HTML is not null
  • The HTML comes from a trusted source. Using this with arbitrary HTML allows arbitrary untrusted JavaScript to be executed. This example is from a comment by Mike Samuel on the duplicate question: <img onerror='alert(\"could run arbitrary JS here\")' src=bogus>

Code:

var html = "<p>Some HTML</p>";
var div = document.createElement("div");
div.innerHTML = html;
var text = div.textContent || div.innerText || "";
Flaky answered 15/2, 2011 at 10:40 Comment(14)
Nice answer, I didn't know about textContent. How many browsers do textContent + innerText cover? BTW, I've edited my answer to include the jQuery way.Omora
@Felix: All major browsers have at least one of textContent and innerText.Flaky
Doesn't work when the string contains something like <script>alert('hi');</script>. Then it crashes with "illegal token at" etc..Sharolynsharon
Good caveats. In case it is not already clear I wanted to add that Firefox will crash on div.innerHTML = html if the value of html is NULL. Worse, it won't properly report the error (instead says parent function has TypeError). Chrome/IE do not crash.Nutritive
SECURITY ISSUE ... This could be vulnerable as you're setting div.innerHTML ... i'm sure you don't wanted to get some unwanted script executed. ... manual cleanup would be cool.Basion
@alee-sindhu: I think the caveats cover that.Flaky
Elegant solution, but isn't universal. It doesn't work if you use it on node server because of the document dependencyNollie
using React Native 0.51, can't use this solutionEmplane
<p>test</p><p>test</p> gives testtest, should have spave or newline betweenKimura
@eomeroff: That isn't what this question is asking for.Flaky
Literally it is not. But having contents of two paragraphs becoming one word makes no sense.Kimura
@eomeroff: Whether it makes sense depends on the context. What input do you want to accept and what do you require the output to be?Flaky
@TimDown the one that closely corresponds to what is rendered with two <p> tags. For example, you take content from a rich text editor, remove the tags and past it to notepad. Should have the same spaces or/and line breaks.Kimura
var text = new DOMParser().parseFromString("<p>Some HTML</p>", "text/html").body.textContent || ""; one line versionMosemoseley
O
89
var html = "<p>Hello, <b>World</b>";
var div = document.createElement("div");
div.innerHTML = html;
alert(div.innerText); // Hello, World

That pretty much the best way of doing it, you're letting the browser do what it does best -- parse HTML.


Edit: As noted in the comments below, this is not the most cross-browser solution. The most cross-browser solution would be to recursively go through all the children of the element and concatenate all text nodes that you find. However, if you're using jQuery, it already does it for you:

alert($("<p>Hello, <b>World</b></p>").text());

Check out the text method.

Omora answered 15/2, 2011 at 10:1 Comment(11)
Not every browser supports innerText.Flaky
A concise jQuery could look like: var html = "<b>test</b>"; var text = $("<div/>").html(html).text(); Using $("<div/>") lets you reuse the same element and less memory for consecutive calls or for loops.Louvenialouver
Same problem, crash it with: $(...).html('<script>alert("hi");</script>').text();Sharolynsharon
and check out the text method for var txt = "<p>my line</p><p>my other line</p>some other text"; alert($(txt).text(); where you don't proxy the string within a dom node. 3 lines in, 2 lines out.Sitka
I like the jQuery solution because it is not vulnerable to code injection, as far as I know.Seventh
Doesn't handle well whitespaces.Cleaver
This was perfect solution for me, thank you!Kif
JS injection is possible if the HTML text is comming from unknown sources.Slowworm
The jQuery solution is the best for all of us (most of us, I guess) who already use it almost everywhere. Just keep in mind that if the string is in a variable, you will have to insert it in an element, e.g. let text = $(`<div>${html_fragment}</div>`).Crust
function removeTags(str) { if ((str===null) || (str==='')) return false; else str = str.toString(); return str.replace( /(<([^>]+)>)/ig, ''); } document.write(removeTags('<html> <body> Javascript<body> is not Java'));;Posthumous
doesnt work on node.jsPo
S
34

I know this question has an accepted answer, but I feel that it doesn't work in all cases.

For completeness and since I spent too much time on this, here is what we did: we ended up using a function from php.js (which is a pretty nice library for those more familiar with PHP but also doing a little JavaScript every now and then):

http://phpjs.org/functions/strip_tags:535

It seemed to be the only piece of JavaScript code which successfully dealt with all the different kinds of input I stuffed into my application. That is, without breaking it – see my comments about the <script /> tag above.

Sharolynsharon answered 7/9, 2012 at 16:14 Comment(4)
^ this, definitely better than the accepted answer for Chrome 30.0 and aboveGio
Works nicely on server-side without DOM support, e.g. Google Apps Script.Sackcloth
If you use the allowed param you are vulnerable to XSS: stripTags('<p onclick="alert(1)">mytext</p>', '<p>') returns <p onclick="alert(1)">mytext</p>Tesler
Updated link: locutus.io/php/strings/strip_tagsOrson

© 2022 - 2024 — McMap. All rights reserved.