{"id":21310956,"url":"https://github.com/webqit/oohtml","last_synced_at":"2025-04-12T22:19:17.505Z","repository":{"id":41936664,"uuid":"319665781","full_name":"webqit/oohtml","owner":"webqit","description":"Towards a more dynamic and object-oriented HTML.","archived":false,"fork":false,"pushed_at":"2025-03-04T12:01:50.000Z","size":27252,"stargazers_count":123,"open_issues_count":0,"forks_count":7,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-04T06:04:39.701Z","etag":null,"topics":["data-binding","html-imports","html-include","html-partials","namespaced-html","observer-api","oohtml","proposal","quantum-js","scoped-css","scoped-html","scoped-js"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/webqit.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"ox-harris","patreon":null,"open_collective":"webqit","ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2020-12-08T14:36:59.000Z","updated_at":"2025-03-04T12:01:55.000Z","dependencies_parsed_at":"2023-02-16T05:45:50.499Z","dependency_job_id":"5df29bca-ba80-41d5-ad05-659c33f9c109","html_url":"https://github.com/webqit/oohtml","commit_stats":{"total_commits":429,"total_committers":3,"mean_commits":143.0,"dds":0.5547785547785548,"last_synced_commit":"4a3960b46d760b090b9c25055080afad1f3e78a6"},"previous_names":[],"tags_count":248,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webqit%2Foohtml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webqit%2Foohtml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webqit%2Foohtml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webqit%2Foohtml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webqit","download_url":"https://codeload.github.com/webqit/oohtml/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248638018,"owners_count":21137586,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["data-binding","html-imports","html-include","html-partials","namespaced-html","observer-api","oohtml","proposal","quantum-js","scoped-css","scoped-html","scoped-js"],"created_at":"2024-11-21T17:15:20.492Z","updated_at":"2025-04-12T22:19:17.473Z","avatar_url":"https://github.com/webqit.png","language":"JavaScript","readme":"# OOHTML\n\n[![npm version][npm-version-src]][npm-version-href]\u003c!--[![npm downloads][npm-downloads-src]][npm-downloads-href]--\u003e\n[![bundle][bundle-src]][bundle-href]\n[![License][license-src]][license-href]\n\n**[Explainer](#explainer) • [Features](#features) • [Modular HTML](#modular-html) • [HTML Imports](#html-imports) • [Data Binding](#data-binding) • [Data Plumbing](#data-plumbing) • [Implementation](#implementation) • [Examples](#examples) • [License](#license)**\n\nObject-Oriented HTML (OOHTML) is a set of features that extend standard HTML and the DOM to enable authoring modular, reusable and reactive markup - with a \"buildless\" and intuitive workflow as design goal! This project revisits the HTML problem space to solve for an object-oriented approach to HTML!\n\nBuilding Single Page Applications? OOHTML is a special love letter! Writing Web Components? Now you can do so with zero tooling! Love vanilla HTML but can't go far with that? Well, now you can!\n\n\u003cdetails\u003e\u003csummary\u003eVersions\u003c/summary\u003e\n\n*This is documentation for `OOHTML@4`. (Looking for [`OOHTML@1`](https://github.com/webqit/oohtml/tree/v1.10.4)?)*\n\n\u003c/details\u003e\n\n## Status\n\n+ Actively maintained\n+ A working implementation\n+ [Proposed at the WICG](https://github.com/WICG/proposals/issues/137)\n+ Open to contributions\n\n## Implementation\n\nOOHTML may be used today. This implementation adheres closely to the spec and helps evolve the proposal through a practice-driven process.\n\n\u003cdetails\u003e\u003csummary\u003eLoad from a CDN\u003cbr\u003e\n└───────── \u003ca href=\"https://bundlephobia.com/result?p=@webqit/oohtml\"\u003e\u003cimg align=\"right\" src=\"https://img.shields.io/badge/21.8%20kB-black\"\u003e\u003c/a\u003e\u003c/summary\u003e\n\n```html\n\u003cscript src=\"https://unpkg.com/@webqit/oohtml/dist/main.lite.js\"\u003e\u003c/script\u003e\n```\n\n└ This is to be placed early on in the document and should be a classic script without any `defer` or `async` directives!\n\n└ For `@webqit/oohtml@3.1` and below, you would need an external polyfill - like the [samthor/scoped](https://github.com/samthor/scoped) polyfill - for the Scoped Styles feature:\n\n```html\n\u003chead\u003e\n  \u003cscript src=\"https://unpkg.com/style-scoped/scoped.min.js\"\u003e\u003c/script\u003e\n\u003c/head\u003e\n```\n\n└ Being an integral part of OOHTML, the Observer and Quantum JS APIs are also accessible on loading the OOHTML polyfill:\n\n```js\nconst { QuantumFunction, QuantumAsyncFunction, QuantumScript, QuantumModule, QuantumAsyncScript, State, Observer } = window.webqit;\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eInstall from NPM\u003cbr\u003e\n└───────── \u003ca href=\"https://npmjs.com/package/@webqit/oohtml\"\u003e\u003cimg align=\"right\" src=\"https://img.shields.io/npm/v/@webqit/oohtml?style=flat\u0026label=\u0026colorB=black\"\u003e\u003c/a\u003e\u003c/summary\u003e\n\n```bash\nnpm i @webqit/oohtml @webqit/quantum-js\n```\n\n```js\n// Import\nimport * as Quantum from '@webqit/quantum-js/lite'; // Or from '@webqit/quantum-js'; See implementation notes below\nimport init from '@webqit/oohtml/src/init.js';\n\n// Initialize the lib\ninit.call(window, Quantum[, options = {}]);\n```\n\n└ Being an integral part of OOHTML, the Observer API, in addition to the Quantum JS APIs, is also available from the OOHTML installation:\n\n```js\nimport * as Observer from '@webqit/observer';\n```\n\n└ To use the polyfill on server-side DOM instances as made possible by libraries like [jsdom](https://github.com/jsdom/jsdom), simply install and initialize the library with the DOM instance as above.\n\n└ But all things \"SSR\" for OOHTML are best left to the [`@webqit/oohtml-ssr`](https://github.com/webqit/oohtml-ssr) package!\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eExtended usage concepts\u003c/summary\u003e\n\nIf you'll be going ahead to build a real app with OOHTML, you may want to consider also using:\n\n+ the [`@webqit/oohtml-cli`](https://github.com/webqit/oohtml-cli) package for operating a file-based templating system.\n\n+ the modest, OOHTML-based [Webflo](https://github.com/webqit/webflo) framework to greatly streamline your workflow!\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eImplementation Notes\u003c/summary\u003e\n\n+ **Scoped/Quantum Scripts**. This feature is an extension of [Quantum JS](https://github.com/webqit/quantum-js). While the main OOHTML build is based on the main Quantum JS APIs, a companion \"OOHTML Lite\" build is also available based on the [Quantum JS Lite](https://github.com/webqit/quantum-js#quantum-js-lite) edition. The trade-off is in the execution timing of `\u003cscript quantum\u003e\u003c/script\u003e` and `\u003cscript scoped\u003e\u003c/script\u003e` elements: being \"synchronous/blocking\" with the former, and \"asynchronous/non-blocking\" with the latter! (See [`async`/`defer`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#attributes).)\n\n    Of the two, the \"OOHTML Lite\" edition is the recommend option on web pages (as used above) for faster load times unless there's a requirment to emulate the [native synchronous timing](https://html.spec.whatwg.org/multipage/parsing.html#scripts-that-modify-the-page-as-it-is-being-parsed) of classic scripts, in which case you'd need the main OOHTML build:\n\n    ```html\n    \u003chead\u003e\n      \u003cscript src=\"https://unpkg.com/@webqit/oohtml/dist/main.js\"\u003e\u003c/script\u003e\n    \u003c/head\u003e\n    ```\n\n    └─ \u003ca href=\"https://bundlephobia.com/result?p=@webqit/oohtml\"\u003e\u003cimg align=\"right\" src=\"https://img.shields.io/bundlephobia/minzip/@webqit/oohtml?label=\u0026style=flat\u0026colorB=black\"\u003e\u003c/a\u003e\n\n+ **Loading Requirements**. As specified above, the OOHTML script tag is to be placed early on in the document and should be a classic script without any `defer` or `async` directives!\n    \n    If you must load the script \"async\", one little trade-off would have to be made for `\u003cscript scoped\u003e` and `\u003cscript quantum\u003e` elements to have them ignored by the browser until the polyfill comes picking them up: *employing a custom MIME type in place of the standard `text/javascript` and `module` types*, in which case, a `\u003cmeta name=\"scoped-js\"\u003e` element is used to configure the polyfill to honor the custom MIME type:\n\n    ```html\n    \u003chead\u003e\n      \u003cmeta name=\"scoped-js\" content=\"script.mimeTypes=module|text/javascript|application/javascript|some-mime\"\u003e\n      \u003cscript async src=\"https://unpkg.com/@webqit/oohtml/dist/main.lite.js\"\u003e\u003c/script\u003e\n    \u003c/head\u003e\n    \u003cbody\u003e\n      \u003cscript type=\"some-mime\" scoped\u003e\n        console.log(this); // body\n      \u003c/script\u003e\n    \u003c/body\u003e\n    ```\n\n    The custom MIME type strategy also comes in as a \"fix\" for when in a browser or other runtime where the polyfill is not able to intercept `\u003cscript scoped\u003e` and `\u003cscript quantum\u003e` elements ahead of the runtime - e.g. where...\n\n    ```html\n    \u003cbody\u003e\n      \u003cscript scoped\u003e\n        console.log(this); // body\n      \u003c/script\u003e\n    \u003c/body\u003e\n    ```\n\n    ...still gives the `window` object in the console.\n\n+ **Syntax**. The syntax for attribute names and API names across features - e.g. the `def` and `ref` attributes, the `render` attribute - isn't finalized, and may change on subsequent iterations, albeit with same principle of operation. But the polyfill is designed to be configurable via meta tags, and to honour any such \"overrides\". Here's an example:\n\n    ```html\n    \u003chead\u003e\n      \u003c!-- Configurations come before the polyfil --\u003e\n      \u003cmeta name=\"data-binding\" content=\"attr.render=render;\"\u003e\n      \u003cmeta name=\"namespaced-html\" content=\"attr.id=id;\"\u003e\n      \u003cmeta name=\"html-imports\" content=\"attr.def=def; attr.ref=ref;\"\u003e\n      \u003cscript src=\"https://unpkg.com/@webqit/oohtml/dist/main.js\"\u003e\u003c/script\u003e\n    \u003chead\u003e\n    ```\n\n    Now, even when the default syntax change, your `def`, `ref`, etc. overrides will keep your implementation intact.\n\n    Additionally, you could employ a global prefix in your implementation:\n\n    ```html\n    \u003cmeta name=\"webqit\" content=\"prefix=wq;\"\u003e\n    ```\n\n    ...which automatically applies to all `webqit` attributes and APIs (with the exception of the `scoped`, `quantum`, and `data-*` attributes), such that:\n\n    + `\u003ctemplate def=\"foo\"\u003e\u003c/template\u003e` now becomes: `\u003ctemplate wq-def=\"foo\"\u003e\u003c/template\u003e`,\n    + `\u003cimport ref=\"foo\"\u003e\u003c/import\u003e` now becomes: `\u003cwq-import wq-ref=\"foo\"\u003e\u003c/wq-import\u003e`,\n    + `document.import()` now becomes: `document.wqImport()`,\n    + `document.bind()` now becomes: `document.wqBind()`,\n    + `document.bindings` now becomes: `document.wqBindings`,\n    + etc.\n\n    \u003cdetails\u003e\u003csummary\u003eShow the full syntax table\u003c/summary\u003e\n\n    **Spec: `\u003cmeta name=\"data-binding\"\u003e`**\n\n    | Config | Default Syntax | Description |\n    | :----- | :------------- | :---------- |\n    | `attr.render` | `render` | The \"render\" attribute for inline data binding. ([Docs](#inline-data-binding)) |\n    | `attr.itemIndex` | `data-index` | The \"item index\" attribute for assigning indexes to list items. ([Docs](#inline-data-binding))  |\n\n    **Spec: `\u003cmeta name=\"bindings-api\"\u003e`**\n\n    | Config | Default Syntax | Description |\n    | :----- | :------------- | :---------- |\n    | `attr.bindingsreflection` | `bindings` | The attribute for exposing an element's bindings. |\n    | `api.bind` | `bind` | The `document.bind()` and `Element.prototype.bind()` methods. ([Docs](#the-bindings-api)) |\n    | `api.bindings` | `bindings` | The `document.bindings` and `Element.prototype.bindings` object properties. ([Docs](#the-bindings-api)) |\n\n    **Spec: `\u003cmeta name=\"context-api\"\u003e`**\n\n    | Config | Default Syntax | Description |\n    | :----- | :------------- | :---------- |\n    | `attr.contextname` | `contextname` | The \"context name\" attribute on arbitrary elements. ([Docs](#the-context-api)) |\n    | `api.contexts` | `contexts` | The `document.contexts` and `Element.prototype.contexts` object properties. ([Docs](#the-context-api)) |\n\n    **Spec: `\u003cmeta name=\"html-imports\"\u003e`**\n\n    | Config | Default Syntax | Description |\n    | :----- | :------------- | :---------- |\n    | `elements.import` | `import` | The tag name for \"import\" elements. ([Docs](#html-imports)) |\n    | `attr.def` | `def` | The \"definition\" attribute on the `\u003ctemplate\u003e` elements. ([Docs](#module-definition)) |\n    | `attr.fragmentdef` | *Inherits the value of `attr.def`* | The \"definition\" attribute on a `\u003ctemplate\u003e`'s contents. ([Docs](#module-definition)) |\n    | `attr.extends` | `extends` | The \"extends\" attribute for extending definitions. ([Docs](#module-inheritance)) |\n    | `attr.inherits` | `inherits` | The \"inherits\" attribute for inheriting definitions. ([Docs](#module-inheritance)) |\n    | `attr.ref` | `ref` | The \"import ref\" attribute on \"import\" elements. ([Docs](#declarative-module-imports)) |\n    | `attr.importscontext` | `importscontext` | The \"importscontext\" attribute on arbitrary elements. ([Docs](#imports-contexts)) |\n    | `api.def` | `def` | The readonly string property for accessing an element's \"def\" value. ([Docs](#module-definition)) |\n    | `api.defs` | `defs` | The readonly object property for accessing a `\u003ctemplate\u003e`'s list of definitions. ([Docs](#module-definition)) |\n    | `api.import` | `import` | The `document.import()` and `Element.prototype.import()` methods. ([Docs](#imperative-module-imports)) |\n\n\n    **Spec: `\u003cmeta name=\"namespaced-html\"\u003e`**\n\n    | Config | Default Syntax | Description |\n    | :----- | :------------- | :---------- |\n    | `attr.namespace` | `namespace` | The \"namespace\" attribute on arbitrary elements. ([Docs](#namespacing)) |\n    | `attr.id` | `id` | The \"id\" attribute on arbitrary elements. ([Docs](#namespacing)) |\n    | `api.namespace` | `namespace` | The \"namespace\" object property on arbitrary elements. ([Docs](#namespacing)) |\n\n    **Spec: `\u003cmeta name=\"scoped-css\"\u003e`** (TODO)\n\n    **Spec: `\u003cmeta name=\"scoped-js\"\u003e`** (TODO)\n\n    \u003c/details\u003e\n\n\u003c/details\u003e\n\n## Explainer\n\n\u003cdetails\u003e\u003csummary\u003eShow\u003c/summary\u003e\n\nAmidst a multitude of approaches, vanilla HTML remains an attractive option for authoring modern UI! But the current authoring experience still leaves much to be desired in how the language lacks modularity, reusability, and certain modern paradigms like data binding! Authors still have to rely on tools - and, for the most part, have to do half of the work in HTML and half in JS - to express even basic concepts!\n\n\"As an author, I want to be able to do 'x' *declaratively* in HTML instead of *imperatively* in JavaScript or by means of a special Custom Element!\" \"As a Web Component author, I want to be able to leverage *conventions* that keep my component logic *concise*!\" All such \"user stories\" represent important developer intuitions that has yet to be met in HTML; much of which belong under a broad subject: an object-oriented markup language! This subject is what we explore with OOHTML!\n\nOOHTML comes, not as a specific technology, but as a conceptual \"framework\" of features that solves for HTML as an object-oriented language - whether that means re-aligning existing features or introducing new ones! While features may be discussed or explored individually, the one agenda \"Object-Oriented HTML\" helps us stay aligned with the original problem! Each of these features has been introduced below with a small explainer.\n\nOOHTML is effectively different from Web Components (and from the related Declarative Custom Elements and Declarative Shadow DOM efforts) in its focus on \"arbitrary\" HTML and the DOM rather than on just the Custom Element or Shadow DOM \"subset\" of the language. This in turn lets us have a niftier authoring experience in Web Components as the latter actually just relies on the very HTML and DOM.\n\n└ You may want to learn more in the introductory article: [Revisiting the HTML Problem Space and Introducing OOHTML](https://dev.to/oxharris/revisiting-the-html-problem-space-and-introducing-oohtml-3oh5)\n\n\u003c/details\u003e\n\n## Features\n\n+ [Modular HTML](#modular-html)\n+ [HTML Imports](#html-imports)\n+ [Data Binding](#data-binding)\n+ [Data Plumbing](#data-plumbing)\n\n## Modular HTML\n\nThe modern UI is best approached with a modular architecture (think UI component frameworks) wherein we are able to author in bits and pieces while having each piece *encapsulate* their structure, styling and logic!\n\nOOHTML makes this possible by introducing \"namespacing\" and style and script scoping!\n\n### Namespacing\n\nNaming things is hard! That's especially so where you have one global namespace and a miriad of potentially conflicting identifiers to coordinate!\n\n\u003cdetails\u003e\u003csummary\u003eLearn more\u003c/summary\u003e\n\nYou want to see how IDs are, in fact, by default, exposed as global variables:\n\n```html\n\u003cdiv id=\"foo\"\u003e\u003cdiv\u003e\n```\n\n```js\nconsole.log(window.foo); // div\n```\n\n[Read more](https://stackoverflow.com/questions/6381425/is-there-a-spec-that-the-id-of-elements-should-be-made-global-variable)\n\n\u003c/details\u003e\n\nHere, we get a modular naming convention that let's us create a naming context for identifiers in a given subtree - by means of a new `namespace` attribute:\n\n```html\n\u003cform\u003e\n\n  \u003cfieldset namespace\u003e\n    \u003clegend\u003eHome Address\u003c/legend\u003e\n\n    \u003clabel for=\"~address-line\"\u003eAddress\u003c/label\u003e\n    \u003cinput id=\"address-line\"\u003e\n\n    \u003clabel for=\"~city\"\u003eCity\u003c/label\u003e\n    \u003cinput id=\"city\"\u003e\n  \u003cfieldset\u003e\n\n  \u003cfieldset namespace\u003e\n    \u003clegend\u003eDelivery Address\u003c/legend\u003e\n\n    \u003clabel for=\"~address-line\"\u003eAddress\u003c/label\u003e\n    \u003cinput id=\"address-line\"\u003e\n    \n    \u003clabel for=\"~city\"\u003eCity\u003c/label\u003e\n    \u003cinput id=\"city\"\u003e\n  \u003cfieldset\u003e\n\n\u003c/form\u003e\n```\n\nThis lets us have repeating structures with identical but non-conflicting identifiers. These identifiers are then referenced locally using \"local `IDREFS`\" - denoted by the `~` prefix.\n\nLocal `IDREFS` are resolved within the namespace where they're used (not globally; not deeply):\n\n```js\n// Matches \"#city\" within the fieldset's namespace; not super namespace, not sub namespace \nconst city = fieldset.querySelector('#~city');\n```\n\nAnd when used from the document context, these are resolved against top-level IDs; i.e. IDs in the document namespace itself (not deeply):\n\n```html\n\u003cdiv id=\"user\" namespace\u003e\n  \u003ca id=\"url\" href=\"https://example.org\"\u003e\n    \u003cspan id=\"name\"\u003eJoe Bloggs\u003c/span\u003e\n  \u003c/a\u003e\n  \u003ca id=\"email\" href=\"mailto:joebloggs@example.com\" \u003ejoebloggs@example.com\u003c/a\u003e\n\u003c/div\u003e\n```\n\n```js\n// Namespace aware ID selectors\nconsole.log(document.querySelector('#user')); // div#user\nconsole.log(document.querySelector('#~user')); // div#user\n\nconsole.log(document.getElementById('user')); // div#user\nconsole.log(document.getElementById('~user')); // div#user\n\nconsole.log(document.querySelector('#url')); // a#url\nconsole.log(document.querySelector('#~url')); // null... not directly in the \"document\" namespace\n\nconsole.log(document.getElementById('url')); // a#url\nconsole.log(document.getElementById('~url')); // null... not directly in the \"document\" namespace\n```\n\nAnd these also play well as navigation targets, with additional support for path expressions given a hierarchy of namespaces:\n\n```html\n\u003ca href=\"#~user/email\"\u003eJump to Email\u003c/a\u003e\n```\n\nAnd JavaScript applications are able to consume namespace structures as an object model:\n\n```html\nuser\n ├── url\n ├── name\n └── email\n```\n\n```js\n// The document.namespace API\nlet { user } = document.namespace;\n// The Element.prototype.namespace API\nlet { url, name, email } = user.namespace;\n```\n\n\u003cdetails\u003e\u003csummary\u003eAll in realtime\u003c/summary\u003e\n\nThe Namespace API is designed to always reflect the DOM in real-time. This may be observed using the general-purpose object observability API - [Observer API](https://github.com/webqit/observer):\n\n```js\n// Observing the addition or removal of elements with an ID\nObserver.observe(document.namespace, changeCallback);\n\nconst paragraph = document.createElement('p');\nparagraph.setAttribute('id', 'bar');\ndocument.body.appendChild(paragraph); // Reported synchronously\n```\n\n```js\n// Observing the addition or removal of elements with an ID\nparagraph.toggleAttribute('namespace', true);\nObserver.observe(paragraph.namespace, changeCallback);\n\nconst span = document.createElement('span');\nspan.setAttribute('id', 'baz');\nparagraph.appendChild(span); // Reported synchronously\n```\n\n```js\nfunction changeCallback(changes) {\n    console.log(changes[0].type, changes[0].key, changes[0].value, changes[0].oldValue);\n}\n```\n\n\u003c/details\u003e \n\n\u003cdetails\u003e\u003csummary\u003eImplementation details\u003c/summary\u003e\n\nIn the current implementation, a small random string is automatically prepended to each ID and IDREF token in the DOM to give the browser something \"unique\" to work with, but without that implementation detail leaking into your application. So, while an element may be seen in the browser console as having a random hash prepended to their ID or IDREF:\n\n```html\n\u003c!-- Original --\u003e\n\u003clabel for=\"~real-id\"\u003eQuestion 1:\u003c/label\u003e\n\u003cinput id=\"real-id\"\u003e\n```\n\n```html\n\u003c!-- Transformed --\u003e\n\u003clabel for=\"~hg3j:real-id\"\u003eQuestion 1:\u003c/label\u003e\n\u003cinput id=\"~hg3j:real-id\"\u003e\n```\n\nthe values your application sees are the unprefixed IDs and IDREFs:\n\n```js\nconsole.log(label.htmlFor); // ~real-id\nconsole.log(input.id); // real-id\n\nconsole.log(label.getAttribute('for')); // ~real-id\nconsole.log(input.attributes[0].value); // real-id\n```\n\nNow, for URL targets, e.g. `#~user/email`, the \"target\" element is given a custom `:target` class while it matches the URL fragment, and this may be accessed in CSS as:\n\n```css\n.\\:target {\n  background-color: whitesmoke;\n}\n```\n\nor, to be more complete:\n\n```css\n:target, .\\:target {\n  background-color: whitesmoke;\n}\n```\n\n\u003c/details\u003e\n\n### Style and Script Scoping\n\nWe often need a way to keep component-specific style sheets and scripts [scoped to a component](https://vuejs.org/guide/scaling-up/sfc.html). **This is especially crucial to \"page components\" in an SPA architecture.**\n\nHere, we get a new `scoped` attribute that lets us do just that:\n\n```html\n\u003cdiv\u003e\n\n  \u003cstyle scoped\u003e\n    :scope { color: red }\n  \u003c/style\u003e\n\n  \u003cscript scoped\u003e\n    console.log(this) // div\n  \u003c/script\u003e\n\n\u003c/div\u003e\n```\n\nAnd the special namespace-aware ID selector is supported from within scoped style sheets:\n\n```html\n\u003cdiv namespace\u003e\n  \u003ca id=\"url\" href=\"https://example.org\"\u003e\n    \u003cspan id=\"name\"\u003eJoe Bloggs\u003c/span\u003e\n  \u003c/a\u003e\n  \u003ca id=\"email\" href=\"mailto:joebloggs@example.com\" \u003ejoebloggs@example.com\u003c/a\u003e\n\n  \u003cstyle scoped\u003e\n    #\\~name { color: red }\n  \u003c/style\u003e\n\u003c/div\u003e\n```\n\nAnd everything comes with a complementary low-level API that exposes said assets to tools:\n\n```js\nlet { styleSheets, scripts } = user; // APIs that are analogous to the document.styleSheets, document.scripts properties\n```\n\n\u003cdetails\u003e\u003csummary\u003eLearn more\u003c/summary\u003e\n\nHere, the `scoped` attribute has two effects on the `\u003cscript\u003e` element:\n\n+ The `this` keyword is implicitly bound to the script's host element\n+ The `\u003cscript\u003e` element is (re)executed on each re-insertion into the DOM\n\n\u003c/details\u003e\n\n## HTML Imports\n\nHTML Imports is a realtime *import* system for HTML that's drawn entirely on HTML - and which addresses a different pain point in comparison to [the abandoned `\u003clink type=\"import\"\u003e` feature](https://www.w3.org/TR/html-imports/) and the [HTML Modules proposal](https://github.com/WICG/webcomponents/blob/gh-pages/proposals/html-modules-explainer.md)! **Something like it is the [`\u003cdefs\u003e`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs) and [`\u003cuse\u003e`](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/use) system in SVG.**\n\nHere, we get a way to both define and reuse a snippet out of *same* document:\n\n```html\n\u003chead\u003e\n\n  \u003ctemplate def=\"foo\"\u003e\n    \u003cdiv\u003e\u003c/div\u003e\n  \u003c/template\u003e\n\n\u003c/head\u003e\n\u003cbody\u003e\n\n  \u003cimport ref=\"foo\"\u003e\u003c/import\u003e\n\n\u003c/body\u003e\n```\n\n...while optionally supporting remote content without a change in paradigm:\n\n```html\n\u003chead\u003e\n\n  \u003ctemplate def=\"foo\" src=\"/foo.html\"\u003e\u003c/template\u003e\n\n\u003c/head\u003e\n\u003cbody\u003e\n\n  \u003cimport ref=\"foo\"\u003e\u003c/import\u003e\n  \n\u003c/body\u003e\n```\n\n\nOOHTML makes this possible in a simple new `def` attribute and a complementary new `\u003cimport\u003e` element!\n\n### Module Definition\n\nA \"module\" here is any piece of markup that can be reused.\n\nHere, we get the `def` attribute for defining those - both at the `\u003ctemplate\u003e` element level and at its direct children (*fragments*) level:\n\n```html\n\u003chead\u003e\n\n  \u003ctemplate def=\"foo\"\u003e\n    \u003cdiv def=\"fragment1\"\u003eA module fragment that can be accessed independently\u003c/div\u003e\n    \u003cdiv def=\"fragment2\"\u003eAnother module fragment that can be accessed independently\u003c/div\u003e\n    \u003cp\u003eAn element that isn't explicitly exposed.\u003c/p\u003e\n  \u003c/template\u003e\n\n\u003c/head\u003e\n```\n\n**--\u003e** *with module nesting for code organization*:\n\n```html\n\u003chead\u003e\n\n  \u003ctemplate def=\"foo\"\u003e\n    \u003cdiv def=\"fragment1\"\u003e\u003c/div\u003e\n\n    \u003ctemplate def=\"nested\"\u003e\n      \u003cdiv def=\"fragment2\"\u003e\u003c/div\u003e\n    \u003c/template\u003e\n  \u003c/template\u003e\n\n\u003c/head\u003e\n```\n\n### Remote Modules\n\nWe shouldn't need a different mechanism to work with remote content.\n\nHere, OOHTML extends the `\u003ctemplate\u003e` with an `src` attribute that lets us have self-loading `\u003ctemplate\u003e` elements:\n\n```html\n\u003ctemplate def=\"foo\" src=\"/foo.html\"\u003e\u003c/template\u003e\n\u003c!-- which links to the file below --\u003e\n```\n\n```html\n-- file: /foo.html --\n\u003cdiv def=\"fragment1\"\u003e\u003c/div\u003e\n\u003ctemplate def=\"nested\" src=\"/nested.html\"\u003e\u003c/template\u003e\n\u003c!-- which itself links to the file below --\u003e\n```\n\n```html\n-- file: /nested.html --\n\u003cdiv def=\"fragment2\"\u003e\u003c/div\u003e\n```\n\n**--\u003e** *which just draws on the existing semantics of `src` in elements like `\u003cimg\u003e`; terminating with either a `load` or an `error` event*:\n\n```js\nfoo.addEventListener('load', loadCallback);\nfoo.addEventListener('error', errorCallback);\n```\n\n### Declarative Module Imports\n\nHTML snippets should be reusable entirely out of HTML! So, we get an `\u003cimport\u003e` element that lets us do just that:\n\n```html\n\u003cbody\u003e\n  \u003cimport ref=\"/foo#fragment1\"\u003e\u003c/import\u003e \u003c!-- Pending resolution --\u003e\n  \u003cimport ref=\"/foo/nested#fragment2\"\u003e\u003c/import\u003e \u003c!-- Pending resolution --\u003e\n\u003c/body\u003e\n```\n\n```html\n\u003cbody\u003e\n  \u003cdiv def=\"fragment1\"\u003e\u003c/div\u003e \u003c!-- After resolution --\u003e\n  \u003cdiv def=\"fragment2\"\u003e\u003c/div\u003e \u003c!-- After resolution --\u003e\n\u003c/body\u003e\n```\n\n\u003cdetails\u003e\u003csummary\u003eAll in realtime\u003c/summary\u003e\n\nHere, import *refs* are live bindings that are sensitive to:\n\n+ changes in the *ref* itself (as to *refs* that are later defined/undefined/redefined)\n+ changes in the referenced *defs* themselves (as to these later becoming available/loaded/unavailable)\n\nAnd an `\u003cimport\u003e` element that has been resolved will self-restore in the event that:\n\n+ the above changes invalidate the reference.\n+ the previously slotted contents have *all* been programmatically removed and slot is empty.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eWith SSR support\u003c/summary\u003e\n\nOn the server, these `\u003cimport\u003e` elements will retain their place in the DOM, but this time, serialized into comment nodes, while having their output rendered just above them as siblings.\n\nThe above resolved imports would thus give us something like:\n\n```html\n\u003cbody\u003e\n  \u003cdiv def=\"fragment1\"\u003e\u003c/div\u003e\n  \u003c!--\u0026lt;import ref=\"/foo#fragment1\"\u0026gt;\u0026lt;/import\u0026gt;--\u003e\n  \u003cdiv def=\"fragment2\"\u003e\u003c/div\u003e\n  \u003c!--\u0026lt;import ref=\"/foo/nested#fragment2\"\u0026gt;\u0026lt;/import\u0026gt;--\u003e\n\u003c/body\u003e\n```\n\nBut they also will need to remember the exact imported nodes that they manage so as to be able to re-establish relevant relationships on getting to the client. This information is automatically encoded as part of the serialised element itself, in something like:\n\n```html\n\u003c!--\u0026lt;import ref=\"/foo/nested#fragment2\" nodecount=\"1\"\u0026gt;\u0026lt;/import\u0026gt;--\u003e\n```\n\nNow, on getting to the client and getting \"hydrated\" back into an `\u003cimport\u003e` element, that extra bit of information is decoded, and original relationships are formed again. But, the `\u003cimport\u003e` element itself stays invisible in the DOM while still continuing to kick as above!\n\n\u003e Note: We know we're on the server when `window.webqit.env === 'server'`. This flag is automatically set by OOHTML's current SSR engine: [OOHTML-SSR](https://github.com/webqit/oohtml-ssr)\n\n\u003c/details\u003e\n\n### Imperative Module Imports\n\nJavaScript applications will need more than a declarative import mechanism.\n\nHere, we get an *HTMLImports* API for imperative module import:\n\n```js\nconst moduleObject1 = document.import('/foo#fragment1');\nconsole.log(moduleObject1.value); // divElement\n```\n\n```js\nconst moduleObject2 = document.import('/foo/nested#fragment2');\nconsole.log(moduleObject2.value); // divElement\n```\n\n**--\u003e** *with the `moduleObject.value` property being a live property for when results are delivered asynchronously; e.g. in the case of remote modules*:\n\n```js\nObserver.observe(moduleObject2, 'value', e =\u003e {\n    console.log(e.value); // divElement\n});\n```\n\n**--\u003e** *with an equivalent `callback` option on the `import()` API itself*:\n\n```js\ndocument.import('/foo#fragment1', divElement =\u003e {\n    console.log(divElement);\n});\n```\n\n**--\u003e** *with an optional `live` parameter for staying subscribed to live results*:\n\n```js\nconst moduleObject2 = document.import('/foo/nested#fragment2', true/*live*/);\nconsole.log(moduleObject2.value);\nObserver.observe(moduleObject2, 'value', e =\u003e {\n    console.log(e.value);\n});\n```\n\n```js\ndocument.import('/foo#fragment1', true/*live*/, divElement =\u003e {\n    console.log(divElement); // To be received after remote module has been loaded\n});\n```\n\n*...both of which get notified on doing something like the below*:\n\n```js\ndocument.querySelector('template[def=\"foo\"]').content.firstElementChild.remove();\n```\n\n**--\u003e** *with a `moduleObject.abort()` method for unsubscribing from live updates*:\n\n**--\u003e** *with an optional `signal` parameter for passing in a custom `AbortSignal` instance*:\n\n```js\nconst abortController = new AbortController;\nconst moduleObject2 = document.import('/foo/nested#fragment2', { live: true, signal: abortController.signal });\n```\n\n```js\nsetTimeout(() =\u003e {\n  abortController.abort(); // which would also call moduleObject2.abort()\n}, 1000);\n```\n\n\u003c!--\u003cdetails\u003e\u003csummary\u003eExtended Imports concepts\u003c/summary\u003e--\u003e\n\n### Lazy-Loading Modules\n\nWe should be able to defer module loading until we really need them.\n\nHere, we get the `loading=\"lazy\"` directive for that; and loading is only then triggered on the first attempt to import those or their contents:\n\n```html\n\u003c!-- Loading doesn't happen until the first time this is being accessed --\u003e\n\u003ctemplate def=\"foo\" src=\"/foo.html\" loading=\"lazy\"\u003e\u003c/template\u003e\n```\n\n```html\n\u003cbody\u003e\n  \u003cimport ref=\"/foo#fragment1\"\u003e\u003c/import\u003e \u003c!-- Triggers module loading and resolves on load success --\u003e\n\u003c/body\u003e\n```\n```js\nconst moduleObject2 = document.import('/foo#fragment1'); // Triggers module loading and resolves at moduleObject2.value on load success\n```\n\n### Module Inheritance\n\nWe'll often have repeating markup structures across component layouts.\n\nHere, we get module nesting with inheritance to facilitate more reusability:\n\n```html\n\u003ctemplate def=\"foo\"\u003e\n\n  \u003cheader def=\"header\"\u003e\u003c/header\u003e\n  \u003cfooter def=\"footer\"\u003e\u003c/footer\u003e\n\n  \u003ctemplate def=\"nested1\" inherits=\"header footer\"\u003e \u003c!-- Using the \"inherits\" attribute --\u003e\n    \u003cmain def=\"main\"\u003e\u003c/main\u003e\n  \u003c/template\u003e\n\n  \u003ctemplate def=\"nested2\" inherits=\"header footer\"\u003e \u003c!-- Using the \"inherits\" attribute --\u003e\n    \u003cmain def=\"main\"\u003e\u003c/main\u003e\n  \u003c/template\u003e\n\n\u003c/template\u003e\n```\n\n```html\n\u003ctemplate def=\"foo\"\u003e\n\n  \u003ctemplate def=\"common\"\u003e\n    \u003cheader def=\"header\"\u003e\u003c/header\u003e\n    \u003cfooter def=\"footer\"\u003e\u003c/footer\u003e\n  \u003c/template\u003e\n\n  \u003ctemplate def=\"nested1\" extends=\"common\"\u003e \u003c!-- Using the \"extends\" attribute --\u003e\n    \u003cmain def=\"main\"\u003e\u003c/main\u003e\n  \u003c/template\u003e\n\n  \u003ctemplate def=\"nested2\" extends=\"common\"\u003e \u003c!-- Using the \"extends\" attribute --\u003e\n    \u003cmain def=\"main\"\u003e\u003c/main\u003e\n  \u003c/template\u003e\n\n\u003c/template\u003e\n```\n\n```html\n\u003cbody\u003e\n  \u003cimport ref=\"/foo/nested1#header\"\u003e\u003c/import\u003e\n\u003c/body\u003e\n```\n\n### Imports Contexts\n\nWe should be able to have *relative* import refs that resolve against local contexts in the document tree.\n\nHere, we call these \"Imports Contexts\", and these could be:\n\n+ Simple Base Path Contexts ([below](#base-path-contexts))\n+ Scoped Module Contexts ([below](#scoped-module-contexts))\n+ Named Contexts ([below](#named-contexts))\n+ Extended Scoped Module Contexts ([below](#extended-scoped-module-contexts))\n\nAnd to facilitate working with contexts, we also get an `Element.prototype.import()` API that is context-aware.\n\n#### \"Base Path\" Contexts\n\nBase paths may be defined at arbitrary levels in the page using the `importscontext` attribute:\n\n```html\n\u003cbody importscontext=\"/foo\"\u003e\n  \u003csection\u003e\n    \u003cimport ref=\"#fragment1\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolving to: /foo#fragment1 --\u003e\n  \u003c/section\u003e\n\u003c/body\u003e\n```\n\n```html\n\u003cbody importscontext=\"/foo/nested\"\u003e\n  \u003cmain\u003e\n    \u003cimport ref=\"#fragment2\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolving to: /foo/nested#fragment2 --\u003e\n  \u003c/main\u003e\n\u003c/body\u003e\n```\n\n**--\u003e** *with said base paths being able to \"nest\" nicely*:\n\n```html\n\u003cbody importscontext=\"/foo\"\u003e\n\n  \u003csection\u003e\n    \u003cimport ref=\"#fragment1\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolves to: /foo#fragment1 --\u003e\n  \u003c/section\u003e\n\n  \u003cdiv importscontext=\"nested\"\u003e \u003c!-- Relative path (beginning without a slash), resolves to: /foo/nested --\u003e\n    \n    \u003cmain\u003e\n      \u003cimport ref=\"#fragment2\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolves to: /foo/nested#fragment2 --\u003e\n    \u003c/main\u003e\n\n  \u003c/div\u003e\n\n\u003c/body\u003e\n```\n\n**--\u003e** *with the `Element.prototype.import()` API for equivalent context-based imports*:\n\n```js\n// Using the HTMLImports API to import from context\nconst contextElement = document.querySelector('section');\nconst response = contextElement.import('#fragment1'); // Relative path (beginning without a slash), resolving to: /foo#fragment1\n```\n\n```js\n// Using the HTMLImports API to import from context\nconst contextElement = document.querySelector('main');\nconst response = contextElement.import('#fragment2'); // Relative path (beginning without a slash), resolving to: /foo/nested#fragment2\n```\n\n#### \"Scoped Module\" Contexts\n\nSome modules will only be relevant within a specific context in the page, and those wouldn't need to have a business with the global scope.\n\nHere, we get the `scoped` attribute for scoping those to their respective hosts, to give us an *object-scoped* module system (like what Scoped Registries seek to be to Custom Elements):\n\n```html\n\u003csection\u003e \u003c!-- Host object --\u003e\n\n  \u003ctemplate def=\"foo\" scoped\u003e \u003c!-- Scoped to host object and not available globally --\u003e\n    \u003cdiv def=\"fragment1\"\u003e\u003c/div\u003e\n  \u003c/template\u003e\n\n  \u003cdiv\u003e\n    \u003cimport ref=\"foo#fragment1\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolving to the local module: foo#fragment1 --\u003e\n    \u003cimport ref=\"/foo#fragment1\"\u003e\u003c/import\u003e \u003c!-- Absolute path, resolving to the global module: /foo#fragment1 --\u003e\n  \u003c/div\u003e\n\n\u003c/section\u003e\n```\n\n**--\u003e** *with the `Element.prototype.import()` API for equivalent context-based imports*:\n\n```js\n// Using the HTMLImports API for local import\nconst contextElement = document.querySelector('div');\nconst localModule = moduleHost.import('foo#fragment1'); // Relative path (beginning without a slash), resolving to the local module: foo#fragment1\n```\n\n```js\n// Using the HTMLImports API for global import\nconst contextElement = document.querySelector('div');\nconst globalModule = contextElement.import('/foo#fragment1'); // Absolute path, resolving to the global module: /foo#fragment1 \n```\n\n#### Named Contexts\n\nImports Contexts may be named for direct referencing:\n\n```html\n\u003cbody contextname=\"context1\" importscontext=\"/foo/nested\"\u003e\n\n  \u003cimport ref=\"#fragment2\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolves to: /foo/nested#fragment2 --\u003e\n\n  \u003csection importscontext=\"/foo\"\u003e\n    \u003cimport ref=\"#fragment1\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolves to: /foo#fragment1 --\u003e\n\n    \u003cdiv\u003e\n      \u003cimport ref=\"@context1#fragment2\"\u003e\u003c/import\u003e \u003c!-- Context-relative path (beginning with a context name), resolves to: /foo/nested#fragment2 --\u003e\n    \u003c/div\u003e\n\n  \u003c/section\u003e\n\n\u003c/body\u003e\n```\n\n**--\u003e** *with the `Element.prototype.import()` API for equivalent context-based imports*:\n\n```js\n// Using the HTMLImports API to import from a named Imports Context\nconst contextElement = document.querySelector('div');\nconst result = contextElement.import('@context1#fragment2'); // Resolving to the module:/foo/nested#fragment2\n```\n\n#### Extended Scoped Module Contexts\n\nScoped Module Contexts may also have a Base Path Context that they inherit from:\n\n```html\n\u003cbody contextname=\"context1\" importscontext=\"/bar\"\u003e\n  \u003csection importscontext=\"nested\"\u003e \u003c!-- object with Scoped Modules, plus inherited context: /bar/nested --\u003e\n\n    \u003ctemplate def=\"foo\" scoped\u003e \u003c!-- Scoped to host object and not available globally --\u003e\n      \u003cdiv def=\"fragment1\"\u003e\u003c/div\u003e\n      \u003cdiv def=\"fragment2\"\u003e\u003c/div\u003e\n    \u003c/template\u003e\n\n    \u003cdiv\u003e\n      \u003cimport ref=\"foo#fragment2\"\u003e\u003c/import\u003e \u003c!-- Relative path (beginning without a slash), resolving to the local module: foo#fragment2, and if not found, the inherited module: /bar/nested/foo#2 --\u003e\n      \u003cimport ref=\"/foo#fragment1\"\u003e\u003c/import\u003e \u003c!-- Absolute path, resolving to the global module: /foo#fragment1 --\u003e\n      \u003cimport ref=\"@context1#fragment1\"\u003e\u003c/import\u003e \u003c!-- Relative path with a named context, resolving to the global module: /bar#fragment1 --\u003e\n    \u003c/div\u003e\n\n  \u003c/section\u003e\n\u003c/body\u003e\n```\n\n**--\u003e** *with the `Element.prototype.import()` API for equivalent context-based imports*:\n\n```js\n// Using the HTMLImports API\nconst contextElement = document.querySelector('div');\nconst result = contextElement.import('foo#fragment2'); // the local module: foo#fragment2, and if not found, the inherited module: /bar/nested#fragment2\n```\n\n\u003c!--\u003c/details\u003e--\u003e\n\n## Data Binding\n\nData binding is the idea of declaratively binding the UI to application data, wherein the relevant parts of the UI *automatically* update as application state changes.\n\nOOHTML makes this possible in just simple conventions - via a new comment-based data-binding syntax `\u003c?{ }?\u003e` and a complementary new `render` attribute!\n\nAnd for when we need to write extensive reactive logic on the UI, a perfect answer: Quantum Scripts!\n\n### Discrete Data-Binding\n\nHere, we get a comment-based data-binding syntax `\u003c?{ }?\u003e` (or `\u003c!--?{ }?--\u003e`), **which works as a regular HTML comment** but also as an insertion point for application data:\n\n```js\n\u003chtml\u003e\n  \u003chead\u003e\n    \u003ctitle\u003e\u003c/title\u003e\n  \u003c/head\u003e\n  \u003cbody\u003e\n    \u003chi\u003e\u003c?{ app.title }?\u003e\u003c/h1\u003e\n    Hi, I'm \u003c?{ name ?? 'Default name' }?\u003e!\n    and here's another way to write the same comment: \u003c!--?{ cool }?--\u003e\n  \u003c/body\u003e\n\u003c/html\u003e\n```\n\n\u003cdetails\u003e\u003csummary\u003eResolution details\u003c/summary\u003e\n\nHere, JavaScript references are resolved from the closest node up the document tree that exposes a corresponding *binding* on its Bindings API ([discussed below](#bindings-api)). For the above markup, our underlying data structure could be something like the below:\n\n```js\ndocument.bind({ name: 'James Boye', cool: '100%', app: { title: 'Demo App' } });\ndocument.body.bind({ name: 'John Doe' });\n```\n\n```js\ndocument: { name: 'James Boye', cool: '100%', app: { title: 'Demo App' } }\n └── html\n  ├── head\n  └── body: { name: 'John Doe' }\n```\n\nNow, the `name` reference remains bound to the `name` *binding* on the `\u003cbody\u003e` element until the meaning of \"closest node\" changes again:\n\n```js\ndelete document.body.bindings.name;\n```\n\nWhile the `cool` reference remains bound to the `cool` *binding* on the `document` node until the meaning of \"closest node\" changes again:\n\n```js\ndocument.body.bindings.cool = '200%';\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eWith SSR support\u003c/summary\u003e\n\nOn the server, these data-binding tags will retain their place in the DOM while having their output rendered to their right in a text node.\n\nThe following expression: `\u003c?{ 'Hello World' }?\u003e` would thus give us: `\u003c?{ 'Hello World' }?\u003eHello World`.\n\nBut they also will need to remember the exact text node that they manage, so as to be able to re-establish relevant relationships on getting to the client. That information is automatically encoded as part of the declaration itself, and that brings us to having a typical server-rendered binding in the following form:\n\n```html\n\u003c?{ 'Hello World'; [=11] }?\u003eHello World\n```\n\nNow, on getting to the client, that extra bit of information gets decoded, and original relationships are forned again. But the binding tag itself graciously disappears from the DOM, while the now \"hydrated\" text node continues to kick!\n\n\u003e Note: We know we're on the server when `window.webqit.env === 'server'`. This flag is automatically set by OOHTML's current SSR engine: [OOHTML-SSR](https://github.com/webqit/oohtml-ssr)\n\n\u003c/details\u003e\n\n### Inline Data-Binding\n\nFor attribute-based data binding, OOHTML deviates from the usual (and problematic) idea of bringing markup-style bindings into attribute texts: `title=\"Hello { titleValue }\"`, **as though attributes had the same semantics as markup**. Instead, we get a dedicated \"render\" attribute - `render` - for a nifty, key/value data-binding language:\n\n\u003e Note that in OOHTML \u003c= v3 the `render` attribute was `expr`.\n\n```html\n\u003cdiv render=\"\u003cdirective\u003e \u003cparam\u003e: \u003carg\u003e;\"\u003e\u003c/div\u003e\n```\n\n**--\u003e** *where*:\n\n+ *`\u003cdirective\u003e` is a directive, which is always a symbol*\n+ *`\u003cparam\u003e` is the parameter being bound, which could be a CSS property, class name, attribute name, Structural Directive - depending on the givin directive*\n+ *`\u003carg\u003e` is the bound value or expression*\n\n**--\u003e** *which would give us the following for a CSS property*:\n\n```html\n\u003cdiv render=\"\u0026color:someColor; \u0026backgroundColor:'red'\"\u003e\u003c/div\u003e\n```\n\n**--\u003e** *without being space-sensitive*:\n\n```html\n\u003cdiv render=\"\u0026 color:someColor; \u0026backgroundColor: 'red'\"\u003e\u003c/div\u003e\n```\n\n**--\u003e** *the rest of which can be seen below*:\n\n| Directive | Type | Usage |\n| :---- | :---- | :---- |\n| `\u0026`  | CSS Property | `\u003cdiv render=\"\u0026color:someColor; \u0026backgroundColor:someBgColor;\"\u003e\u003c/div\u003e` |\n| `%`  | Class Name | `\u003cdiv render=\"%active:app.isActive; %expanded:app.isExpanded;\"\u003e\u003c/div\u003e` |\n| `~`  | Attribute Name | `\u003ca render=\"~href:person.profileUrl+'#bio'; ~title:'Click me';\"\u003e\u003c/a\u003e` |\n|   | Boolean Attribute | `\u003ca render=\"~?required:formField.required; ~?aria-checked: formField.checked\"\u003e\u003c/a\u003e` |\n| `@`  | DOM Event | `\u003cdiv render=\"@click: this.methodCall(); @change: { state.prop1 = this.value };\"\u003e\u003c/div\u003e` |\n| `#`  | Structural Directive: | *See below* |\n| `#text`   | Plain text content | `\u003cspan render=\"#text:firstName+' '+lastName;\"\u003e\u003c/span\u003e` |\n| `#html`   | Markup content | `\u003cspan render=\"#html: '\u003ci\u003e'+firstName+'\u003c/i\u003e';\"\u003e\u003c/span\u003e` |\n|  `#items`  | A list, of the following format | `\u003cdeclaration\u003e \u003cof\\|in\u003e \u003citerable\u003e / \u003cimportRef\u003e`\u003cbr\u003e*See next two tables* |\n\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eFor ... Of\u003c/code\u003e Loops\u003c/summary\u003e\n\n|  Idea | Usage |\n| :---- | :---- |\n| A `for...of` loop over an array/iterable | `\u003cul render=\"#items: value of [1,2,3] / 'foo#fragment';\"\u003e\u003c/ul\u003e` |\n| Same as above but with a `key` declaration  | `\u003cul render=\"#items: (value,key) of [1,2,3] / 'foo#fragment';\"\u003e\u003c/ul\u003e` |\n| Same as above but with different variable names  | `\u003cul render=\"#items: (product,id) of store.products / 'foo#fragment';\"\u003e\u003c/ul\u003e` |\n| Same as above but with a dynamic `importRef`  | `\u003cul render=\"#items: (product,id) of store.products / store.importRef;\"\u003e\u003c/ul\u003e` |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003e\u003ccode\u003eFor ... In\u003c/code\u003e Loops\u003c/summary\u003e\n\n| Idea | Usage |\n| :---- | :---- |\n| A `for...in` loop over an object | `\u003cul render=\"#items: key in {a:1,b:2} / 'foo#fragment';\"\u003e\u003c/ul\u003e` |\n| Same as above but with a `value` and `index` declaration | `\u003cul render=\"#items: (key,value,index) in {a:1, b:2} / 'foo#fragment';\"\u003e\u003c/ul\u003e` |\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eResolution details\u003c/summary\u003e\n\nHere, JavaScript references are resolved from the closest node up the document tree that exposes a corresponding *binding* on its Bindings API ([discussed below](#bindings-api)). For the above CSS bindings, our underlying data structure could be something like the below:\n\n```js\ndocument.bind({ someColor: 'green', someBgColor: 'yellow' });\ndocument.body.bind({ someBgColor: 'silver' });\n```\n\n```js\ndocument: { someColor: 'green', someBgColor: 'yellow' }\n └── html\n  ├── head\n  └── body: { someBgColor: 'silver' }\n```\n\nNow, the `someBgColor` reference remains bound to the `someBgColor` *binding* on the `\u003cbody\u003e` element until the meaning of \"closest node\" changes again:\n\n```js\ndelete document.body.bindings.someBgColor;\n```\n\nWhile the `someColor` reference remains bound to the `someColor` *binding* on the `document` node until the meaning of \"closest node\" changes again:\n\n```js\ndocument.body.bindings.someColor = 'brown';\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eAll in realtime\u003c/summary\u003e\n\nBindings are resolved in realtime! And in fact, for lists, in-place mutations - additions and removals - on the *iteratee* are automatically reflected on the UI!\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eWith SSR support\u003c/summary\u003e\n\nFor lists, generated item elements are automatically assigned a corresponding key with a `data-key` attribute! This helps in remapping generated item nodes to their corresponding entry in *iteratee* during a rerendering or during hydration.\n\n\u003c/details\u003e\n\n### Quantum Scripts\n\nWe often still need to write more serious reactive logic on the UI than a declarative data-binding language can provide for. But we shouldn't need to reach for special tooling or some \"serious\" programming paradigm on top of JavaScript.\n\nHere, from the same `\u003cscript\u003e` element we already write, we get a direct upgrade path to reactive programming in just the addition of an attribute: `quantum` - for [Quantum Scripts](https://github.com/webqit/quantum-js):\n\n```html\n\u003cscript quantum\u003e\n  // Code here\n  console.log(this); // window\n\u003c/script\u003e\n```\n\n```html\n\u003cscript type=\"module\" quantum\u003e\n  // Code here\n  console.log(this); // undefined\n\u003c/script\u003e\n```\n\n**--\u003e** *which gives us fine-grained reactivity on top of literal JavaScript syntax; and which adds up really well with the `scoped` attribute for Single Page Applications*:\n\n```html\n\u003cmain\u003e\n\n  \u003cscript scoped quantum\u003e\n    // Code here\n    console.log(this); // main\n  \u003c/script\u003e\n\n\u003c/main\u003e\n```\n\n```html\n\u003cmain\u003e\n\n  \u003cscript type=\"module\" scoped quantum\u003e\n    // Code here\n    console.log(this); // main\n  \u003c/script\u003e\n\n\u003c/main\u003e\n```\n\n**--\u003e** *with content being whatever you normally would write in a `\u003cscript\u003e` element, minus the \"manual\" work for reactivity*:\n\n```html\n\u003cmain\u003e\n\n  \u003cscript type=\"module\" scoped quantum\u003e\n    import { someAPI } from 'some-module';\n\n    let clickCount = 0;\n    console.log(clickCount);\n    someAPI(clickCount);\n\n    this.addEventListener('click', e =\u003e clickCount++);\n  \u003c/script\u003e\n\n\u003c/main\u003e\n```\n\n**--\u003e** *within which dynamic application state/data, and even things like the Namespace API above, fit seamlessly*:\n\n```html\n\u003cmain namespace\u003e\n\n  \u003cscript scoped quantum\u003e\n    if (this.namespace.specialButton) {\n      console.log('specialButton present!');\n    } else {\n      console.log('specialButton not present!');\n    }\n    let specialButton = this.namespace.specialButton;\n    console.log(specialButton);\n  \u003c/script\u003e\n\n\u003c/main\u003e\n```\n\n```js\nconst main = document.querySelector('main');\nconst button = document.createElement('button');\nbutton.id = 'specialButton';\n\nconst addButton = () =\u003e {\n  main.appendChild(button);\n  setTimeout(removeButton, 5000);\n};\nconst removeButton = () =\u003e {\n  button.remove();\n  setTimeout(addButton, 5000);\n};\n```\n\n\u003cdetails\u003e\u003csummary\u003eLearn more\u003c/summary\u003e\n\nIt's Imperative Reactive Programming ([IRP](https://en.wikipedia.org/wiki/Reactive_programming#Imperative)) right there and it's the [Quantum](https://github.com/webqit/quantum-js) runtime extension to JavaScript!\n\nHere, the runtime executes your code in a special execution mode that gets literal JavaScript expressions to statically reflect changes. This makes a lot of things possible on the UI! The [Quantum JS](https://github.com/webqit/quantum-js) documentation has a detailed run down.\n\nNow, in each case above, reactivity terminates on script's removal from the DOM or via a programmatic approach:\n\n```js\nconst script = document.querySelector('script[quantum]');\n// const script = document.querySelector('main').scripts[0];\nscript.state.dispose();\n// which also happens on doing script.remove()\n```\n\nBut note that while said termination is automatic on script's removal, DOM event handlers bound via `addEventListener()` would still need to be terminated in their own way.\n\n\u003c/details\u003e\n\n## Data Plumbing\n\nComponents often need to manage, and be driven by, dynamic application state. That could get pretty problematic and messy if all of that should go on DOM nodes as direct properties:\n\n\u003cdetails\u003e\u003csummary\u003eExample\u003c/summary\u003e\n\n```js\n// Inside a custom element\nconnectedCallback() {\n  this.prop1 = 1;\n  this.prop2 = 2;\n  this.prop3 = 3;\n  this.style = 'tall-dark'; // ??? - conflict with the standard HTMLElement: style property\n}\n```\n\n```js\n// Outside the component\nconst node = document.querySelector('my-element');\nnode.prop1 = 1;\nnode.prop2 = 2;\nnode.prop3 = 3;\nnode.normalize = true; // ??? - conflict with the standard Node: normalize() method\n```\n\n\u003c/details\u003e\n\nThis calls for a decent API and some data-flow mechanism!\n\n### The Bindings API\n\nA place to maintain state need not be a complex state machine! Here, that comes as a simple, read/write, data object exposed on the document object and on DOM elements as a readonly `bindings` property. This is the Bindings API.\n\n**--\u003e** *it's an ordinary JavaScript object that can be read and mutated*:\n\n```js\n// Read\nconsole.log(document.bindings); // {}\n// Modify\ndocument.bindings.app = { title: 'Demo App' };\nconsole.log(document.bindings.app); // { title: 'Demo App' }\n```\n\n```js\nconst node = document.querySelector('div');\n// Read\nconsole.log(node.bindings); // {}\n// Modify\nnode.bindings.style = 'tall-dark';\nnode.bindings.normalize = true;\n```\n\n**--\u003e** *with a complementary `bind()` method that lets us make multiple mutations in one batch*:\n\n```js\n// ------------\n// Set multiple properties\ndocument.bind({ name: 'James Boye', cool: '100%', app: { title: 'Demo App' } });\n\n// ------------\n// Replace existing properties with a new set\ndocument.bind({ signedIn: false, hot: '100%' });\n// Inspect\nconsole.log(document.bindings); // { signedIn: false, hot: '100%' }\n\n// ------------\n// Merge a new set of properties with existing\ndocument.bind({ name: 'James Boye', cool: '100%' }, { merge: true });\n// Inspect\nconsole.log(document.bindings); // { signedIn: false, hot: '100%', name: 'James Boye', cool: '100%' }\n```\n\n**--\u003e** *which also provides an easy way to pass data down a component tree*:\n\n```js\n// Inside a custom element\nconnectedCallback() {\n  this.child1.bind(this.bindings.child1Data);\n  this.child2.bind(this.bindings.child2Data);\n}\n```\n\n**--\u003e** *and with the Observer API in the picture all the way for reactivity*:\n\n```js\nObserver.observe(document.bindings, mutations =\u003e {\n  mutations.forEach(mutation =\u003e console.log(mutation));\n});\n```\n\n```js\n// Inside a custom element\nconnectedCallback() {\n  Observer.observe(this.bindings, 'style', e =\u003e {\n    // Compunonent should magically change style\n    console.log(e.value);\n  });\n}\n```\n\n```js\nconst node = document.querySelector('my-element');\nnode.bindings.style = 'tall-dark';\n```\n\n\u003cdetails\u003e\u003csummary\u003eImplementation details\u003c/summary\u003e\n\nIn the current OOHTML implementation, the `document.bindings` and `Element.prototype.bindings` APIs are implemented as proxies over their actual bindings interface to enable some interface-level reactivity. This lets us have reactivity over literal property assignments and deletions on these interfaces:\n\n```js\nnode.bindings.style = 'tall-dark'; // Reactive assignment\ndelete node.bindings.style; // Reactive deletion\n```\n\nFor mutations at a deeper level to be reactive, the corresponding Observer API method would need to be used:\n\n```js\nObserver.set(document.bindings.app, 'title', 'Demo App!!!');\nObserver.deleteProperty(document.bindings.app, 'title');\n```\n\n\u003c/details\u003e\n\n### The Context API\n\nComponent trees on the typical UI often call for more than the normal \"top-down\" flow of data that the Bindings API facilitates. We still often require the ability to \"look up\" the component tree to directly access specific data, or in other words, get data from \"context\". This is where a Context API comes in.\n\nInterestingly, the Context API is the underlying \"resolution\" infrastructure for the Namespace API and the Data Binding and HTML Imports features in OOHTML!\n\nHere, we simply leverage the DOM's existing event system to fire a \"request\" event and let an arbitrary \"provider\" in context fulfill the request. This becomes very simple with the Context API which is exposed on the document object and on element instances as a readonly `contexts` property.\n\n**--\u003e** *with the `contexts.request()` method for firing requests*:\n\n```js\n// ------------\n// Get an arbitrary\nconst node = document.querySelector('my-element');\n\n// ------------\n// Prepare and fire request event\nconst requestParams = { kind: 'html-imports', detail: '/foo#fragment1' };\nconst response = node.contexts.request(requestParams);\n\n// ------------\n// Handle response\nconsole.log(response.value); // It works!\n```\n\n**--\u003e** *and the `contexts.attach()` and  `contexts.detach()` methods for attaching/detaching providers at arbitrary levels in the DOM tree*:\n\n```js\n// ------------\n// Define a CustomContext class\nclass FakeImportsContext extends DOMContext {\n  static kind = 'html-imports';\n  handle(event) {\n    console.log(event.detail); // '/foo#fragment1'\n    event.respondWith('It works!');\n  }\n}\n\n// ------------\n// Instantiate and attach to a node\nconst fakeImportsContext = new FakeImportsContext;\ndocument.contexts.attach(fakeImportsContext);\n\n// ------------\n// Detach anytime\ndocument.contexts.detach(fakeImportsContext);\n```\n\n\u003cdetails\u003e\u003csummary\u003eDetails\u003c/summary\u003e\n\nIn the current OOHTML implementation, the Context API interfaces are exposed via the global `webqit` object:\n\n```js\nconst { DOMContext, DOMContextRequestEvent, DOMContextResponse, DuplicateContextError } = window.webqit;\n```\n\nNow, by design...\n\n+ a provider will automatically adopt the `contextname`, if any, of its host element:\n\n    ```html\n    \u003cdiv contextname=\"context1\"\u003e\u003c/div\u003e\n    ```\n\n    ```js\n    // Instantiate and attach to a node\n    const host = document.querySelector('div');\n    const fakeImportsContext = new FakeImportsContext;\n    host.contexts.attach(fakeImportsContext);\n    // Inspect name\n    console.log(fakeImportsContext.name); // context1\n    ```\n\n    ...which a request could target:\n\n    ```js\n    const requestParams = { kind: FakeImportsContext.kind, targetContext: 'context1', detail: '/foo#fragment1' };\n    const response = node.contexts.request(requestParams);\n    ```\n\n+ and providers of same kind could be differentiated by an extra \"detail\" - an arbitrary value passed to the constructor:\n\n    ```js\n    const fakeImportsContext = new FakeImportsContext('lorem');\n    console.log(fakeImportsContext.detail); // lorem\n    ```\n\n+ and a provider could indicate to manually match requests where the defualt \"kind\" matching, and optional \"targetContext\" matching, don't suffice:\n\n    ```js\n    // Define a CustomContext class\n    class CustomContext extends DOMContext {\n      static kind = 'html-imports';\n      matchEvent(event) {\n        // The default request matching algorithm + \"detail\" matching\n        return super.matchEvent(event) \u0026\u0026 event.detail === this.detail;\n      }\n      handle(event) {\n        console.log(event.detail);\n        event.respondWith('It works!');\n      }\n    }\n    ```\n\n+ and a request could choose to stay subscribed to changes on the requested data; the request would simply add a `live` flag:\n\n    ```js\n    // Set the \"live\" flag\n    const requestParams = { kind: FakeImportsContext.kind, targetContext: 'context1', detail: '/foo#fragment1', live: true };\n    ```\n\n    ...then stay alert to said updates on the returned `DOMContextResponse` object or specify a callback function at request time:\n\n    ```js\n    // Handle response without a callback\n    const response = node.contexts.request(requestParams);\n    console.log(response.value); // It works!\n    Observer.observe(response, 'value', e =\u003e {\n      console.log(e.value); // It works live!\n    });\n    ```\n\n    ```js\n    // Handle response with a callback\n    node.contexts.request(requestParams, value =\u003e {\n      console.log(value);\n      // It works!\n      // It works live!\n    });\n    ```\n\n    ...while provider simply checks for the `event.live` flag and keep the updates flowing:\n\n    ```js\n    // Define a CustomContext class\n    class CustomContext extends DOMContext {\n      static kind = 'html-imports';\n      handle(event) {\n        event.respondWith('It works!');\n        if (event.live) {\n          setTimeout(() =\u003e {\n            event.respondWith('It works live!');\n          }, 5000);\n        }\n      }\n    }\n    ```\n\n    ...or optionally implement a `subscribed` and `unsubscribed` lifecycle hook for when a \"live\" event enters and leaves the instance:\n\n    ```js\n    // Define a CustomContext class\n    class CustomContext extends DOMContext {\n      static kind = 'html-imports';\n      subscribed(event) {\n        console.log(this.subscriptions.size); // 1\n      }\n      unsubscribed(event) {\n        console.log(this.subscriptions.size); // 0\n      }\n      handle(event) {\n        event.respondWith('It works!');\n        if (event.live) {\n          setTimeout(() =\u003e {\n            event.respondWith('It works live!');\n          }, 5000);\n        }\n      }\n    }\n    ```\n\n+ live requests are terminated via the returned `DOMContextResponse` object...\n\n    ```js\n    response.abort();\n    ```\n\n    ...or via an initially specified custom `AbortSignal`:\n\n    ```js\n    // Add a signal to the original request\n    const abortController = new AbortController;\n    const requestParams = { kind: FakeImportsContext.kind, targetContext: 'context1', detail: '/foo#fragment1', live: true, signal: abortController.signal };\n    ```\n\n    ```js\n    abortController.abort(); // Which also calls response.abort();\n    ```\n\n+ now, where a node in a provider's subtree is suddenly attached an identical provider, any live requests the super provider may be serving are automatically \"claimed\" by the sub provider:\n\n    ```js\n    document: // 'fake-provider' here\n    └── html\n      ├── head\n      └── body:  // 'fake-provider' here. Our request above is now served from here.\n    ```\n\n    And where the sub provider is suddenly detached from said node, any live requests it may have served are automatically hoisted back to super provider.\n\n    ```js\n    document: // 'fake-provider' here. Our request above is now served from here.\n    └── html\n      ├── head\n      └── body:\n    ```\n\n    While, in all, the requesting code is spared all of that \"admin\" work!\n\n\u003c/details\u003e\n\n**--\u003e** *all of which gives us a standardized API across context-based features in HTML - like HTMLImports and Data Binding*:\n\n```html\n\u003cdiv contextname=\"vendor1\"\u003e\n  \u003cdiv contextname=\"vendor2\"\u003e\n    ...\n\n      \u003cmy-element\u003e\n        \u003c!-- Declarative import --\u003e\n        \u003cimport ref=\"@vendor1/foo#fragment1\"\u003e\u003c/import\u003e\n        \u003c!-- Declarative Data Binding --\u003e\n        \u003c?{ @vendor2.app.title }?\u003e\n      \u003c/my-element\u003e\n\n    ...\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n```js\n// ------------\n// Equivalent import() approach\nconst response = myElement.import('@vendor1/foo#fragment1');\n\n// ------------\n// Equivalent Context API approach\nconst requestParams = { kind: 'html-imports', targetContext: 'vendor1', detail: 'foo#fragment1' };\nconst response = myElement.contexts.request(requestParams);\n\n// ------------\n// Handle response\nconsole.log(response.value);\n```\n\n```js\n// ------------\n// Context API request for bindings\nconst requestParams = { kind: 'bindings', targetContext: 'vendor2', detail: 'app' };\nconst response = myElement.contexts.request(requestParams);\n\n// ------------\n// Handle response\nconsole.log(response.value.title);\n```\n\n## Examples\n\nHere are a few examples in the wide range of use cases these features cover. While we'll demonstrate the most basic form of these scenarios, it takes roughly the same principles to build an intricate form and a highly interactive UI.\n\n\u003cdetails\u003e\u003csummary\u003eExample 1: \u003ci\u003eSingle Page Application\u003c/i\u003e\u003cbr\u003e\n└───────── \u003c/summary\u003e\n\nThe following is how something you could call a Single Page Application ([SPA](https://en.wikipedia.org/wiki/Single-page_application)) could be made - with zero tooling:\n\n**--\u003e** *First, two components that are themselves analogous to a Single File Component ([SFC](https://vuejs.org/guide/scaling-up/sfc.html))*:\n\n```html\n\u003ctemplate def=\"pages\"\u003e\n\n  \u003ctemplate def=\"layout\"\u003e\n    \u003cheader def=\"header\"\u003e\u003c/header\u003e\n    \u003cfooter def=\"footer\"\u003e\u003c/footer\u003e\n  \u003c/template\u003e\n\n  \u003c!-- Home Page --\u003e\n  \u003ctemplate def=\"home\" extends=\"layout\"\u003e\n    \u003cmain def=\"main\" namespace\u003e\n      \u003ch1 id=\"banner\"\u003eHome Page\u003c/h1\u003e\n      \u003ca id=\"cta\" href=\"#/products\"\u003eGo to Products\u003c/a\u003e\n      \u003ctemplate scoped\u003e\u003c/template\u003e\n      \u003cstyle scoped\u003e\u003c/style\u003e\n      \u003cscript scoped\u003e\u003c/script\u003e\n    \u003c/main\u003e\n  \u003c/template\u003e\n\n  \u003c!-- Products Page --\u003e\n  \u003ctemplate def=\"products\" extends=\"layout\"\u003e\n    \u003cmain def=\"main\" namespace\u003e\n      \u003ch1 id=\"banner\"\u003eProducts Page\u003c/h1\u003e\n      \u003ca id=\"cta\" href=\"#/home\"\u003eGo to Home\u003c/a\u003e\n      \u003ctemplate scoped\u003e\u003c/template\u003e\n      \u003cstyle scoped\u003e\u003c/style\u003e\n      \u003cscript scoped\u003e\u003c/script\u003e\n    \u003c/main\u003e\n  \u003c/template\u003e\n\n\u003c/template\u003e\n```\n\n**--\u003e** *Then a 2-line router that alternates the view based on the URL hash*:\n\n```html\n\u003cbody importscontext=\"/pages/home\"\u003e\n\n  \u003cimport ref=\"#header\"\u003e\u003c/import\u003e\n  \u003cimport ref=\"#main\"\u003e\u003c/import\u003e\n  \u003cimport ref=\"#footer\"\u003e\u003c/import\u003e\n  \n  \u003cscript\u003e\n  const route = () =\u003e { document.body.setAttribute('importscontext', '/pages' + location.hash.substring(1)); };\n  window.addEventListener('hashchange', route);\n  \u003c/script\u003e\n  \n\u003c/body\u003e\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eExample 2: \u003ci\u003eMulti-Level Namespacing\u003c/i\u003e\u003cbr\u003e\n└───────── \u003c/summary\u003e\n\nThe following is a Listbox component lifted directly from the [ARIA Authoring Practices Guide (APG)](https://www.w3.org/WAI/ARIA/apg/patterns/listbox/examples/listbox-grouped/#sc_label) but with IDs effectively \"contained\" at different levels within the component using the `namespace` attribute.\n\n```html\n\u003cdiv namespace class=\"listbox-area\"\u003e\n  \u003cdiv\u003e\n    \u003cspan id=\"ss_elem\" class=\"listbox-label\"\u003e\n      Choose your animal sidekick\n    \u003c/span\u003e\n    \u003cdiv id=\"ss_elem_list\"\n         tabindex=\"0\"\n         role=\"listbox\"\n         aria-labelledby=\"~ss_elem\"\u003e\n      \u003cul role=\"group\" namespace aria-labelledby=\"~cat\"\u003e\n        \u003cli role=\"presentation\" id=\"cat\"\u003e\n          Land\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_1\" role=\"option\"\u003e\n          Cat\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_2\" role=\"option\"\u003e\n          Dog\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_3\" role=\"option\"\u003e\n          Tiger\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_4\" role=\"option\"\u003e\n          Reindeer\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_5\" role=\"option\"\u003e\n          Raccoon\n        \u003c/li\u003e\n      \u003c/ul\u003e\n      \u003cul role=\"group\" namespace aria-labelledby=\"~cat\"\u003e\n        \u003cli role=\"presentation\" id=\"cat\"\u003e\n          Water\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_6\" role=\"option\"\u003e\n          Dolphin\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_7\" role=\"option\"\u003e\n          Flounder\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_8\" role=\"option\"\u003e\n          Eel\n        \u003c/li\u003e\n      \u003c/ul\u003e\n      \u003cul role=\"group\" namespace aria-labelledby=\"~cat\"\u003e\n        \u003cli role=\"presentation\" id=\"cat\"\u003e\n          Air\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_9\" role=\"option\"\u003e\n          Falcon\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_10\" role=\"option\"\u003e\n          Winged Horse\n        \u003c/li\u003e\n        \u003cli id=\"ss_elem_11\" role=\"option\"\u003e\n          Owl\n        \u003c/li\u003e\n      \u003c/ul\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eExample 3: \u003ci\u003eDynamic Shadow DOM\u003c/i\u003e\u003cbr\u003e\n└───────── \u003c/summary\u003e\n\nThe following is a custom element that derives its Shadow DOM from an imported `\u003ctenplate\u003e` element. The idea is to have different Shadow DOM layouts defined and let the \"usage\" context decide which variant is imported!\n\n**--\u003e** *First, two layout options defined for the Shadow DOM*:\n\n```html\n\u003ctemplate def=\"vendor1\"\u003e\n\n  \u003ctemplate def=\"components-layout1\"\u003e\n    \u003ctemplate def=\"magic-button\"\u003e\n      \u003cspan id=\"icon\"\u003e\u003c/span\u003e \u003cspan id=\"text\"\u003e\u003c/span\u003e\n    \u003c/template\u003e\n  \u003c/template\u003e\n\n  \u003ctemplate def=\"components-layout2\"\u003e\n    \u003ctemplate def=\"magic-button\"\u003e\n      \u003cspan id=\"text\"\u003e\u003c/span\u003e \u003cspan id=\"icon\"\u003e\u003c/span\u003e\n    \u003c/template\u003e\n  \u003c/template\u003e\n\n\u003c/template\u003e\n```\n\n**--\u003e** *Next, the Shadow DOM creation that imports its layout from context*:\n\n```js\ncustomElements.define('magic-button', class extends HTMLElement {\n  connectedCallback() {\n    const shadowRoot = this.attachShadow({ mode: 'open' });\n    this.import('@vendor1/magic-button', template =\u003e {\n      shadowRoot.appendChild( template.content.cloneNode(true) );\n    });\n  }\n});\n```\n\n**--\u003e** *Then, the part where we just drop the component in \"layout\" contexts*:\n\n```html\n\u003cdiv contextname=\"vendor1\" importscontext=\"/vendor1/components-layout1\"\u003e\n\n  \u003cmagic-button\u003e\u003c/magic-button\u003e\n\n  \u003caside contextname=\"vendor1\" importscontext=\"/vendor1/components-layout2\"\u003e\n    \u003cmagic-button\u003e\u003c/magic-button\u003e\n  \u003c/aside\u003e\n\n\u003c/div\u003e\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eExample 4: \u003ci\u003eDeclarative Lists\u003c/i\u003e\u003cbr\u003e\n└───────── \u003c/summary\u003e\n\nThe following is a hypothetical list page!\n\n```html\n\u003csection\u003e\n\n  \u003c!-- The \"items\" template --\u003e\n  \u003ctemplate def=\"item\" scoped\u003e\n    \u003cli\u003e\u003ca render=\"~href: '/animals#'+name;\"\u003e\u003c?{ index+': '+name }?\u003e\u003c/a\u003e\u003c/li\u003e\n  \u003c/template\u003e\n\n  \u003c!-- The loop --\u003e\n  \u003cul render=\"#items: (name,index) of ['dog','cat','ram'] / 'item';\"\u003e\u003c/ul\u003e\n\n\u003c/section\u003e\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eExample 5: \u003ci\u003eImperative Lists\u003c/i\u003e\u003cbr\u003e\n└───────── \u003c/summary\u003e\n\nThe following is much like the above, but imperative. Additions and removals on the data items are also statically reflected!\n\n```html\n\u003csection namespace\u003e\n\n  \u003c!-- The \"items\" template --\u003e\n  \u003ctemplate def=\"partials\" scoped\u003e\n    \u003cli def=\"item\"\u003e\u003c/li\u003e\n  \u003c/template\u003e\n\n  \u003c!-- The loop --\u003e\n  \u003cul id=\"list\"\u003e\u003c/ul\u003e\n\n  \u003cscript quantum scoped\u003e\n    // Import item template\n    let itemImport = this.import('partials#item');\n    let itemTemplate = itemImport.value;\n\n    // Iterate\n    let items = [ 'Item 1', 'Item 2', 'Item 3' ];\n    for (let entry of items) {\n      const currentItem = itemTemplate.cloneNode(true);\n      // Add to DOM\n      this.namespace.list.appendChild(currentItem);\n      // Remove from DOM whenever corresponding entry is removed\n      if (typeof entry === 'undefined') {\n        currentItem.remove();\n        continue;\n      }\n      // Render\n      currentItem.innerHTML = entry;\n    }\n\n    // Add a new entry\n    setTimeout(() =\u003e items.push('Item 4'), 1000);\n    // Remove an new entry\n    setTimeout(() =\u003e items.pop(), 2000);\n  \u003c/script\u003e\n\n\u003c/section\u003e\n```\n\n\u003c/details\u003e\n\n## Getting Involved\n\nAll forms of contributions are welcome at this time. For example, syntax and other implementation details are all up for discussion. Also, help is needed with more formal documentation. And here are specific links:\n\n+ [Project](https://github.com/webqit/oohtml)\n+ [Documentation](https://github.com/webqit/oohtml/wiki)\n+ [Discusions](https://github.com/webqit/oohtml/discussions)\n+ [Issues](https://github.com/webqit/oohtml/issues)\n\n## License\n\nMIT.\n\n[npm-version-src]: https://img.shields.io/npm/v/@webqit/oohtml?style=flat\u0026colorA=18181B\u0026colorB=F0DB4F\n[npm-version-href]: https://npmjs.com/package/@webqit/oohtml\n[npm-downloads-src]: https://img.shields.io/npm/dm/@webqit/oohtml?style=flat\u0026colorA=18181B\u0026colorB=F0DB4F\n[npm-downloads-href]: https://npmjs.com/package/@webqit/oohtml\n[bundle-src]: https://img.shields.io/bundlephobia/minzip/@webqit/oohtml?style=flat\u0026colorA=18181B\u0026colorB=F0DB4F\n[bundle-href]: https://bundlephobia.com/result?p=@webqit/oohtml\n[license-src]: https://img.shields.io/github/license/webqit/oohtml.svg?style=flat\u0026colorA=18181B\u0026colorB=F0DB4F\n[license-href]: https://github.com/webqit/oohtml/blob/master/LICENSE\n","funding_links":["https://github.com/sponsors/ox-harris","https://opencollective.com/webqit"],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebqit%2Foohtml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebqit%2Foohtml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebqit%2Foohtml/lists"}