The problem: Many libraries operate on elements that match a specific selector. Either they only fetch elements on DOMContentLoaded, missing any dynamically inserted elements, or they additionally use the MutationObserver API to listen for future changes. However, this means that every library needs to add its own mutation observer that listens to changes in the entire DOM tree, which is slow.
The solution: Syntactic sugar over the MutationObserver API that allows developers to add callbacks every time an element that matches a given selector is added. This way, there would only be one mutation observer for all libraries and all their needs in the page, created lazily when the fist one is needed.
I’m not asking for selector mutation observers. This is nice to have, but a library works just fine. I’m suggesting a performance optimization so that libraries can effectively observe the entire page DOM, without creating yet another mutation observer for the entire DOM. This can only be done on the browser level, not as a library, since otherwise all libraries would need to agree to use the same dependency, which as you can imagine, is quite unrealistic.
Syntax-wise, I guess it could be something like document.onAppend(selector, callback);, name TBB. Or just an event on document, since it wouldn’t have anywhere to bubble anyway? Though that sounds dangerously close to mutation events, which had serious perf issues.
but, they would still be async, batch/flush and give you mutation records, right? I honestly don’t see why a prollyfill/speculative polyfill for this isn’t valuable. Yes, I realize that means that people would have to agree to use it but the alternative is that they have to write their own or wait for native to work it out, and not just one browser, but all of them. There’s a decent chance that through such actual dev use we can improve it before anyone does native work and see what people have to say. It seems to me that’s what incubation is all about really… So I’m saying, let’s write up a draft and a reference implementation and that gives us something to talk about. I’m happy to collab on this if you want.
According to my experience, iterating over and filtering elements returned by a mutation observer is plain painful.
Also, I suspect browsers could filter the elements much more effectively in terms of performance than a web developer forced to always iterate over all mutated elements though he needs e. g. just A elements.
After all, we already have the ability to provide a list of specific attributes to observe, so it would be natural to be able to do the same with elements at least as for tag name (but selectors would be more usable and flexible).
Filtering mutation records based on a css selector sounds cool but is actually way more work for the browser than what we currently do for mutation observers; indeed when you insert or move a node that contains children, we currently do not care about these children at all; filtering based on css selectors means that you need to test all added/removed nodes, not just the roots; you also need to update pseudo-classes like :last-of-type on every dom mutation which is costly.
On the other hand, when we perform the getMatchedRulesForElement, we could very likely at the same time reevaluate an additional set of js-provided selectors and queue appropriate events. Seems easier to me, and it relies on existing css invalidation mechanics.
On the other hand, a solution I support even more is to add support for StyleMutationObserver where you can listen for changes in the computed value of a property; if you have that you can trivially have a selector listener by adding “selector { --custom-property-with-unique-name: non-initial }” and listen for changes of the “–custom-property-with-unique-name” property (and that also works for things like hover/active/etc).