Does anyone know of an easy way to escape HTML from strings in jQuery? I need to be able to pass an arbitrary string and have it properly escaped for display in an HTML page (preventing JavaScript/HTML injection attacks). I'm sure it's possible to extend jQuery to do this, but I don't know enough about the framework at the moment to accomplish this.
-
Also see perf: jsperf.com/…Christophe Roussy– Christophe Roussy2015年10月27日 09:39:48 +00:00Commented Oct 27, 2015 at 9:39
27 Answers 27
There is also the solution from mustache.js
var entityMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
'/': '/',
'`': '`',
'=': '='
};
function escapeHtml (string) {
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
return entityMap[s];
});
}
-
1Sorry to bother but is there anyway this can be reversed? i don't know regex so i need helpTony Patino– Tony Patino2022年01月29日 09:03:35 +00:00Commented Jan 29, 2022 at 9:03
-
1it would be handy if there were unit tests for this, but this seems like a better solutionspy– spy2022年12月11日 14:09:19 +00:00Commented Dec 11, 2022 at 14:09
-
What if the string is already escaped? This expression matches
&
except when it's followed by ( 1-8 letters followed by 0-2 digits OR#
followed by a 1-4 (decimal OR hex) digit number ) followed by;
. Pattern:/([<>"'`=\/]|&(?!([a-zA-Z]{1,8}\d{0,2}|#(\d{1,4}|x[a-zA-Z\d]{1,4}));))/g
Use:escapeHtml('"This"	=	a &v3ry; &dumb; quote.')
Result:'"This"	=	a &v3ry; &dumb; quote.'
In DOM:'"This"\t=\ta &v3ry; &dumb; quote.'
Page display:"This" = a &v3ry; &dumb; quote.
Travis Bemrose– Travis Bemrose2023年02月09日 16:26:31 +00:00Commented Feb 9, 2023 at 16:26
Since you're using jQuery, you can just set the element's text
property:
// before:
// <div class="someClass">text</div>
var someHtmlString = "<script>alert('hi!');</script>";
// set a DIV's text:
$("div.someClass").text(someHtmlString);
// after:
// <div class="someClass"><script>alert('hi!');</script></div>
// get the text in a string:
var escaped = $("<div>").text(someHtmlString).html();
// value:
// <script>alert('hi!');</script>
-
1Is it safe ? linkedin.com/pulse/…paaacman– paaacman2022年01月18日 13:41:28 +00:00Commented Jan 18, 2022 at 13:41
-
@paaacman setting the property with jQuery using
.text()
or.attr()
is safe, but building an HTML string like in that example you would definitely run into issues.travis– travis2022年01月19日 18:16:46 +00:00Commented Jan 19, 2022 at 18:16
$('<div/>').text('This is fun & stuff').html(); // "This is fun & stuff"
Source: http://debuggable.com/posts/encode-html-entities-with-jquery:480f4dd6-13cc-4ce9-8071-4710cbdd56cb
-
12As mentioned in the above answer, this solution is not guaranteed to preserve whitespace.geofflee– geofflee2011年03月24日 11:53:26 +00:00Commented Mar 24, 2011 at 11:53
If you're escaping for HTML, there are only three that I can think of that would be really necessary:
html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
Depending on your use case, you might also need to do things like "
to "
. If the list got big enough, I'd just use an array:
var escaped = html;
var findReplace = [[/&/g, "&"], [/</g, "<"], [/>/g, ">"], [/"/g, """]]
for(var item in findReplace)
escaped = escaped.replace(findReplace[item][0], findReplace[item][1]);
encodeURIComponent()
will only escape it for URLs, not for HTML.
-
14This regular expression will produce strange results if the HTML in question already has escaped entities. For example, escaping "Tom & Jerry" will produce "Tom &amp; Jerry"Ryan– Ryan2010年11月07日 18:24:32 +00:00Commented Nov 7, 2010 at 18:24
-
12Please use
var
to declareitem
locally; anyway, don't use afor ... in
loop at all when looping through an array! Use an ordinaryfor
loop instead. Oh, and it'sencodeURIComponent
, notescapeURIComponent
.Marcel Korpel– Marcel Korpel2011年03月16日 16:33:28 +00:00Commented Mar 16, 2011 at 16:33 -
5Just a kind reminder for new people, don't use this if you intend to have non-english characters somewhere on your website ... Obviously this won't do because of characters with accents like 'é' :
é
; Here's a list of html entities, for reference : w3schools.com/tags/ref_entities.aspLoganWolfer– LoganWolfer2011年04月01日 21:50:54 +00:00Commented Apr 1, 2011 at 21:50 -
13@Ryan: While it's worth pointing out that this solution doesn't handle already-encoded strings correctly, it's also worth nothing that the same applies to most - possibly all - solutions on this page.mklement0– mklement02013年04月12日 14:21:28 +00:00Commented Apr 12, 2013 at 14:21
-
4@RyanMohr You say that escaping "Tom & Jerry" will produce "Tom &amp; Jerry". Good! That's exactly the correct behaviour. Correct escaping like this lets people post comments like yours which discuss HTML without weird things happening. If it stayed the same, that would be weird.Flimm– Flimm2019年06月21日 15:27:30 +00:00Commented Jun 21, 2019 at 15:27
Easy enough to use underscore:
_.escape(string)
Underscore is a utility library that provides a lot of features that native js doesn't provide. There's also lodash which is the same API as underscore but was rewritten to be more performant.
-
2And the inverse is
_.unescape(string)
.qräbnö– qräbnö2021年01月21日 19:12:07 +00:00Commented Jan 21, 2021 at 19:12
I wrote a tiny little function which does this. It only escapes "
, &
, <
and >
(but usually that's all you need anyway). It is slightly more elegant then the earlier proposed solutions in that it only uses one .replace()
to do all the conversion. (EDIT 2: Reduced code complexity making the function even smaller and neater, if you're curious about the original code see end of this answer.)
function escapeHtml(text) {
'use strict';
return text.replace(/[\"&<>]/g, function (a) {
return { '"': '"', '&': '&', '<': '<', '>': '>' }[a];
});
}
This is plain Javascript, no jQuery used.
Escaping /
and '
too
Edit in response to mklement's comment.
The above function can easily be expanded to include any character. To specify more characters to escape, simply insert them both in the character class in the regular expression (i.e. inside the /[...]/g
) and as an entry in the chr
object. (EDIT 2: Shortened this function too, in the same way.)
function escapeHtml(text) {
'use strict';
return text.replace(/[\"&'\/<>]/g, function (a) {
return {
'"': '"', '&': '&', "'": ''',
'/': '/', '<': '<', '>': '>'
}[a];
});
}
Note the above use of '
for apostrophe (the symbolic entity '
might have been used instead – it is defined in XML, but was originally not included in the HTML spec and might therefore not be supported by all browsers. See: Wikipedia article on HTML character encodings). I also recall reading somewhere that using decimal entities is more widely supported than using hexadecimal, but I can't seem to find the source for that now though. (And there cannot be many browsers out there which does not support the hexadecimal entities.)
Note: Adding /
and '
to the list of escaped characters isn't all that useful, since they do not have any special meaning in HTML and do not need to be escaped.
Original escapeHtml
Function
EDIT 2: The original function used a variable (chr
) to store the object needed for the .replace()
callback. This variable also needed an extra anonymous function to scope it, making the function (needlessly) a little bit bigger and more complex.
var escapeHtml = (function () {
'use strict';
var chr = { '"': '"', '&': '&', '<': '<', '>': '>' };
return function (text) {
return text.replace(/[\"&<>]/g, function (a) { return chr[a]; });
};
}());
I haven't tested which of the two versions are faster. If you do, feel free to add info and links about it here.
I realize how late I am to this party, but I have a very easy solution that does not require jQuery.
escaped = new Option(unescaped).innerHTML;
Edit: This does not escape quotes. The only case where quotes would need to be escaped is if the content is going to be pasted inline to an attribute within an HTML string. It is hard for me to imagine a case where doing this would be good design.
Edit 3: For the fastest solution, check the answer above from Saram. This one is the shortest.
After last tests I can recommend fastest and completely cross browser compatible native javaScript (DOM) solution:
function HTMLescape(html){
return document.createElement('div')
.appendChild(document.createTextNode(html))
.parentNode
.innerHTML
}
If you repeat it many times you can do it with once prepared variables:
//prepare variables
var DOMtext = document.createTextNode("test");
var DOMnative = document.createElement("span");
DOMnative.appendChild(DOMtext);
//main work for each case
function HTMLescape(html){
DOMtext.nodeValue = html;
return DOMnative.innerHTML
}
Look at my final performance comparison (stack question).
-
2Is it necessary to use two nodes? How about just one:
var p = document.createElement('p'); p.textContent = html; return p.innerHTML;
Dan Dascalescu– Dan Dascalescu2015年08月13日 15:14:47 +00:00Commented Aug 13, 2015 at 15:14 -
2@DanDascalescu: According to MDN, the
textContent
function is only supported by Chrome 1+, Firefox 2, IE9, Opera 9.64 and Safari 3 (the latter two annotated "possibly earlier"). It would thus break the OPs "completely cross-browser compatible" claim.zb226– zb2262015年11月11日 11:00:09 +00:00Commented Nov 11, 2015 at 11:00 -
p.innerText = html; return p.innerHTML
Bekim Bacaj– Bekim Bacaj2016年11月27日 08:58:45 +00:00Commented Nov 27, 2016 at 8:58 -
This doesn't escape single or double quotes, but it does escape these:
<
,>
,&
.R. Navega– R. Navega2025年07月16日 06:14:51 +00:00Commented Jul 16 at 6:14
Here is a clean, clear JavaScript function. It will escape text such as "a few < many" into "a few < many".
function escapeHtmlEntities (str) {
if (typeof jQuery !== 'undefined') {
// Create an empty div to use as a container,
// then put the raw text in and get the HTML
// equivalent out.
return jQuery('<div/>').text(str).html();
}
// No jQuery, so use string replace.
return str
.replace(/&/g, '&')
.replace(/>/g, '>')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
Try Underscore.string lib, it works with jQuery.
_.str.escapeHTML('<div>Blah blah blah</div>')
output:
'<div>Blah blah blah</div>'
-
20The main underscore library now has an
_.escape()
utility function.codeape– codeape2012年10月11日 12:14:37 +00:00Commented Oct 11, 2012 at 12:14
escape()
and unescape()
are intended to encode / decode strings for URLs, not HTML.
Actually, I use the following snippet to do the trick that doesn't require any framework:
var escapedHtml = html.replace(/&/g, '&')
.replace(/>/g, '>')
.replace(/</g, '<')
.replace(/"/g, '"')
.replace(/'/g, ''');
-
If you're going to have
"
s then you need to add at least'
and `` to the fray. Those are only really needed for string tag data inside elements in html. For html data itself (outside tags) only the first 3 are required.Marius– Marius2013年07月12日 12:01:05 +00:00Commented Jul 12, 2013 at 12:01
I've enhanced the mustache.js example adding the escapeHTML()
method to the string object.
var __entityMap = {
"&": "&",
"<": "<",
">": ">",
'"': '"',
"'": ''',
"/": '/'
};
String.prototype.escapeHTML = function() {
return String(this).replace(/[&<>"'\/]/g, function (s) {
return __entityMap[s];
});
}
That way it is quite easy to use "Some <text>, more Text&Text".escapeHTML()
-
Useful, but also I moved
__entityMap
into function local scope. And wrapped all of this intoif (typeof String.prototype.escapeHTML !== 'function'){...}
FlameStorm– FlameStorm2017年08月09日 11:27:22 +00:00Commented Aug 9, 2017 at 11:27
If you have underscore.js, use _.escape
(more efficient than the jQuery method posted above):
_.escape('Curly, Larry & Moe'); // returns: Curly, Larry & Moe
If your're going the regex route, there's an error in tghw's example above.
<!-- WON'T WORK - item[0] is an index, not an item -->
var escaped = html;
var findReplace = [[/&/g, "&"], [/</g, "<"], [/>/g,">"], [/"/g,
"""]]
for(var item in findReplace) {
escaped = escaped.replace(item[0], item[1]);
}
<!-- WORKS - findReplace[item[]] correctly references contents -->
var escaped = html;
var findReplace = [[/&/g, "&"], [/</g, "<"], [/>/g, ">"], [/"/g, """]]
for(var item in findReplace) {
escaped = escaped.replace(findReplace[item[0]], findReplace[item[1]]);
}
-
2I believe it should be for(var item in findReplace) { escaped = escaped.replace(findReplace[item][0], findReplace[item][1]); }Chris Stephens– Chris Stephens2011年06月23日 21:23:10 +00:00Commented Jun 23, 2011 at 21:23
This is a nice safe example...
function escapeHtml(str) {
if (typeof(str) == "string"){
try{
var newStr = "";
var nextCode = 0;
for (var i = 0;i < str.length;i++){
nextCode = str.charCodeAt(i);
if (nextCode > 0 && nextCode < 128){
newStr += "&#"+nextCode+";";
}
else{
newStr += "?";
}
}
return newStr;
}
catch(err){
}
}
else{
return str;
}
}
-
4What types of exceptions are you suppressing there?Stefan Majewsky– Stefan Majewsky2012年11月16日 16:08:05 +00:00Commented Nov 16, 2012 at 16:08
You can easily do it with vanilla js.
Simply add a text node the document. It will be escaped by the browser.
var escaped = document.createTextNode("<HTML TO/ESCAPE/>")
document.getElementById("[PARENT_NODE]").appendChild(escaped)
2 simple methods that require NO JQUERY...
You can encode all characters in your string like this:
function encode(e){return e.replace(/[^]/g,function(e){return"&#"+e.charCodeAt(0)+";"})}
Or just target the main characters to worry about &
, line breaks, <
, >
, "
and '
like:
function encode(r){
return r.replace(/[\x26\x0A\<>'"]/g,function(r){return"&#"+r.charCodeAt(0)+";"})
}
var myString='Encode HTML entities!\n"Safe" escape <script></'+'script> & other tags!';
test.value=encode(myString);
testing.innerHTML=encode(myString);
/*************
* \x26 is &ersand (it has to be first),
* \x0A is newline,
*************/
<p><b>What JavaScript Generated:</b></p>
<textarea id=test rows="3" cols="55"></textarea>
<p><b>What It Renders Too In HTML:</b></p>
<div id="testing">www.WHAK.com</div>
Plain JavaScript escaping example:
function escapeHtml(text) {
var div = document.createElement('div');
div.innerText = text;
return div.innerHTML;
}
escapeHtml("<script>alert('hi!');</script>")
// "<script>alert('hi!');</script>"
-
3Code-only answers are discouraged because they do not explain how they resolve the issue. Please update your answer to explain how this improves on the other accepted and upvoted answers this question already has. Also, this question is 9 years old, your efforts would be more appreciated by users who have recent unanswered questions. Please review How do I write a good answer.FluffyKitten– FluffyKitten2017年10月11日 10:20:07 +00:00Commented Oct 11, 2017 at 10:20
-
1@FluffyKitten here is an an extremely nicly written blog post on the advantages and disadvantages of such function that explains in detail everything you would like to know :) shebang.brandonmintern.com/…db306– db3062017年11月13日 07:54:48 +00:00Commented Nov 13, 2017 at 7:54
-
@db306 The answer was flagged as low quality because code-only answer don't meet Stack Overflow guidelines - see How to write a good answer. My comment was added during the review process to explain what is required to improve it, i.e. the answer needs to by updated to explain what the code does and how it improves on the existing answers. The upvotes are from other reviewers to endorse this. Adding an external link to the comments still does not meet SO guidelines. Instead Andrew needs to include the relevant information directly in his answer.FluffyKitten– FluffyKitten2017年11月14日 09:19:44 +00:00Commented Nov 14, 2017 at 9:19
-
Note that brandonmintern DOT com expired and is now parked. The new shebang address is shebang.mintern.net/foolproof-html-escaping-in-javascript/.Brandon– Brandon2020年04月24日 18:52:50 +00:00Commented Apr 24, 2020 at 18:52
ES6 one liner for the solution from mustache.js
const escapeHTML = str => (str+'').replace(/[&<>"'`=\/]/g, s => ({'&': '&','<': '<','>': '>','"': '"',"'": ''','/': '/','`': '`','=': '='})[s]);
(function(undefined){
var charsToReplace = {
'&': '&',
'<': '<',
'>': '>'
};
var replaceReg = new RegExp("[" + Object.keys(charsToReplace).join("") + "]", "g");
var replaceFn = function(tag){ return charsToReplace[tag] || tag; };
var replaceRegF = function(replaceMap) {
return (new RegExp("[" + Object.keys(charsToReplace).concat(Object.keys(replaceMap)).join("") + "]", "gi"));
};
var replaceFnF = function(replaceMap) {
return function(tag){ return replaceMap[tag] || charsToReplace[tag] || tag; };
};
String.prototype.htmlEscape = function(replaceMap) {
if (replaceMap === undefined) return this.replace(replaceReg, replaceFn);
return this.replace(replaceRegF(replaceMap), replaceFnF(replaceMap));
};
})();
No global variables, some memory optimization. Usage:
"some<tag>and&symbol©".htmlEscape({'©': '©'})
result is:
"some<tag>and&symbol©"
function htmlDecode(t){
if (t) return $('<div />').html(t).text();
}
works like a charm
-
text removes html tags, but $('<div />').html(t).html(); worksBass Jobsen– Bass Jobsen2013年08月08日 19:50:56 +00:00Commented Aug 8, 2013 at 19:50
function htmlEscape(str) {
var stringval="";
$.each(str, function (i, element) {
alert(element);
stringval += element
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(' ', '-')
.replace('?', '-')
.replace(':', '-')
.replace('|', '-')
.replace('.', '-');
});
alert(stringval);
return String(stringval);
}
A speed-optimized version:
function escapeHtml(s) {
let out = "";
let p2 = 0;
for (let p = 0; p < s.length; p++) {
let r;
switch (s.charCodeAt(p)) {
case 34: r = """; break; // "
case 38: r = "&" ; break; // &
case 39: r = "'" ; break; // '
case 60: r = '<' ; break; // <
case 62: r = '>' ; break; // >
default: continue;
}
if (p2 < p) {
out += s.substring(p2, p);
}
out += r;
p2 = p + 1;
}
if (p2 == 0) {
return s;
}
if (p2 < s.length) {
out += s.substring(p2);
}
return out;
}
const s = "Hello <World>!";
document.write(escapeHtml(s));
console.log(escapeHtml(s));
For escape html specials (UTF-8)
function htmlEscape(str) {
return str
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/\//g, '/')
.replace(/=/g, '=')
.replace(/`/g, '`');
}
For unescape html specials (UTF-8)
function htmlUnescape(str) {
return str
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, "'")
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(///g, '/')
.replace(/=/g, '=')
.replace(/`/g, '`');
}
This answer provides the jQuery and normal JS methods, but this is shortest without using the DOM:
unescape(escape("It's > 20% less complicated this way."))
Escaped string: It%27s%20%3E%2020%25%20less%20complicated%20this%20way.
If the escaped spaces bother you, try:
unescape(escape("It's > 20% less complicated this way.").replace(/%20/g, " "))
Escaped string: It%27s %3E 20%25 less complicated this way.
Unfortunately, the escape()
function was deprecated in JavaScript version 1.5. encodeURI()
or encodeURIComponent()
are alternatives, but they ignore '
, so the last line of code would turn into this:
decodeURI(encodeURI("It's > 20% less complicated this way.").replace(/%20/g, " ").replace("'", '%27'))
All major browsers still support the short code, and given the number of old websites, i doubt that will change soon.
-
This is for URL encoding. The question was about HTML escaping, which is very different.thelem– thelem2015年10月15日 09:22:28 +00:00Commented Oct 15, 2015 at 9:22
-
@thelem, not if the strings are embedded in JavaScript arrays embedded in HTML, but i agree it was about plain HTML escaping so it can be immediately displayed as text.Cees Timmerman– Cees Timmerman2015年10月15日 13:02:25 +00:00Commented Oct 15, 2015 at 13:02
All solutions are useless if you dont prevent re-escape, e.g. most solutions would keep escaping &
to &
.
escapeHtml = function (s) {
return s ? s.replace(
/[&<>'"]/g,
function (c, offset, str) {
if (c === "&") {
var substr = str.substring(offset, offset + 6);
if (/&(amp|lt|gt|apos|quot);/.test(substr)) {
// already escaped, do not re-escape
return c;
}
}
return "&" + {
"&": "amp",
"<": "lt",
">": "gt",
"'": "apos",
'"': "quot"
}[c] + ";";
}
) : "";
};
-
4That's called double escaping and should be fixed by making sure your input data is not already escaped. What if you wanted to literally show < to the user? Or perhaps the text is going to be reused elsewhere, and depend on the escaping having happened?thelem– thelem2015年10月15日 09:26:34 +00:00Commented Oct 15, 2015 at 9:26
If you are saving this information in a database, its wrong to escape HTML using a client-side script, this should be done in the server. Otherwise its easy to bypass your XSS protection.
To make my point clear, here is a exemple using one of the answers:
Lets say you are using the function escapeHtml to escape the Html from a comment in your blog and then posting it to your server.
var entityMap = {
"&": "&",
"<": "<",
">": ">",
'"': '"',
"'": ''',
"/": '/'
};
function escapeHtml(string) {
return String(string).replace(/[&<>"'\/]/g, function (s) {
return entityMap[s];
});
}
The user could:
- Edit the POST request parameters and replace the comment with javascript code.
- Overwrite the escapeHtml function using the browser console.
If the user paste this snippet in the console it would bypass the XSS validation:
function escapeHtml(string){
return string
}
-
I disagree. To bypass this XSS protection you'd have to use a XSS attack (injecting a script that disables the escaping), which is what you are actually blocking. In certain cases it's actually more appropriate to escape on the client, for example if the data comes from a REST API that has to return standard JSON.ItalyPaleAle– ItalyPaleAle2015年03月13日 18:00:36 +00:00Commented Mar 13, 2015 at 18:00
-
@Qualcuno If you are doing this validation in the client and posting this information to the server trusting it was validated the user could simply edit the request and the script would be saved in the database.Kauê Gimenes– Kauê Gimenes2015年03月13日 18:12:14 +00:00Commented Mar 13, 2015 at 18:12
-
@Qualcuno I included some examples to make my point more clear.Kauê Gimenes– Kauê Gimenes2015年03月13日 18:21:27 +00:00Commented Mar 13, 2015 at 18:21
-
1The question was about escaping strings received from the server to display them on the browser. What you are saying is about escaping strings before submitting them to the server, which is a different thing (though you're right, there, and it goes back to the old rule never blindly accept any input from the client)ItalyPaleAle– ItalyPaleAle2015年03月13日 18:26:38 +00:00Commented Mar 13, 2015 at 18:26
-
@Qualcuno This is a popular question in Stackoverflow, and i believe this is an important point to be covered. Thats why i answered.Kauê Gimenes– Kauê Gimenes2015年03月13日 18:29:11 +00:00Commented Mar 13, 2015 at 18:29