Revisiting the HTML Problem Space and Introducing OOHTML
Tags: webdev, javascript, html, webqit
Published: 2024-01-24 13:01:03

It's 2024! Is it perhaps time to give attention to HTML?

It's a time when many people are interested in going back to the basics! Even whole teams are looking to make the big return [from rethinking best practices](https://dev.to/oxharris/rethinking-the-modern-web-5cn1#looking-back-the-paradigm-shift)! (How we, in fact, got fed such a line remains a mystery!)

But perhaps, no one is talking about the alternative and how still "philosophical" it is to build anything of substance in just HTML, CSS and JS in 2024! In fact, you may contend that *a lot* still goes unanswered in our web-native playbooks!

I'd agree!

Actually, while it's now possible to streamline your workflow with features like native ES Modules + Import Maps (I can see you on that, [Joe Pea](https://twitter.com/trusktr/status/1742622565838066077)), the Shadow DOM (I see that you love that, [Passle](https://twitter.com/passle_/status/1732659968174694690)), CSS nesting, etc., so much is still only philosophical!

For example, more recently, I decided to play the devil's advocate on the subject myself, and, so, threw in an obvious question: [how do you do reactivity](https://twitter.com/Ox_Harris/status/1741103662104015266)? (Hoping to hear something intriguing!) But it turns out, we still aren't close! And you're almost always disappointed [each time](https://twitter.com/AgentZeroNine/status/1741140904184844402)!

It's something we cannot possibly be dogmatic about or evangelize as though there were no limitations when we talk about [web-native development](https://dev.to/oxharris/rethinking-the-modern-web-5cn1#introducing-webnative-development). That could make one come across as being out of touch with reality or as being merely dismissive of framework-era innovations!

Web-native development, from one perspective, simply addresses *overheads*!

That's the whole point about "*leveraging* native platform capabilities and *streamlining* your workflow and tooling budget"! — The web-native manifesto.

That's the whole point about native technologies like [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components), speaking of which:

