HTML in XMLHttpRequest

The W3C XMLHttpRequest specification adds HTML parsing support to XMLHttpRequest, which originally supported only XML parsing. This feature allows Web apps to obtain an HTML resource as a parsed DOM using XMLHttpRequest.

To get an overview of how to use XMLHttpRequest in general, see Using XMLHttpRequest.

Limitations

To discourage the synchronous use of XMLHttpRequest, HTML support is not available in the synchronous mode. Also, HTML support is only available if the responseType property has been set to "document". This limitation avoids wasting time parsing HTML uselessly when legacy code uses XMLHttpRequest in the default mode to retrieve responseText for text/html resources. Also, this limitation avoids problems with legacy code that assumes that responseXML is null for HTTP error pages (which often have a text/html response body).

Usage

Retrieving an HTML resource as a DOM using XMLHttpRequest works just like retrieving an XML resource as a DOM using XMLHttpRequest, except you can't use the synchronous mode and you have to explicitly request a document by assigning the string "document" to the responseType property of the XMLHttpRequest object after calling open() but before calling send().

var xhr = new XMLHttpRequest();
xhr.onload = function() {
  console.log(this.responseXML.title);
}
xhr.open("GET", "file.html");
xhr.responseType = "document";
xhr.send();

Feature detection

Method 1

This method relies on the "force async" nature of the feature. When you try to set responseType of an XMLHttpRequest object after it is opened as "sync". This throws an error in the browsers that implement the feature and works on others.

function HTMLinXHR() {
  if (!window.XMLHttpRequest)
    return false;
  var req = new window.XMLHttpRequest();
  req.open('GET', window.location.href, false);
  try {
    req.responseType = 'document';
  } catch(e) {
    return true;
  }
  return false;
}

View on JSFiddle

This method is synchronous, does not rely on external assets though it may not be as reliable as method 2 described below since it does not check the actual feature but an indication of that feature.

Method 2

There are two challenges to detecting exactly if a browser supports HTML parsing in XMLHttpRequest. First, the detection result is obtained asynchronously, because HTML support is only available in the asynchronous mode. Second, you have to actually fetch a test document over HTTP, because testing with a data: URL would end up testing data: URL support at the same time.

Thus, to detect HTML support, a test HTML file is needed on the server. This test file is small and is not well-formed XML:

<title>&amp;&<</title>

If the file is named detect.html, the following function can be used for detecting HTML parsing support:

function detectHtmlInXhr(callback) {
  if (!window.XMLHttpRequest) {
    window.setTimeout(function() { callback(false); }, 0);
    return;
  }
  var done = false;
  var xhr = new window.XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState == 4 && !done) {
      done = true;
      callback(!!(this.responseXML && this.responseXML.title && this.responseXML.title == "&&<"));
    }
  }
  xhr.onabort = xhr.onerror = function() {
    if (!done) {
      done = true;
      callback(false);
    }
  }
  try {
    xhr.open("GET", "detect.html");
    xhr.responseType = "document";
    xhr.send();
  } catch (e) {
    window.setTimeout(function() {
      if (!done) {
        done = true;
        callback(false);
      }
    }, 0);
  }
}

The argument callback is a function that will be called asynchronously with true as the only argument if HTML parsing is supported and false as the only argument if HTML parsing is not supported.

View on JSFiddle

Character encoding

If the character encoding is declared in the HTTP Content-Type header, that character encoding is used. Failing that, if there is a byte order mark, the encoding indicated by the byte order mark is used. Failing that, if there is a <meta> element that declares the encoding within the first 1024 bytes of the file, that encoding is used. Otherwise, the file is decoded as UTF-8.

Handling HTML on older browsers

XMLHttpRequest originally supported only XML parsing. HTML parsing support is a recent addition. For older browsers, you can even use the XMLHttpRequest.responseText property in association with regular expressions in order to get, for example, the source code of an HTML element given its ID:

function getHTML (oXHR, sTargetId) {
  var  rOpen = new RegExp("<(?!\!)\\s*([^\\s>]+)[^>]*\\s+id\\=[\"\']" + sTargetId + "[\"\'][^>]*>" ,"i"),
       sSrc = oXHR.responseText, aExec = rOpen.exec(sSrc);

  return aExec ? (new RegExp("(?:(?:.(?!<\\s*" + aExec[1] + "[^>]*[>]))*.?<\\s*" + aExec[1] + "[^>]*[>](?:.(?!<\\s*\/\\s*" + aExec[1] + "\\s*>))*.?<\\s*\/\\s*" + aExec[1] + "\\s*>)*(?:.(?!<\\s*\/\\s*" + aExec[1] + "\\s*>))*.?", "i")).exec(sSrc.slice(sSrc.indexOf(aExec[0]) + aExec[0].length)) || "" : "";
}

