I am new to web components and trying to get the lay of the land. Apologies if I have missed a prior discussion of this question.
As someone interested in userland discoverability I was surprised to find that the CustomElementRegistry is a black box. There is simply no way to know what is registered. You must know a priori what to look for.
This suffices for programmers, who build everything in advance. But for a user-focused, dynamic environment it makes custom elements just another invisible thing.
Is this intentional? If so, I am curious why.
To be clear, I'm talking about something like this:
// Extend global customElements registry to allow component discovery.
(function() {
if (!customElements) return;
const registry = new Map();
const super_define = customElements.define;
Object.defineProperties(customElements, {
entries: { value: () => registry.entries() },
// Or if you prefer `[...customElements]`
[Symbol.iterator]: { value: () => registry.entries() },
define: {
value: function define(...args) {
try {
super_define.apply(this, args);
// Only register if the super call succeeds.
const [name, definition] = args;
registry.set(name, definition);
} catch (error) {
throw error;
}
}
}
});
})();
This works in Chrome and Firefox. Where by "works" I mean
customElements.entries() (or just customElements)To illustrate:

What are use cases for enumerating all the registered custom elements? What problem(s) are we trying to solve?
Invisibility-by-default is a user-hostile paradigm. I could ask, what problem are we trying to prevent by hiding them? After all, in JavaScript it takes more effort to hide something than to expose it. As this is a design decision, it should be stated somewhere.
For example, you can make an argument for why EventTarget listeners are not enumerable. If a third party could find out what listeners are registered, then it could unregister someone else's listeners. I would certainly accept that this is undesirable, (although note that in Node EventerEmitter listeners are exposed.).
EventTarget offers protection against that since the functions are registered by reference, and subscribers can hide the function reference (i.e. not leak it), even while retaining it in a context where they can later unsubscribe.
By-reference protection doesn't apply to CustomElementRegistry, since the elements are keyed by name. But it offers even stronger protections:
With those protections, I fail to see what harm could arise from making components discoverable.
Again, I see the burden-of-proof the other way around. But I will say a few words about my use case. The web is our best shot at a worldwide, user-empowering, dynamic computing environment. We have the tools to create a platform where models are fully portable, decomposable, visible, and self-documenting at runtime. In such an environment, users can build new models from the components that are available. Built-in elements are not enumerable as such, but they are well-known. Since the user might not know all of the new components that have been loaded in a given context, enumeration of the registry would be the most direct way to make their availability known.
Invisibility-by-default is a user-hostile paradigm. I could ask, what problem are we trying to prevent by hiding them? After all, in JavaScript it takes more effort to hide something than to expose it. As this is a design decision, it should be stated somewhere.
We're not hiding anything. Making the list of custom elements in a given document enumerable is a new API surface we need to add. Like any other feature, then, I'd like to understand why such a new API surface is needed because in some cases the API you want is not the best API we should be providing.
Every new API we add to the Web platform has a cost. I don't actually agree with your point that there is any material benefit in hiding event listeners on a given event target. However, for the sake of the discussion, let's say it is beneficial. If, as you're arguing here, followed the principle of being not user-hostile as you defined, and allowed the enumeration of the event listeners without realizing the benefit you've just mentioned (again, which I don't really agree to but that's beside the point), then we would not have been able to hide event listener after the fact short of adding a new non-enumerable event listener type.
This is why, in general, the burden of proof of adding any infinitesimally small API surface is on the party who is proposing to add it.
Since the user might not know all of the new components that have been loaded in a given context, enumeration of the registry would be the most direct way to make their availability known.
I'm failing to see how can some script on a website can dynamically detect an existence of an element of which it has no idea, and make use of it. What is a concrete scenario that makes such a thing useful?
A use case of a new API is a concrete scenario in which some need for a new capability comes up. For example, the following is a use case for the shadow DOM:
I want to build a custom flight date picker. This picker can be used multiple times within a given page, and may appear in many different pages across variety of websites. The websites which sues this picker should be able to use this picker, receive the events when the user picks a certain date range. The date picker shouldn't affect the styles of other elements in a given document, nor should it be affected by style rules in the document. Finally, the internal implementation details of such a date picker should be encapsulated; meaning that it shouldn't easily discoverable & manipulative by scripts in a given document via
querySelector, etc...
I should note that the term "user-hostile" was not aimed specifically at this proposal. Invisibility-by-default is everywhere, and always has been, with few exceptions (Smalltalk and Emacs come to mind).
I fully understand that "Every new API we add to the Web platform has a cost." You can use that argument against anything, including this entire proposal, which is extremely costly. The "shadow dom" alone adds immense complexity to the model and burden to what implementors remain. Just this week even Microsoft cried uncle.
However, I did not ask that anything be added to the API. I did ask whether or not there is any specific rationale for excluding this "infinitesimally small" capability, so that it might be documented, since the API is specifically designed to prevent it. (The registry resembles a Map but omits entries()). I provided a code example so that we could be 100% surely talking about the same thing.
Unlike native platforms, the web is positioned to universally empower rather than exploit users. This is its key to long-term survival. To understand the motivation for not adding more black boxes, you have to look to the use of browsers as dynamic modeling environments. Discovery of capabilities is crucial to this potential. You rightly ask
how can some script on a website can dynamically detect an existence of an element of which it has no idea, and make use of it
That's exactly the point. Suppose one component imports a date picker that's better than the native date input. Other components have no idea that it's available. Keep in mind that components (being functions) can be extended with metadata annotations describing more fully what they are and what they do. This can be done by convention with no modification whatsoever to this proposal. With that, you can make a query like "are any other date pickers available"? That type of usage鈥攆etching components by the qualities that they possess, rather than their exact identity or location鈥攚ould open up great potential for a component ecosystem. As things stand, the registry precludes this prospect (at least locally), since there is nothing to query.
With that, you can make a query like "are any other date pickers available"? That type of usage鈥攆etching components by the qualities that they possess, rather than their exact identity or location鈥攚ould open up great potential for a component ecosystem.
I don't see a practical situation in which this would work. In order to use such a data picker component, the script has to understand how it communicates back the picked date & how to set the valid date range, etc... The most likely situation instead is that each component will end up embedding its own date picker.
Anyhow, I hate to keep repeating the same mantra, we really need more concrete use case than that kind of abstract notion of it might allow use cases. We need a solid, concrete, down-to-earth, I-can-write-it-tomorrow use case.
Understood, @rniwa. Thanks for your thoughtful responses.
Regarding the question, I conclude that no special reason will be given.
Closing.
Most helpful comment
We're not hiding anything. Making the list of custom elements in a given document enumerable is a new API surface we need to add. Like any other feature, then, I'd like to understand why such a new API surface is needed because in some cases the API you want is not the best API we should be providing.
Every new API we add to the Web platform has a cost. I don't actually agree with your point that there is any material benefit in hiding event listeners on a given event target. However, for the sake of the discussion, let's say it is beneficial. If, as you're arguing here, followed the principle of being not user-hostile as you defined, and allowed the enumeration of the event listeners without realizing the benefit you've just mentioned (again, which I don't really agree to but that's beside the point), then we would not have been able to hide event listener after the fact short of adding a new non-enumerable event listener type.
This is why, in general, the burden of proof of adding any infinitesimally small API surface is on the party who is proposing to add it.
I'm failing to see how can some script on a website can dynamically detect an existence of an element of which it has no idea, and make use of it. What is a concrete scenario that makes such a thing useful?
A use case of a new API is a concrete scenario in which some need for a new capability comes up. For example, the following is a use case for the shadow DOM: