Two methods, two kinds of content
An element's content can be thought of in two ways:
- its text: just the characters a reader sees;
- its HTML: the markup, including any tags inside it.
jQuery has a method for each: .text() and .html(). Both are getters without an argument and setters with one.
<p id="intro">Learn <strong>jQuery</strong> today.</p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
console.log("text:", $("#intro").text());
console.log("html:", $("#intro").html());
</script>text: Learn jQuery today.
html: Learn <strong>jQuery</strong> today..text() drops the tags and returns only the words. .html() returns the markup exactly as the browser holds it.
Setting text
.text(value) replaces everything inside the element with plain text:
<p id="status">Loading...</p>
<p id="raw"></p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#status").text("Saved at 10:30");
$("#raw").text("<b>Not bold</b>");
console.log($("#raw").html());
</script><b>Not bold</b>The second paragraph shows the characters <b>Not bold</b> instead of bold text. jQuery escaped the angle brackets, which you can see in the logged HTML as < and >. This escaping is what makes .text() safe for any value, including what a visitor typed.
Setting HTML
.html(value) parses the string as markup and builds real elements:
<div id="card"></div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#card").html("<h3>Desk lamp</h3><p>Price: <strong>1,200</strong></p>");
console.log($("#card").children().length, "elements created");
console.log($("#card strong").text());
</script>2 elements created
1,200After the call, #card contains a real h3 and p that you can select and style like any other elements.
The danger: cross-site scripting
Suppose a comment form shows the visitor's comment with .html(). A visitor types something that is not a normal comment:
<input id="comment" value='Nice post! <img src=x onerror="console.log('attacker code ran')">' size="60">
<button id="unsafe">Show with .html()</button>
<button id="safe">Show with .text()</button>
<div id="out"></div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#unsafe").on("click", () => $("#out").html($("#comment").val()));
$("#safe").on("click", () => $("#out").text($("#comment").val()));
</script>attacker code ranWith .html(), the browser created an image with a broken address, and its onerror attribute ran JavaScript: that is the line in the output. On a real site, that code could read the page, change it, or send the visitor's data elsewhere. This attack is called cross-site scripting (XSS), and it is one of the most common web security bugs.
With .text(), the same input is shown harmlessly as characters.
The rule is simple: use .text() for anything that came from a user, a URL, or a server you do not fully control. Use .html() only for markup you wrote yourself. When you need to build HTML around user data, create the elements and set the user part with .text():
<ul id="comments"></ul>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const name = "Ravi <script>";
const message = "Great <b>tutorial</b>";
const $li = $("<li>");
$("<strong>").text(name).appendTo($li);
$li.append(": ", document.createTextNode(message));
$("#comments").append($li);
console.log($li.html());
</script><strong>Ravi <script></strong>: Great <b>tutorial</b>The structure (the strong element) is yours; the user's words go in as text, so their angle brackets are escaped.
Updating based on the current value
Both setters accept a function instead of a value. It runs once per element, receives the index and the current content, and returns the new content:
<ul>
<li>apple</li>
<li>banana</li>
<li>cherry</li>
</ul>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("li").text(function (index, oldText) {
return (index + 1) + ". " + oldText.toUpperCase();
});
console.log($("li").text());
</script>1. APPLE2. BANANA3. CHERRYThis replaces a whole .each() loop with one call.
Emptying content
To clear an element, set its text to an empty string or use .empty():
$("#results").text("");
$("#results").empty(); // same effect, and clearer.empty() removes everything inside but keeps the element itself. The lesson on removing elements covers it with .remove().
Text across several elements
Remember that .text() as a getter joins the text of all selected elements, while .html() reads only the first. If you want each element's text separately, use .map():
const names = $("li").map((i, el) => $(el).text()).get();Common mistakes
- Using
.html()to show user input. Use.text(). - Using
.text()when you meant to add markup, and seeing tags printed on the page. - Expecting
.html()to read every element. It reads the first. - Setting
.html()repeatedly in a loop. Build the string or elements first and set them once; each call makes the browser parse and rebuild the content.
Exercise
Add a text input and a Preview button. When the button is clicked, show the input's value inside a <p id="preview"> so that any HTML the user types is displayed, not run.
Show one possible answer
<input id="msg" value="<i>hello</i>">
<button id="go">Preview</button>
<p id="preview"></p>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
$("#go").on("click", function () {
$("#preview").text($("#msg").val());
});
</script>Key points
- .text() reads or sets plain text; any HTML in the value is shown as characters, not run as markup.
- .html() reads or sets markup; the browser parses the value and builds elements from it.
- Never pass user input to .html(): it opens the page to cross-site scripting (XSS). Use .text() instead.
- Both setters accept a function that receives the old value and returns the new one.