> *"One of the best outcomes from delegating our component model to the platform is that, when we do, many things get cheaper. Not only can we throw out the code to create and manage separate trees, browsers will increasingly compete on performance for apps structured this way."* — [Alex Russel](https://infrequently.org/2017/10/web-components-the-long-game/#:~:text=one%20of%20the%20best%20outcomes%20from%20delegating%20our%20component%20model%20to%20the%20platform%20is%20that%2C%20when%20we%20do%2C%20many%20things%20get%20cheaper.%20not%20only%20can%20we%20throw%20out%20the%20code%20to%20create%20and%20manage%20separate%20trees%2C%20browsers%20will%20increasingly%20compete%20on%20performance%20for%20apps%20structured%20this%20way.)

*And* should any aspect of that, at some point, begin to go counterproductive, such that you wind up with more boilerplates and homegrown tooling, or more runtime regressions — being oftentimes the counterargument, **it should be time again to _address_ overheads, not sugar coat them**!

In the spirit of that, here is what I am happy to do today: **discuss specific pain points that have yet to be addressed  natively and touch each one with the relevant part of a proposal you're sure to be excited about: [Object-Oriented HTML (OOHTML)](https://github.com/webqit/oohtml)**!

OOHTML is a new set of HTML and DOM-level features designed to make the HTML-First + Progressive Enhancement paradigm a viable idea — initially developed *out of need* at WebQit! If you've ever tried, as much as we have, to make success of the above, you probably would come to the same design and architectural conclusions as below and you might as well be inclined to put your money where your mouth is!

Coincidentally, with vanilla HTML increasingly becoming an attractive option for the modern UI author — amidst a multitude of frameworks, it is a perfect time to revisit the HTML problem space!

This is a long discussion but I can tell you this will be worth your time and contribution! See what's on the agenda:

+ [Question 1: How Do You Do Reactivity?](#question-1-how-do-you-do-reactivity)
+ [Question 2: How Do You Make Components?](#question-2-how-do-you-make-components)
+ [Question 3: How Do You Re-Use Components?](#question-3-how-do-you-re-use-components)
+ [Question 4: How Do You Pass Data/Props?](#question-4-how-do-you-pass-dataprops)

{% details **Show Full Outline** %}

+ [Question 1: How Do You Do Reactivity?](#question-1-how-do-you-do-reactivity)
    + [Introducing: Native Data Binding for HTML](#introducing-native-data-binding-for-html)
    + [Wanna Try?](#wanna-try)
    + [Introducing: Quantum Reactivity](#introducing-quantum-reactivity)
    + [This Works Today!](#this-works-today)
+ [Question 2: How Do You Make Components?](#question-2-how-do-you-make-components)
    + [Introducing: Namespacing](#introducing-namespacing)
    + [Good Thinking?](#good-thinking)
    + [Introducing: Style and Script Scoping](#introducing-style-and-script-scoping)
    + [Try Now!](#try-now)
+ [Question 3: How Do You Re-Use Components?](#question-3-how-do-you-re-use-components)
    + [Introducing: HTML Imports](#introducing-html-imports)
      + [Module Definition](#module-definition)
      + [Remote Modules](#remote-modules)
      + [Module Imports](#module-imports)
      + [Scoped Modules](#scoped-modules)
    + [Cool Yet?](#cool-yet)
+ [Question 4: How Do You Pass Data/Props?](#question-4-how-do-you-pass-dataprops)
    + [Introducing: The Bindings API](#introducing-the-bindings-api)
    + [Good Job There?](#good-job-there)
    + [Introducing: The Context API](#introducing-the-context-api)
    + [Exciting Yet?](#exciting-yet)

{% enddetails %}

------------

## Question 1: How Do You Do Reactivity?

This isn't something Web Components do today! And I do in fact fear that inventing a *WC-only* solution to this effect, such that you now have to employ a custom `<my-div>` element where a regular `<div>` element would ordinarily suffice, **would yet constitute a new form of _overhead_**!

And I'd like to say that what we do in [Lit](https://lit.dev/) today isn't to me a particularly attractive thing! TL;DR: a *runtime* solution to a *markup-level* problem is an absolute non-starter! **That's to still miss the essence of a markup language!**

You enter a framework like [Vue](https://vuejs.org/) or [Svelte](https://svelte.dev/) and you see something more like the ideal: a markup-based solution — wherein HTML is your first language:

```html
<!-- Vue -->
<script setup>
  let count = 0;
</script>

<template>
  <button>Count is: {{ count }}</button>
</template>
```

```html
<!-- Svelte -->
<script>
  let count = 0;
</script>

<button>Count is: {count}!</button>
```

Something more HTML-ish now!

You are able to just write markup and *progressively* add logic, as against *going ahead of the problem* with a JS-first approach!

Now, you think of this as a native language feature, and you aren't totally mistaking! For that would be us delegating all of the work to the HTML parser and getting to write code that practically hits the ground running:

```js
button.innerHTML = 'Count is: {count}!';
```

Which would mean: no compile step; no waiting for some JS dependency to generate the UI!

### Introducing: Native Data Binding for HTML

But the Vue/Svelte conventions above aren't where this leads! Not exactly!

First, we do need a binding syntax that upholds, instead of change, the default behaviour of the opening brace `{` and closing brace `}` characters in HTML! Whereas these should behave as mere text characters, a new behaviour is introduced above wherein, across the active DOM, every arbitrary text sequence in that form — `{count}` — is treated as special and automatically transformed. That as a native language feature (i.e. browsers suddenly waking up with this new rule) would be a breaking change to older code that make up a large percentage of the web today:

```html
<body>
  Hello {curly braces}!
</body>
```

```js
element.innerHTML = 'Hello {curly braces}!';
```

Consider the dilemma: should raw template tags be default-visible so as to be backwards-compatible with older code? Then, newer code would be having a "flash of unrendered content" and an inadvertent exposure of low-level implementation details! Should they be default hidden, then older code would be broken!

Given how the HTML language currently works, I found a sweet spot with a comment-based approach wherein regular HTML comments get to do the job and double up as dedicated insertion points for application data:

```html
<body>
  Hello {curly braces}!

  <button>Count is: <?{count}?>!</button>

  Or, using the comment syntax you might know: <button>Count is: <!--?{count}?-->!</button>
</body>
```

```js
element.innerHTML = 'Count is: <?{count}?>. Hello {curly braces}!';
```

Data-binding expressions are now default-hidden while application data becomes available at any timing! And the idea of having a special behaviour for certain text characters now requires an explicit opt-in using a special opening character sequence `<?` (or the longer equivalent `<!--?`) and a special closing character sequence `?>` (or the longer equivalent `?-->`). (Of course, syntax could be improved on where possible!)

This is something I really do like and I found that it resonates with many developers!

We next come to attribute bindings and the first challenge becomes whether or not to support text interpolation within attributes as Svelte would have it?:

```html
<img {src} alt="{name} dances." />
```

Heck! That again would be a breaking change in how curly braces are treated within attributes, just as has been considered above!

Also, how do you hydrate server-rendered attributes such that, given the `<img>` above, the browser still knows to map the `src` and `alt` attributes to certain application data after having been rendered to?:

```html
<img src="/my/image.png" alt="John Doe dances." />
```

Interestingly, I did set my foot on this path with OOHTML and that turned out messy!

Here is where Vue shines with its idea of having a separate, pseudo attribute do the binding for every given attribute:

```html
<img v-bind:src="src" v-bind:alt="computedExpr">
<!-- Or, for short: <img :src="src" :alt="computedExpr"> -->
```

which renders to:

```html
<img v-bind:src="src" v-bind:alt="computedExpr" src="/my/image.png" alt="John Doe dances.">
```

thus, obviating the trouble with the former approach. 

But heck! The attribute bloat... the sheer idea of an extra attribute for every given attribute!

What if we simply had one dedicated attribute for everything wherein we follow a key/value mapping syntax?:

```html
<img render="src:src; alt:computedExpr">
<!-- Or, with on-the-fly JS expressions: <img render="src:src; alt:name+' dances.'"> -->
```

to render to?:

```html
<img render="src:src; alt:computedExpr" src="/my/image.png" alt="John Doe dances.">
```

That would give us a more compact binding syntax, plus the same benefit as with the Vue approach — of having the original binding logic retained, instead of replaced, after having been rendered!

We only now need to extend our syntax to support a wider range of DOM element features like "class list" and "style". For this, we introduce the idea of directives, or special symbols, that add the relevant meaning to each binding:

e.g. the tilde symbol `~` for attribute binding:

```html
<img render="~src:src; ~alt:computedExpr" src="/my/image.png" alt="John Doe dances.">
```

the percent symbol `%` for class binding:

```html
<my-widget render="%active:app.isActive"></my-widget>
```

the ampersand `&` for CSS binding:

```html
<div render="&color:app.themeColor"></div>
```

etc.

I find this very conventional on the backdrop of existing syntaxes like CSS rules! And we've introduced no breaking changes and no funky attribute names!

But how should bindings be resolved? From an embedded `<script>` tag in scope as we have above?:

```html
<script>
  let count = 0;
</script>

<button>Count is: <?{ count }?>!</button>
```

That idea might be more suited to the Single File Component (SFC) architecture than to the DOM itself where the actual building blocks aren't SFCs but the very DOM nodes themselves!

Given the DOM, it makes more sense for the said JS references in binding expressions to have to do with the state of those DOM nodes:

```html
<button>Count is: <?{ count }?>!</button>
```

```js
button.count = 0;
```

which also resonates with the object/property paradigm of Custom Elements:

```html
<my-counter>Count is: <?{ count }?>!</my-counter>
```

```js
customElements.define('my-counter', class extends HTMLElement {
  connectedCallback() {
    this.count = 0;
  }
});
```

But there goes one subtle challenge: using an element's root namespace for arbitrary state management and potentially conflicting with native methods and properties!

It turns out, a more decent approach would be to have a dedicated state object for this:

```js
button.bindings.count = 0;
```

```js
connectedCallback() {
  this.bindings.count = 0;
}
```

And to make this even more flexible, we don't have to restrict the resolution scope of references to the immediate host elements. A more flexible approach would be to have things resolve from *the closest node in scope* who exposes said property, such that:

```html
<body>
  <div>
    <div>
      <button>Count is: <?{ count }?>!</button>
    </div>
  </div>
</body>
```

```js
document.body.bindings.count = 0;
// Or, even
document.bindings.count = 0;
```

still works!

This way, it becomes possible for higher-level state (or even the global state that lives at `document.bindings`) to still be reflected at deeply nested elements in the page without having to mechanically pass data from node to mode down the tree!

### Wanna Try?

Simply include the OOHTML polyfill from a CDN!

{% details Polyfill %}

```html
<head>
  <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
  <!-- other code -->
</head>
```

{% enddetails %}

And here's something to try on a blank document:

```html
<!DOCTYPE html>
<html>

  <head>
    <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
    <script>

      // Global count
      document.bindings.count = 0;
      setInterval(() => document.bindings.count++, 1000);

      // Local count
      customElements.define('my-counter', class extends HTMLElement {
        connectedCallback() {
          this.bindings.count = 0;
          setInterval(() => this.bindings.count++, 2000);
        }
      });
    </script>
  </head>

  <body>
    <h1>Global count is: <?{ count }?>.</h1>
    <my-counter>Local count is: <?{ count }?>.</my-counter>
  </body>

</html>
``` 

And you could try writing the "Declarative Lists" example in the [list of examples](https://github.com/webqit/oohtml?tab=readme-ov-file#examples)!

I ask that you share your thoughts and [leave us a star](https://github.com/webqit/oohtml) 🌟!

You may want to visit the [Data-Binding section](https://github.com/webqit/oohtml#data-binding) on the project README to learn more!

### Introducing: Quantum Reactivity

Data binding isn't all there is to reactivity on the UI!

While you're able to express JavaScript logic within binding tags:

```html
<h1>Global count is: <?{ count }?>.</h1>
<h2>Global count, doubled, is: <?{ count * 2 }?>.</h2>
```

you still need a way to write *reactive* logic in your main application code — i.e. the counter logic itself, above — as things begin to grow and require some form of dependency tracking.

Here's a sampling across frameworks of how our code could look in a reactive programming paradigm:

```html
<!-- Vue -->
<script setup>
  import { ref, computed } from "vue";

  let count = ref(0);
  let doubleCount = computed(() => count.value * 2);
</script>

<template>
  <button>Count is: {{ count }}</button>
  <button>Double count is: {{ doubleCount }}</button>
</template>
```

```html
<!-- Svelte -->
<script>
  let count = 0;
  $: doubleCount = count * 2;
</script>

<button>Count is: {count}!</button>
<button>Double count is: {doubleCount}!</button>
```

```html
<!-- Upcoming Svelte 5 -->
<script>
  let count = $state(0);
  let doubleCount = $derived(count * 2);
</script>

<button>Count is: {count}!</button>
<button>Double count is: {doubleCount}!</button>
```

But it's a whole new paradigm now from the ordinary *imperative* paradigm you started with! Many "reactive primitives" and much symbolism now, and there isn't a universal syntax for this form of programming!

> Svelte 3, in 2019, did try to bring reactivity in vanilla JS syntax, as seen in the middle code above, but that was greatly limited [in many ways](https://svelte.dev/blog/runes)! And, unfortunately, Svelte is unable to move forward with that idea in v5!

Problem with the above is: that whole idea of manually modelling relationships is an overhead; **you're paying a price that need not be paid**! Short explainer: you do not need to *re-express* the dependency graph of your logic **when that's a baseline knowledge for any runtime**! Plus, you could never do that manually as cheaply, and as accurately as a runtime would!

Long explainer is what I presented in [Re-Exploring Reactivity and Introducing the Observer API and Reflex Functions](https://dev.to/oxharris/re-exploring-reactivity-and-introducing-the-observer-api-and-reflex-functions-4h70) — the previous post in this series! You'll find that we can have reactivity without a shift in programming paradigm!

It turns out, we're able to *again* delegate this work to the platform and simply enable reactive programming in the ordinary imperative form of JavaScript! Impossible? That is what we sought to explore with the [Quantum JavaScript](https://github.com/webqit/quantum-js) project!

Quantum JS is a runtime extension to JavaScript that lets us write ordinary JavaScript and have it work reactively! Given our markup above, we're able to simply opt-in to reactive programming on the regular `<script>` element using the `quantum` attribute:

```html
<script quantum>
  // Global count
  let count = 0;
  let doubleCount = count * 2;
  setInterval(() => count++, 1000);

  document.bindings.count = count;
  document.bindings.doubleCount = doubleCount;
</script>
```

and for the Custom Element definition, we're able to turn our existing `connectedCallback()` method to a Quantum function using a special `quantum` flag:

```js
// Local count
customElements.define('my-counter', class extends HTMLElement {
  quantum connectedCallback() {
    let count = 0;
    let doubleCount = count * 2;
    setInterval(() => count++, 1000);

    this.bindings.count = count;
    this.bindings.doubleCount = doubleCount;
  }
});
```

It's exciting how we practically now have a universal syntax across both reactive and non-reactive code and can now leverage metal-level accuracy and performance! And as a runtime extension to JavaScript, there isn't the "Svelte 3" sort of limitations like relying on symbolism or top-level `let` declaration, and others! On the contrary, you are able to enjoy the [full range](https://github.com/webqit/quantum-js/wiki) of the JS language — conditionals and loops, spread and "rest" syntax sugars, flow control statements, etc.

### This Works Today!

Simply include the OOHTML Polyfill and you have a new useful magic right in the browser! You wanna try the "Imperative Lists" example in the [list of examples](https://github.com/webqit/oohtml?tab=readme-ov-file#examples) to have a feel!

{% details Polyfill %}

```html
<head>
  <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
  <!-- other code -->
</head>
```

{% enddetails %}

You may also want to visit [Quantum JS](https://github.com/webqit/quantum-js) itself and [leave us a star](https://github.com/webqit/oohtml) 🌟.

------------

## Question 2: How Do You Make Components?

Let's say: [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components), or, in other words, [Custom Elements](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements) and the [Shadow DOM](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM) — being collectively a powerful mechanism for encapsulating behaviour, structure, and styling!

Cool, but... there are times you aren't thinking about a "custom" element or some special technology called Shadow DOM when you say "component"!

Given the [tailwind component library](https://tailwindui.com/components/preview) as one random reference
+ the [Daisy UI library](https://daisyui.com/components/) as another
+ the [Bootstrap starter library](https://getbootstrap.com/docs/5.3/examples/#snippets) as another

a sampling of people's idea of that term should include:

+ a distinct unit of behaviour
    - e.g. a **carousel** component that enables a certain form of interaction consistently across instances, e.g. rotating through a series of images or content
+ a distinct structural form
    - e.g. a **card** component that models a certain structure consistently across instances, e.g. featuring an image, a title bar, a description line, a summary area
+ a distinct visual form
    - e.g. a **grid** component that presents elements in a certain pattern consistently across instances

This means that **it isn't always a Web Components' call**! For example, what have many "visual" components, like **grid** above, got to do with Custom Elements or Shadow DOM? And let's just say, this whole idea of subtree isolation which the Shadow DOM is best for, isn't always the idea for many, many "components"!

Consider, for example, structural components, like **card** above! I often just want a way to "model" the needed relationships, or, in other words, a way to associate the card's features like *image* and *title bar* with the card, and nothing more! (Something people have done for years with a naming convention like [BEM](https://getbem.com/)!)

```html
<div class="card">
  <img class="card__image" src="image.jpg" alt="Image">
  <h2 class="card__title">Card Title</h2>
  <div>
    <p class="card__description">Card Description</p>
  </div>
  <div>
    <p class="card__summary">Card Summary</p>
  </div>
</div>
```

which would translate to writing CSS selectors that feel "namespaced":

```css
.card { ... }
.card__title { ... }
```

This means, **you more often just want to write _modular markup_ and less often want to opt-in to subtree isolation and a new rendering model**!

The ideal authoring experience for HTML, therefore === **having a way to do _both_ elegantly: author modular markup by default and let the use case decide when to opt-in to the Shadow DOM**!

### Introducing: Namespacing

Enter modular markup: we currently have to rely on annoying naming conventions to model relationships. (E.g. BEM, above.) And for the relationships that work with only IDREFs, like the relationship between a `<label>` and an `<input>`, and others involving [ARIA Relationship Attributes](https://www.w3.org/TR/wai-aria-1.1/#attrs_relationships), we are challenged with HTML's global ID system wherein you have to generate IDs that must be unique throughout the document:

```html
<form>

  <fieldset>
    <legend>Home Address</legend>

    <label for="home__address-line">Address</label>
    <input id="home__address-line">

    <label for="home__city">City</label>
    <input id="home__city">
  <fieldset>

  <fieldset>
    <legend>Delivery Address</legend>

    <label for="delivery__address-line">Address</label>
    <input id="delivery__address-line">
    
    <label for="delivery__city">City</label>
    <input id="delivery__city">
  <fieldset>

</form>
```

This has you thinking globally even when what you're working on has no global relevance! For a fairly-sized document, the level of coordination needed at the global level is often too unrealistic to happen by hand!

But how about a way to keep those relationships local, or implicitly namespaced? Meet the `namespace` attribute:

```html
<form>

  <fieldset namespace>
    <legend>Home Address</legend>

    <label for="~address-line">Address</label>
    <input id="address-line">

    <label for="~city">City</label>
    <input id="city">
  <fieldset>

  <fieldset namespace>
    <legend>Delivery Address</legend>

    <label for="~address-line">Address</label>
    <input id="address-line">
    
    <label for="~city">City</label>
    <input id="city">
  <fieldset>

</form>
```

Notice how we haven't introduced a breaking change to how IDREFs are resolved in browsers! You need the tilde `~` character to denote "relativity", or "local" resolution.

You're able to use that in selectors to match things within a specified namespace:

```css
fieldset #~address-line {}
```

```js
document.querySelector('#~address-line'); // null; not in the global namespace
document.getElementById('~address-line'); // null; not in the global namespace

fieldset.querySelector('#~address-line'); // input#address-line; in the fieldset namespace
```

In JavaScript, you are additionally able to access these elements declaratively using the `namespace` API:

```js
let { city, ... } = fieldset.namespace;
```

And you get reactivity for free on top of that — in being able to observe DOM changes happening within given namespace:

```js
Observe.observe(fieldset.namespace, changes => {
  console.log(changes);
});
```

### Good Thinking?

This is all currently possible using the OOHTML Polyfill!

The "Multi-Level Namespacing" example in the [list of examples](https://github.com/webqit/oohtml?tab=readme-ov-file#examples) is something you may want to try!

{% details Polyfill %}

```html
<head>
  <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
  <!-- other code -->
</head>
```

{% enddetails %}

You may also want to visit the [Namespacing section](https://github.com/webqit/oohtml?tab=readme-ov-file#namespacing) in the project README to learn more!

I again ask that you share your thoughts and [leave us a star](https://github.com/webqit/oohtml) 🌟!

### Introducing: Style and Script Scoping

While namespacing helps us keep IDREFs relative, we still need a way to keep component-specific style sheets and scripts scoped! This [is a common idea across frameworks](https://vuejs.org/guide/scaling-up/sfc.html)!

Here, we are able to do that using a new `scoped` attribute:

```html
<div>

  <style scoped>
    :scope { color: red }
  </style>

  <script scoped>
    console.log(this) // div
  </script>

</div>
```

Just like that!

Now, that comes especially crucial to SPAs!

It is often asked how the `scoped` attribute on the `<style>` element compares with the `@scope` rule in the [CSS Cascading and Inheritance Level 6 Module](https://drafts.csswg.org/css-cascade-6/) which [lets us do something similar](https://drafts.csswg.org/css-cascade-6/#example-52419898):

```html
<div>
  <style>
    @scope {
      p { color: red; }
    }
  </style>
  <p>this is red</p>
</div>
<p>not red</p>
```

But here's the deal with the attribute-based approach:

+ Free of an extra nesting level!

+ Consistent with the syntax for two other things in the scoping agenda: scoped scripts — `<script scoped>` — and scoped HTML modules — `<template scoped>` — as we'll see shortly!

+ Presents one way to interpret a `<style>` element: as either "entirely scoped" or "entirely unscoped"; which isn't the case with the `@scope` rule approach:

    {% details Code %}

    ```html
    <style scoped>
    /* scoped rules */
    <style>

    <style>
    /* unscoped rules */
    <style>
    ```

    vs

    ```html
    <style>
    @scope {
      /* scoped rules */
    }
    /* unscoped rules */
    @scope {
      /* scoped rules */
    }
    /* unscoped rules */
    </style>
    ```
    &ensp;
    > Notice how the latter requires you to parse the CSS source text itself to know what's going on with a `<style>` element, vs how the the former removes the guesswork at the attribute level!

    {% enddetails %}

+ Presents us an opportunity to have scoped style sheets that can truly make no global footprint, as in, this time, map to their immediate host element instead of to the document:

    {% details Code %}

    ```html
    <div>
      <style scoped>
      /* scoped rules */
      </style>
    </div>

    <style>
    /* unscoped rules */
    </style>
    ```
    &ensp;
    ```js
    // Given that the scoped style sheet really has no global relevance
    console.log(div.styleSheets.length); // 1
    // Only the second style sheet making a global footprint
    console.log(document.styleSheets.length); // 1
    ```
    
    {% enddetails %}

That said, here's how the `scoped` attribute works for the `<style>` element:

+ the `:scoped` pseudo selector is treated as a reference the style sheet's host element
+ the relative ID selector, e.g. `#~child`, is resolved within given namespace:
    
    {% details Code %}
    
    ```html
    <div namespace>

      <p id="child"></p>

      <div namespace>
        <p id="child"></p>
      </div>

      <style scoped>
      /* matches only the first "p" */
      #~child { color: red; }
      /* matches all "p" as usual */
      #child { background-color: whitesmoke; }
      </style>

    </div>
    ```
    
    {% enddetails %}


+ where multiple identical scoped styles exists, you are able to add an (experimental) `shared` directive, as in `<style scoped shared>`, to get only the first instance processed and shared by all host as an [adopted style sheet](https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptedStyleSheets), to optimise performance:

    {% details Code %}
    
    ```html
    <ul>
      <li>
        <style scoped shared></style>
      </li>
      <li>
        <style scoped shared></style>
      </li>
    </ul>
    ```
    
    {% enddetails %}

and here's how the `scoped` attribute works for the `<script>` element:

+ the `this` keyword is bound to the script's host element
+ the `<script>` element is (re)executed on each re-insertion into the DOM

Did that just pique your interest?

### Try Now!

Simply include the OOHTML Polyfill and go ahead with scoping!

The "Single Page Application" example in the [list of examples](https://github.com/webqit/oohtml?tab=readme-ov-file#examples) is something I'm sure you wanna try!

{% details Polyfill %}

```html
<head>
  <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
  <!-- other code -->
</head>
```

{% enddetails %}

You may also want to visit the [Style and Script Scoping section](https://github.com/webqit/oohtml?tab=readme-ov-file#style-and-script-scoping) in the project README!

And we'd like for you to share your thoughts and [leave us a star](https://github.com/webqit/oohtml) 🌟!

------------

## Question 3: How Do You Re-Use Components?

A component architecture is a way to *organise code*! That involves being able to work on disparate pieces of an idea and have them automatically come together! It's about the biggest need frameworks fill! Now, something like that in the HTML/DOM land is the [`<defs>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) and [`<use>`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use) system in SVG!

You could mention the `<template>` element which affords us a place to define reusable pieces of markup. But the `<template>` element is really only half the idea of a *templating system*; the remaining half left out to imperative DOM APIs:

```js
let fragment = document.querySelector('template').content;
document.body.appendChild(fragment.cloneNode(true));
```

And when it comes to dealing with remote contents: a different set of APIs:

```js
fetch('/file.html').then(response => response.text()).then(content => {
  document.body.append(content);
});
```

This has meant doing half of the work in HTML and half in JS!

We do have the [HTML Modules proposal](https://github.com/WICG/webcomponents/blob/gh-pages/proposals/html-modules-explainer.md), **but that's still a JavaScript feature, not HTML**!

But here's what I have always wanted: **a simple define-and-use system in HTML**, just as with the SVG `<defs>` and `<use>` concept!

### Introducing: HTML Imports

HTML Imports is a system for *templating and reusing objects* - in both *declarative* and *programmatic* terms! It extends the language with a *definition* attribute — `def`, complements that with a new `<import>` element, and has everything working together as a real-time module system!

Here, we get a way to *both* define and reuse a snippet within same document, exactly as with the SVG `<defs>` and `<use>` system we've always had:

```html
<head>

  <template def="foo">
    <div></div>
  </template>

</head>
<body>

  <import ref="foo"></import>

</body>
```

...while optionally supporting remote content without a change in paradigm:

```html
<head>

  <template def="foo" src="/foo.html"></template>

</head>
<body>

  <import ref="foo"></import>
  
</body>
```

#### Module Definition

You use the `def` attribute to expose a `<template>` element, and optionally, its direct children, as definition:

```html
<head>

  <template def="foo">
    <div def="fragment1">A module fragment that can be accessed independently</div>
    <div def="fragment2">Another module fragment that can be accessed independently</div>
    <p>An element that isn't explicitly exposed.</p>
  </template>

</head>
```

And you are able to nest modules nicely for code organisation:

```html
<head>

  <template def="bar">
    <div def="fragment1"></div>

    <template def="nested">
      <div def="fragment2"></div>
    </template>
  </template>

</head>
```

#### Remote Modules

We shouldn't need a different mechanism to work with remote content.

Here, OOHTML extends the `<template>` with an `src` attribute that lets us have self-loading `<template>` elements::

```html
<template def="bar" src="/foo.html"></template>
```

└ *Loaded file:*

```html
-- file: /foo.html --
<div def="fragment1"></div>
<template def="nested" src="/nested.html"></template>
```

└ *Sub-loaded file:*

```html
-- file: /nested.html --
<div def="fragment2"></div>
```

And you can lazy-load modules using the `loading="lazy"` directive; meaning that loading doesn't happen until the first attempt to access the given model:

```html
<template def="foo" src="/foo.html" loading="lazy"></template>
```

#### Module Imports

You use the `<import>` element for declarative module imports:

> Notice the *before* and *after*

```html
<body> <!-- Before -->
  <import ref="/foo">Default content</import>
</body>
```

```html
<body> <!-- After -->
  <div def="fragment1"></div>
  <div def="fragment2"></div>
  <p></p>
</body>
```

```html
<body> <!-- Before -->
  <import ref="/foo#fragment1">Default content</import>
</body>
```

```html
<body> <!-- After -->
  <div def="fragment1"></div>
</body>
```

and the HTMLImports API for programmatic module imports:

```js
const result  = document.import('/foo#fragment1'); // module:/foo#fragment1, received synchronously
const divElement = result.value;
```

```js
document.import('/foo#fragment1', divElement => {
  console.log(divElement); // module:/foo#fragment1, received synchronously
});
```

```js
document.import('/bar/nested#fragment2', divElement => {
  console.log(divElement); // module:/bar/nested#fragment2;
});
```

#### Scoped Modules

Just as with [scoped styles and scripts](#introducing-style-and-script-scoping) above, you are able to scope `<template>` elements to create an object-scoped module system:

> Notice how paths are resolved as to whether globally or relatively.

```html
<section> <!-- module host -->

  <template def="foo" scoped> <!-- Scoped to host object and not available globally -->
    <div def="fragment1"></div>
  </template>

  <div>
    <import ref="foo#fragment1"></import> <!-- Relative path (beginning without a slash), resolves to the local module: foo#fragment1 -->
    <import ref="/foo#fragment1"></import> <!-- Absolute path (beginning with a slash), resolves to the global module: /foo#fragment1 -->
  </div>

</section>
```

Paths are also resolved the same way on the HTMLImports API:

```js
// Showing relative path resolution
document.querySelector('div').import('foo#fragment1', divElement => {
  console.log(divElement); // the local module: foo#fragment1
});
```

```js
// Showing absolute path resolution
document.querySelector('div').import('/foo#fragment1', divElement => {
  console.log(divElement); // the global module: foo#fragment1
});
```

*Consider:*

> Custom elements can now, sometimes, be designed to have their logic decoupled from markup:
>
> ```html
> <my-element> <!-- module host -->
>
>   <template def="foo" scoped> <!-- Scoped to host object and not available globally -->
>     <div def="fragment1"></div>
>   </template>
>
> </my-element>
> ```
> &ensp;
> and in JS:
>
> ```js
> customElements.define('my-element', class extends HTMLElement {
>   connectedCallback() {
>     const { value: divElement } = this.import('foo#fragment1'); // the local module: foo#fragment1
>     this.shadowRoot.appendChild(divElement.cloneNode());
>   }
> });
> ```

### Cool Yet?

This is something you may find really interesting! You'll find that there's a whole lot that a declarative define-and-use system in HTML can change in your daily workflow!

Simply grab the OOHTML polyfill and game on with some of the [examples](https://github.com/webqit/oohtml?tab=readme-ov-file#examples)!

{% details Polyfill %}

```html
<head>
  <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
  <!-- other code -->
</head>
```

{% enddetails %}

Once you're comfortable with the basics, you may also want to visit the rest of the story in the [HTML Imports section](https://github.com/webqit/oohtml?tab=readme-ov-file#html-imports) in the project README!

And as before, we'd like for you to share your thoughts and [leave us a star](https://github.com/webqit/oohtml) 🌟!

------------

## Question 4: How Do You Pass Data/Props?

In a hierarchy of components, parent components often need to pass data down to child components or, in some scenarios, just expose certain data for consumption by anyone, including child components! 

On the first scenario, frameworks that do string concatenation for rendering, e.g. [Lit](https://lit.dev), often let you do parent-to-child data-passing via markup/data interpolation, and everything together is parsed into what becomes the DOM: 

```js
// Example in Lit
render() {
  return html`
    <h1>Parent Component</h1>
    <!-- use the dot (.) syntax to pass data as a property -->
    <child-component .data=${this.childData}></child-component>
  `; 
}
```

By contrast, data-passing on an already constructed DOM tree is really what we're talking about when it comes to the DOM!

Interestingly, you could do something as simple as setting arbitrary properties directly on child elements from within a parent element:

```js
// Inside a custom element
connectedCallback() {
  const child = this.querySelector('#child');
  child.data = this.childData;
}
``` 

Only that this isn't very elegant, given that, again, we would be littering an element's root namespace with application data and potentially conflicting with native DOM properties and methods! This is to say, we need a better idea around here!

### Introducing: The Bindings API 

This is a simple, read/write, data object exposed on the document object and on DOM elements as a `bindings` property:

```js
// Read
console.log(document.bindings); // {}
// Modify
document.bindings.app = { title: 'Demo App' };
console.log(document.bindings.app); // { title: 'Demo App' }
```

```js
const node = document.querySelector('div');
// Read
console.log(node.bindings); // {}
// Modify
node.bindings.style = 'tall-dark';
node.bindings.normalize = true;
```

This is the same Bindings API we introduced in the [data-binding section](https://dev.to/oxharris/html-bmo-temp-slug-6744225?preview=065ed74e3971baef5ddc59438403d900d31f1f6bdbabf03ad1fc884720ab2ebc1e5d27a9bc64481c3354e39109dc7ba94f5fe64c06efd61725d4d68f#introducing-native-data-binding-for-html)! But it happens to be designed for arbitrary state management - which fits right in with our case: 

```js
// Notice our use of the Bindings API 
connectedCallback() {
  const child = this.querySelector('#child');
  child.bindings.data = this.bindings.childData;
}
``` 

And above, if we went further to take advantage of the namespace API, we'd be able to access the said child elements declaratively, as against having to imperatively query the DOM: 

```js
// Notice our use of the Namespace API 
connectedCallback() {
  this.namespace.child.bind(this.bindings.childData);
}
```

or...

```js
// We could destructure the above for a more beautiful code
connectedCallback() {
  let { child } = this.namespace;
  let { childData } = this.bindings;
  child.bind(childData);
}
```
Now as a perk, we get reactivity for free on all of the moving parts above: a way to observe when `this.bindings.childData` changes and a way to observe when `this.namespace.child` changes: 

```js
// Notice the observers
connectedCallback() {
  const bind = (child, data) => child.bind(data);
  // bind current values
  bind(this.namespace.child, this.bindings.childData);
  // Bind new values on change
  Observer.observe(this.bindings, 'childData', (e) => bind(this.namespace.child, e.value));
  Observer.observe(this.namespace, 'child', (e) => bind(e.value, this.bindings.childData));
}
``` 

Better yet, we are able to have that same reactivity happen declaratively if we implemented our `connectedCallback()` method as `quantum` function: 

```js
// Notice the double star
quantum connectedCallback() {
  let { child } = this.namespace;
  let { childData } = this.bindings;
  child.bind(childData);
}
``` 

And when not dealing with class instances, we are able to achieve the same logic, and same reactivity, using a scoped, `quantum` script: 

```html
<div namespace>

  <div id="child"></div>

  <script scoped quantum>
    let { child } = this.namespace;
    let { childData } = this.bindings;
    child.bind(childData);
  </script>

</div>
```

### Good Job There?

You'll find that it makes it easier to reason about state management in the DOM, and provides a better way to write Web Components!

Simply include the OOHTML polyfill from a CDN and game on!

{% details Polyfill %}

```html
<head>
  <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
  <!-- other code -->
</head>
```

{% enddetails %}

And here's one take-home idea for a Single Page Application:  the code below, wherein on each navigation to a URL, data is programmatically fetched (via `fetch()`), then JSONed to a JavaScript object and held as global state at `document.bindings` (which you're able to directly render anywhere in the page):

```html
<!DOCTYPE html>
<html>

  <head>
    <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
    <script>
      async function route() {
        const data = await fetch(`http://localhost:3000/api/${ location.hash.substring(1) }`).then(response => response.json());
        document.bind({ pageTitle: data.pageTitle });
      }
      window.addEventListener('hashchange', route);
    </script>
  </head>

  <body>
    <h1>Page title is: <?{ pageTitle }?>.</h1>
  </body>

</html>
``` 

(Now, you may fuse that with the "Single Page Application" example in the [list of examples](https://github.com/webqit/oohtml#examples) to implement individual page layouts for each URL!)

Maybe you'll have some thoughts to share!

You may also want to visit the [Bindings API section](https://github.com/webqit/oohtml#the-bindings-api) on the project README to learn more! And do remember to [leave us a star](https://github.com/webqit/oohtml) 🌟!

### Introducing: The Context API 

While we're able to explicitly bind data on DOM nodes using the Bindings API, giving parents a way to pass data down to child components, sometimes the goal is to just expose certain data at a certain level in the DOM tree for consumption by anyone, including child components! This time, instead of the below:

```js
// Inside "parent" component
connectedCallback() {
  let { child } = this.namespace;
  let { childData } = this.bindings;
  child.bind(childData);
}
```

we now want "child" to request said data from "context":

```js
// Inside "child" component
connectedCallback() {
  let parent = this.parentNode;
  let { childData } = parent.bindings;
  this.bind(childData);
}
```

much like an *inversion of control*!

Now, while we've used the immediate parent node for our data source above, it is sometimes impossible to predetermine the exact location up the tree to find said data, in which case, the idea of walking up the DOM tree mechanically - `this.parentNode.parentNode...` - not only creates a tight coupling between components, but also fails quickly!

That's where a Context API comes in!

You'd find the same philosophy with [React](https://react.dev/reference/react/createContext#usage), and something similar with [Lit](https://lit.dev/docs/data/context/), and perhaps something of same sort with other frameworks!

In our case, we simply leverage the DOM's existing event system to fire a "request" event and let an arbitrary "provider" in context fulfil the request. All of this is made available via an API named `contexts`, exposed on the document object and on DOM elements!

Here, we get a `contexts.request()` method for firing requests:

```js
// ------------
// Get an arbitrary
const node = document.querySelector('my-element');

// ------------
// Prepare and fire request event
const requestParams = { kind: 'html-imports', detail: '/foo#fragment1' };
const response = node.contexts.request(requestParams);

// ------------
// Handle response
console.log(response.value); // It works!
```

and a `contexts.attach()` and `contexts.detach()` methods for attaching/detaching providers at arbitrary levels in the DOM tree:

```js
// ------------
// Define a CustomContext class
class FakeImportsContext extends DOMContext {
  static kind = 'html-imports';
  handle(event) {
    console.log(event.detail); // '/foo#fragment1'
    event.respondWith('It works!');
  }
}

// ------------
// Instantiate and attach to a node
const fakeImportsContext = new FakeImportsContext;
document.contexts.attach(fakeImportsContext);

// ------------
// Detach anytime
document.contexts.detach(fakeImportsContext);
```

And everything comes as one standardized API for looking up the document context for any use case! In fact, the Context API is integral to the Namespace API and the Data Binding and HTML Imports features in OOHTML!

Now, we are able to use the Context API to retrieve the said "binding" in our parent-child scenario earlier:

```js
// Inside "child" component
connectedCallback() {
  const requestParams = { kind: 'data-binding', detail: 'childData' };
  let { value: childData } = this.contexts.request(requestParams);
  this.bind(childData);
}
```

### Exciting Yet?

This is covered in detail in the [Context API section](https://github.com/webqit/oohtml#the-context-api) on the project README!

It goes without saying that this too is possible today using the OOHTML polyfill!

{% details Polyfill %}

```html
<head>
  <script src="https://unpkg.com/@webqit/oohtml/dist/main.lite.js"></script>
  <!-- other code -->
</head>
```

{% enddetails %}

Take that as an invitation to explore and share your thoughts! And we'll be more than delighted to have you [leave us a star](https://github.com/webqit/oohtml) 🌟!

That's now a wrap!

-----------

But that's probably a lot to unpack! Well, think of OOHTML as not one, but a suite of small, interrelated proposals with one agenda: **towards a more dynamic, object-oriented HTML**! While features may be discussed or explored individually, the one agenda helps us stay aligned with the original problem!

As with everything on the web, your contribution is how this gets better!

The polyfill is actively developed and kept in sync with the spec. You'll find that it goes a long way to help us not think in a vacuum! And it's gone as far as help us build interesting internal apps! (And that's a go ahead to give yours a shot! Not to mean that there aren't bugs there waiting to be discovered!)

Finally, here we go:

{% embed https://github.com/webqit/oohtml %}