Scoped HTML is a DOM feature that let's an element establish its own naming context for descendant elements. It makes it possible to keep IDs out of HTML's global namespace and gives us a document that is structured as a hierarchy of scopes and subscopes.
Scopes are designated with the namespace
Boolean attribute.
The following ID is scoped:
<div namespace>
<div>
<div scoped:id="some-id"></div>
</div>
</div>
At scale, what we get is a hierarchy of scopes and subscopes.
<article namespace>
<section scoped:id="europe" namespace>
<div scoped:id="about">About Europe</b></div>
<div scoped:id="countries">Countries in Europe</div>
</section>
<section scoped:id="asia" namespace>
<div scoped:id="about">About Asia</b></div>
<div scoped:id="countries">Countries in Asia</div>
</section>
</article>
A mental model of the hierarchy would be:
continents
|- europe
| |- about
| |- countries
|- asia
|- about
|- countries
Scoped HTML comes with a namespace API that models scope hierarchies.
// Get the "continents" article
let continents = document.querySelector('#continents');
// Access scoped IDs with the new "namespace" DOM property
let europe = continents.namespace.europe;
let asia = continents.namespace.asia;
// And for deeply-nested IDs...
let aboutAfrica = continents.namespace.asia.namespace.about;
This gives an application a more bankable tree than the DOM tree as it lets a UI block hide its implementation details while exposing its relevant parts by role.
An element's .namespace
property is implemented as a live object that reflects the element's namespace tree in real time. CHTML also supports the Observer API for change detection; Obs.observe()
can thus be used to observe when IDs enter or exit the namespace.
Obs.observe(continents.namespace, changes => {
console.log(changes.map(change => change.name));
});
With the code below, our observer above should report having added a new ID africa
to the namespace.
continents.append('<section id="africa"></section>');