var oReq = new XMLHttpRequest();
oReq.open("GET", "yourPage.html", true);
oReq.onload = function () { console.log(getHTML(this, "intro")); };
oReq.send(null);
Note: This solution is very expensive for the interpreter. Use it only when it is really necessary.

Specifications

Specification Status Comment
XMLHttpRequest Living Standard Initial definition

Browser compatibility

XMLHttpRequest interface

DesktopMobile
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewChrome for AndroidFirefox for AndroidOpera for AndroidSafari on iOSSamsung Internet
XMLHttpRequestChrome Full support 1Edge Full support 12
Full support 12
No support 12 — 79
Notes
Notes Implemented via ActiveXObject('Microsoft.XMLHTTP')
Firefox Full support 1IE Full support 7
Full support 7
Full support 5
Notes
Notes Implemented via ActiveXObject('Microsoft.XMLHTTP')
Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
abortChrome Full support 18Edge Full support 12Firefox Full support YesIE Full support 5Opera Full support YesSafari Full support 1.2WebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
abort eventChrome Full support YesEdge Full support ≤79Firefox Full support YesIE Full support 10Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS ? Samsung Internet Android Full support Yes
error eventChrome Full support YesEdge Full support ≤79Firefox Full support YesIE Full support 10Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS ? Samsung Internet Android Full support Yes
getAllResponseHeadersChrome Full support 1Edge Full support 12Firefox Full support 4
Notes
Full support 4
Notes
Notes Starting from Firefox 49, empty headers are returned as empty strings in case the preference network.http.keep_empty_response_headers_as_empty_string is set to true, defaulting to false. Before Firefox 49 empty headers had been ignored. Since Firefox 50 the preference defaults to true.
IE Full support 5Opera Full support YesSafari Full support 1.2WebView Android Full support YesChrome Android Full support YesFirefox Android Full support 4
Notes
Full support 4
Notes
Notes Starting from Firefox 49, empty headers are returned as empty strings in case the preference network.http.keep_empty_response_headers_as_empty_string is set to true, defaulting to false. Before Firefox 49 empty headers had been ignored. Since Firefox 50 the preference defaults to true.
Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
getResponseHeaderChrome Full support 1Edge Full support 12Firefox Full support 1
Notes
Full support 1
Notes
Notes Starting from Firefox 49, empty headers are returned as empty strings in case the preference network.http.keep_empty_response_headers_as_empty_string is set to true, defaulting to false. Before Firefox 49 empty headers had been ignored. Since Firefox 50 the preference defaults to true.
IE Full support 5Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4
Notes
Full support 4
Notes
Notes Starting from Firefox 49, empty headers are returned as empty strings in case the preference network.http.keep_empty_response_headers_as_empty_string is set to true, defaulting to false. Before Firefox 49 empty headers had been ignored. Since Firefox 50 the preference defaults to true.
Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
load eventChrome Full support YesEdge Full support ≤79Firefox Full support YesIE Full support 9Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS ? Samsung Internet Android Full support Yes
loadend eventChrome Full support YesEdge Full support ≤79Firefox Full support YesIE Full support 10Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS ? Samsung Internet Android Full support Yes
loadstart eventChrome Full support YesEdge Full support ≤79Firefox Full support YesIE Full support 10Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS ? Samsung Internet Android Full support Yes
onreadystatechangeChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 5Opera Full support 9Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
openChrome Full support 1Edge Full support 12Firefox Full support 1
Notes
Full support 1
Notes
Notes Starting in Firefox 30, synchronous requests on the main thread have been deprecated due to their negative impact on performance and the user experience. Therefore, the async parameter may not be false except in a Worker.
IE Full support 5Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4
Notes
Full support 4
Notes
Notes Starting in Firefox 30, synchronous requests on the main thread have been deprecated due to their negative impact on performance and the user experience. Therefore, the async parameter may not be false except in a Worker.
Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
overrideMimeTypeChrome Full support 1Edge Full support 12Firefox Full support YesIE Full support 11
Full support 11
Full support 5
Notes
Notes Implemented via ActiveXObject
Opera Full support YesSafari Full support 1.2WebView Android Full support YesChrome Android Full support 18Firefox Android Full support YesOpera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0
progress eventChrome Full support YesEdge Full support ≤79Firefox Full support YesIE Full support 10Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS ? Samsung Internet Android Full support Yes
readyStateChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 7Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
responseChrome Full support 9Edge Full support 12Firefox Full support 6IE Full support 10Opera Full support 11.6Safari Full support 5.1WebView Android Full support ≤37Chrome Android Full support 18Firefox Android Full support 6Opera Android Full support 12Safari iOS Full support 6Samsung Internet Android Full support 1.0
responseTextChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 5
Notes
Full support 5
Notes
Notes Before Internet Explorer 10, the value of XMLHttpRequest.responseText could be read only once the request was complete.
Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
responseTypeChrome Full support 31Edge Full support 12Firefox Full support 6IE Full support 10Opera Full support 18Safari Full support 7WebView Android Full support 55Chrome Android Full support 55Firefox Android Full support 50Opera Android Full support 42Safari iOS Full support 7Samsung Internet Android Full support 6.0
responseURLChrome Full support 37Edge Full support 14Firefox Full support 32IE No support NoOpera Full support 24Safari Full support 8WebView Android Full support 37Chrome Android Full support 37Firefox Android Full support 32Opera Android Full support 24Safari iOS Full support YesSamsung Internet Android Full support 3.0
responseXMLChrome Full support YesEdge Full support 12Firefox Full support Yes
Notes
Full support Yes
Notes
Notes Prior to Firefox 51, an error parsing the received data added a <parsererror> node to the top of the Document and then returned the Document in whatever state it happens to be in. This was inconsistent with the specification. Starting with Firefox 51, this scenario now correctly returns null as per the spec.
IE Full support YesOpera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support Yes
Notes
Full support Yes
Notes
Notes Prior to Firefox 51, an error parsing the received data added a <parsererror> node to the top of the Document and then returned the Document in whatever state it happens to be in. This was inconsistent with the specification. Starting with Firefox 51, this scenario now correctly returns null as per the spec.
Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
sendChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 5Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
sendAsBinary
DeprecatedNon-standard
Chrome No support No
Notes
No support No
Notes
Notes There is a polyfill available to support sendAsBinary().
Edge No support No
Notes
No support No
Notes
Notes There is a polyfill available to support sendAsBinary().
Firefox No support 2 — 31IE No support NoOpera No support NoSafari No support NoWebView Android No support No
Notes
No support No
Notes
Notes There is a polyfill available to support sendAsBinary().
Chrome Android No support No
Notes
No support No
Notes
Notes There is a polyfill available to support sendAsBinary().
Firefox Android No support 4 — 31Opera Android No support NoSafari iOS No support NoSamsung Internet Android No support No
Notes
No support No
Notes
Notes There is a polyfill available to support sendAsBinary().
setRequestHeaderChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 5Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
statusChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 7
Notes
Full support 7
Notes
Notes Internet Explorer version 5 and 6 supported ajax calls using ActiveXObject()
Opera Full support 8Safari Full support 1.2WebView Android Full support 1Chrome Android Full support 18Firefox Android Full support 4Opera Android Full support 10.1Safari iOS Full support 1Samsung Internet Android Full support 1.0
statusTextChrome Full support 1Edge Full support 12Firefox Full support 1IE Full support 7
Notes
Full support 7
Notes
Notes Internet Explorer version 5 and 6 supported ajax calls using ActiveXObject()
Opera Full support YesSafari Full support 1.2WebView Android Full support YesChrome Android Full support 18Firefox Android Full support 4Opera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0
timeoutChrome Full support 29Edge Full support 12Firefox Full support 12IE Full support 8Opera Full support 17
Full support 17
No support 12 — 16
Safari Full support 6.1WebView Android Full support ≤37Chrome Android Full support 29Firefox Android Full support 14Opera Android Full support 18
Full support 18
No support 12 — 16
Safari iOS Full support 7Samsung Internet Android Full support 2.0
timeout eventChrome Full support YesEdge Full support ≤18Firefox Full support YesIE Full support 10Opera Full support YesSafari Full support YesWebView Android Full support YesChrome Android Full support YesFirefox Android Full support YesOpera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support Yes
uploadChrome Full support 1Edge Full support 12Firefox Full support YesIE Full support 10Opera Full support YesSafari Full support 10WebView Android Full support YesChrome Android Full support 18Firefox Android Full support YesOpera Android Full support YesSafari iOS Full support YesSamsung Internet Android Full support 1.0
withCredentialsChrome Full support 3Edge Full support 12Firefox Full support 3.5
Notes
Full support 3.5
Notes
Notes Starting with Firefox 11, it's no longer supported to use the withCredentials attribute when performing synchronous requests. Attempting to do so throws an NS_ERROR_DOM_INVALID_ACCESS_ERR exception.
IE Full support 10
Notes
Full support 10
Notes
Notes Internet Explorer versions 8 and 9 supported cross-domain requests (CORS) using XDomainRequest.
Opera Full support 12Safari Full support 4WebView Android Full support ≤37Chrome Android Full support 18Firefox Android Full support 4
Notes
Full support 4
Notes
Notes Starting with Firefox 11, it's no longer supported to use the withCredentials attribute when performing synchronous requests. Attempting to do so throws an NS_ERROR_DOM_INVALID_ACCESS_ERR exception.
Opera Android Full support 12Safari iOS Full support 3.2Samsung Internet Android Full support 1.0

Legend

Full support
Full support
No support
No support
Compatibility unknown
Compatibility unknown
Non-standard. Expect poor cross-browser support.
Non-standard. Expect poor cross-browser support.
Deprecated. Not for use in new websites.
Deprecated. Not for use in new websites.
See implementation notes.
See implementation notes.

See also