Skip to content

Instantly share code, notes, and snippets.

@spicychickensauce
Created April 22, 2026 14:00
Show Gist options
  • Select an option

  • Save spicychickensauce/ccddf1a1be9a40d4453683cf284400ab to your computer and use it in GitHub Desktop.

Select an option

Save spicychickensauce/ccddf1a1be9a40d4453683cf284400ab to your computer and use it in GitHub Desktop.
dom watcher web component
class DomWatcher extends HTMLElement {
observer?: MutationObserver;
previousMatches?: Set<Element>;
constructor() {
super();
this.observer = undefined;
this.previousMatches = new Set();
}
static get observedAttributes() {
return ["selector", "data"];
}
connectedCallback() {
this.style.display = "none";
this.update();
this.observer = new MutationObserver(() => this.update());
if (this.parentElement) {
this.observer.observe(this.parentElement, {
childList: true,
subtree: true,
});
}
}
disconnectedCallback() {
if (this.observer) {
this.observer.disconnect();
}
}
attributeChangedCallback() {
this.update();
}
update() {
const selector = this.getAttribute("selector");
const dataName = this.getAttribute("data");
if (!selector || !dataName || !this.parentElement) return;
const dataAttr = `data-${dataName}`;
const currentElements = this.parentElement.querySelectorAll(selector);
const nextMatches = new Set(currentElements);
for (const el of this.previousMatches ?? []) {
if (!nextMatches.has(el)) {
el.removeAttribute(dataAttr);
}
}
for (const el of nextMatches) {
if (!this.previousMatches?.has(el)) {
el.setAttribute(dataAttr, "");
}
}
this.previousMatches = new Set(nextMatches);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment