Modern way to sanitize your data using the Sanitizer API

Modern way to sanitize your data using the Sanitizer API

If you don't know what the Sanitizer API is, I highly recommend reading this article. So, that's all well and good... but that's only supported in Chrome, so that's going to be a problem.

Using a polyfill ?

The obvious solution is to use a polyfill, which uses DOMPurify under the hood. The issue with this is that unless you use feature detection to include the polyfill, you are going to include it in Chrome even if you don't need it. And if you use feature detection, you need to wait until the polyfill is loaded before using any code using the polyfill, which may be difficult to detect.

A simpler approach

In my case, all I needed is the setHTML. I don't really care about the rest of the spec.

So let's see what we got:

/**
 * @link https://web.dev/sanitizer/
 * @link https://sanitizer-api.dev/
 * @param {HTMLElement} el (NOT a template element)
 * @param {string} html
 * @param {Boolean} force
 */
export default function setHTML(el, html, force = false) {
  //@ts-ignore
  if (window.Sanitizer && !force) {
    //@ts-ignore
    el.setHTML(html);
  } else if (window["DOMPurify"]) {
    el.innerHTML = window["DOMPurify"].sanitize(html, {
      WHOLE_DOCUMENT: false,
      FORCE_BODY: false,
    });
  } else {
    el.innerHTML = html;
  }
}

/**
 * Set the global DOMPurify if missing and if Sanitizer api is not available
 * Call this with await before any call to setHTML
 * @param {Boolean} force
 */
export async function loadDOMPurify(force = false) {
  //@ts-ignore
  if ((!window.Sanitizer || force) && !window["DOMPurify"]) {
    //@ts-ignore
    window["DOMPurify"] = (await import("https://cdn.jsdelivr.net/npm/dompurify@3/+esm")).default;
  }
}

Import this little snippet, and you are good to go. Call await loadDOMPurify before any code using the setHTML helper. This will load DOMPurify using dynamic import from the cdn (or feel free to use your own local path for this).

Neat, no? :-) I've been using this in my WIP formidable elements library.

EDIT: it seems the current draft has been deprecated, see here: https://developer.chrome.com/blog/sanitizer-api-deprecation?hl=fr