Passing Raw HTML to jQuery $()
When you pass a raw HTML string into the jQuery $()
function, jQuery parses the markup and dynamically creates new Document
Object Model (DOM) elements in memory, wrapping them in a standard
jQuery collection. This article covers how jQuery detects and parses raw
HTML strings, how these elements exist in memory, the potential security
implications, and the recommended practices for handling dynamic HTML
safely.
How jQuery Processes Raw HTML
When a string is passed to $(), jQuery inspects the
string to determine whether it is a CSS selector or markup. If the
string starts with a < character (or in older versions,
contains HTML tags), jQuery routes the input to its internal HTML
parsing logic rather than attempting to query the existing document.
For simple, single-tag strings—such as $("<div/>")
or $("<div></div>")—jQuery utilizes the
browser's native document.createElement() method for fast
object creation.
For complex strings containing multiple tags, nested structures, or
attributes—such as
$("<div><p>Hello World</p></div>")—jQuery
processes the string through a temporary DOM element (typically using a
document fragment and innerHTML or DOMParser).
It converts the string into corresponding native DOM nodes, wraps them
in a jQuery collection, and returns the newly instantiated elements.
Elements Exist in Memory Only
The newly created DOM nodes do not automatically appear on the
webpage. They are created strictly in browser memory. Until you
explicitly attach them to the document using DOM-manipulation
methods—such as .appendTo(), .append(),
.prepend(), or .insertAfter()—they remain
detached from the active DOM tree.
// Created in memory only
const $newElement = $('<div class="alert">Operation Complete</div>');
// Inserted into the active DOM
$('body').append($newElement);Script Execution and Behavior
If the raw HTML string contains <script> tags,
jQuery's default behavior historically allowed those scripts to be
evaluated once the elements were inserted into the DOM. Even if the
nodes are detached, certain attributes like onload or
onerror on image tags might trigger immediate execution in
the browser as soon as the element is instantiated in memory.
Security Implications (Cross-Site Scripting)
Passing unvalidated or unsanitized user-supplied strings directly
into $() introduces serious Cross-Site Scripting (XSS)
vulnerabilities. If an attacker injects arbitrary HTML containing
malicious scripts, jQuery will parse it as HTML instead of treating it
as text or a selector.
In older versions of jQuery (prior to 1.9.0), strings like
$('#' + userInput) could be exploited if
userInput started with a < tag, tricking
jQuery into generating HTML rather than searching for an element by ID.
While modern versions require the string to begin with a
< to be recognized as HTML, passing external or dynamic
data directly into $() remains hazardous.
The Recommended
Alternative: $.parseHTML()
For dynamic or untrusted HTML strings, use
jQuery.parseHTML() instead of the standard $()
constructor. $.parseHTML() converts an HTML string into an
array of DOM nodes and, by default, strips out executable
<script> tags to mitigate script execution risks.
// Safely parse HTML without executing embedded scripts
const nodes = $.parseHTML('<p>Text</p><script>alert("XSS")</script>');
const $safeContent = $(nodes);
// Appends only the <p> element; the script is discarded
$('#container').append($safeContent);Passing a raw HTML string to $() is fundamentally a
shorthand factory method for building in-memory DOM nodes, but it should
be restricted to trusted, static templates. Dynamic or user-controlled
markup should always be validated, sanitized, or processed through
explicit parsing methods.