How jQuery .html() Executes Inline Script Tags

When developers use jQuery’s .html() method to insert markup containing inline <script> tags, jQuery automatically extracts and executes the JavaScript code within the global scope. Unlike native DOM methods such as Element.innerHTML—which explicitly block script execution for security reasons—jQuery intercepts HTML strings, separates the script elements, appends the standard markup to the DOM, and dynamically executes the script content.

Native innerHTML vs. jQuery .html()

In standard HTML5, inserting markup through element.innerHTML = "<script>alert('test');</script>" will not run the script. This behavior was implemented by browser vendors to reduce cross-site scripting (XSS) risks.

jQuery's .html() method was designed to make dynamic DOM updates intuitive, which historically meant ensuring that any included scripts ran as developers expected. To achieve this, jQuery circumvents native browser suppression by parsing and executing scripts manually.

Step 1: Parsing Markup and Isolating Scripts

When you pass an HTML string containing script tags to .html(val), jQuery processes the string through internal utilities:

  1. Document Fragment Creation: jQuery parses the HTML string into DOM nodes using a temporary DocumentFragment.
  2. Identification and Extraction: jQuery traverses the generated nodes to locate all <script> elements, whether they reference external sources (src) or contain inline code.
  3. Detachment: jQuery removes these script elements from the fragment before injecting the remaining HTML into the target element. This ensures that non-script elements are rendered in the DOM first.

Step 2: Global Execution via Script Injection

Once the non-script DOM elements are appended to the document, jQuery iterates over the extracted script elements in the exact order they appeared.

For inline scripts, jQuery does not rely on standard eval(), because direct eval() runs within the local function scope. Instead, jQuery ensures the code runs in the global window scope using an internal utility called jQuery.globalEval().

In modern jQuery versions, global evaluation is achieved by:

  1. Creating a new, native <script> DOM element via document.createElement("script").
  2. Assigning the inline code string to the new element's .text property.
  3. Appending this temporary script element directly to document.head.
  4. Immediately removing the script element from document.head via parentNode.removeChild().

Because the script node is appended to the active DOM document, the browser's JavaScript engine immediately parses and executes the inline code in the global execution context. Removing the node right afterward cleans up the DOM while leaving the side effects (such as defined functions or global variables) intact in memory.

Scope, Order, and Execution Characteristics

  • Global Scope: Variables declared with var or traditional function declarations inside the inline script are attached to the global window object, matching standard page-load script behavior.
  • Synchronous Execution: Inline scripts are evaluated synchronously in the order they were defined within the markup string.
  • Cleaned DOM: Because jQuery handles execution through this temporary injection pattern, the script tags themselves may not remain in the final target element's DOM tree, depending on the exact jQuery version and methods used.