Skip to content

Instantly share code, notes, and snippets.

@deanebarker
Created January 28, 2026 19:06
Show Gist options
  • Select an option

  • Save deanebarker/27d72daa73c71e7f9239ccc92b356e0e to your computer and use it in GitHub Desktop.

Select an option

Save deanebarker/27d72daa73c71e7f9239ccc92b356e0e to your computer and use it in GitHub Desktop.
A JavaScript function to "sanitize" HTML returning from an HTMX request
document.body.addEventListener("htmx:beforeSwap", function (evt) {
const customEvt = evt as CustomEvent;
let rawHtml = customEvt.detail.serverResponse;
rawHtml = sanitizeHtml(rawHtml, "#" + container.id);
customEvt.detail.serverResponse = rawHtml;
});
function sanitizeHtml(htmlString: string, scopeSelector: string) {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, "text/html");
// 1. Remove all <script> tags
doc.querySelectorAll("script").forEach((el) => el.remove());
// 2. Walk all elements once
doc.querySelectorAll("*").forEach((el) => {
// 2a. Remove attributes starting with "on"
[...el.attributes].forEach((attr) => {
if (attr.name.toLowerCase().startsWith("on")) {
el.removeAttribute(attr.name);
}
if (attr.name.toLowerCase().startsWith("hx-on")) {
el.removeAttribute(attr.name);
}
});
// 2b. Rewrite hx-target
const hxTarget = el.getAttribute("hx-target");
if (hxTarget) {
const newVal = rewriteHxTarget(hxTarget, scopeSelector);
el.setAttribute("hx-target", newVal);
}
});
// 3. Scope all <style> blocks
doc.querySelectorAll("style").forEach((el) => {
var style = el.textContent;
el.textContent = `${scopeSelector} { ${style} }`;
});
return doc.body.innerHTML;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment