Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial draft of an explainer conversation around Declarative Custom Elements #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Westbrook
Copy link
Owner

No description provided.

@Westbrook Westbrook force-pushed the draft-1 branch 2 times, most recently from 6cc02a9 to a3dd7d1 Compare April 22, 2022 15:16
@thescientist13
Copy link

thescientist13 commented Jun 12, 2022

Is this draft here meant to build off of this strawman @Westbrook , or is this draft meant to be understood in its own independent context? (and if does build off the strawman, maybe a link back to that spec?)

I only ask because it would be great to show some code samples here to illustrate the point of what sort of declarative outcome are we looking for, e.g. serializing event handling, updating / connecting state to DOM, or is it more generic than that, in just stamping out a Single File Component with the user entirely filling in the blanks and just the "linking" / loading functionality coming the browser?

<script>
  function hello() {
    alert("Hello");
  }
</script>

<style>
  h1{
    color: Daqua;
  }

  button {
    background-color: aquamarine;
  }
</style>

<h1>Hello Example</h1>
<button onclick="hello()"›Say Hello</button>
<!DOCTYPE html>
<html lang="en">
  <head>
    <import src="/wc-hello.html" />
    <title›Hello Example</title>
  <head>
  <body>
    <wc-hello></wc-hello>
  </body>
</html>

Perhaps with HTML Modules, we can leverage ESM so the incoming custom element can share / link it's scope, but hello would not be a global function?


I guess, how much can we realistically expect from a WC without JS, at least at runtime. I've actually been wondering, does a Declarative Shadow DOM (<template shadowroot="open">) work in a browser with JS disabled, since it's all just HTML? 🤔

I suppose though if actually wanted light DOM markup / content, you would just innerHTML in the first place for your custom element?

edit: I did a test and on this demo of mine where JavaScript is both eagerly loaded (the button in the header) and progressively loaded (the animated "slider" component at the bottom of the page). With JavaScript disabled, the button, via the Header custom element, and the animated slide component loaded via an IntersectionObserver on scroll, inlined via a <script> tag do not run, but the Declarative Shadow DOM on the page does work as the all the content and initial styles do display correctly (e.g. the header), I guess since it is all powered by HTML, e.g. <template shadowroot="open">.

So, I assume that was expected but I wasn't sure which way the wind would blow on that one, but was curious to know and figured I would leave that tidbit here for reference. Seems like an interested angle to pursue to get more HTML out of our custom elements.

@Westbrook
Copy link
Owner Author

@thescientist13 I'd not see that straw person, when I get back to this, I'll be sure to include it! Code examples also make sense. However, I get a lot of feedback from browsers that they don't want APIs, they want use cases, so in all the work I'm looking at in the spec'ing space, I'm trying to lean away from that, at least in public.

This specific PR became a conversation with myself, for the most part, and the conclusion was that I was addressing a handful of specs that would be best to address as such rather than a single "Declarative Custom Elements" spec. Further, I made a personal decision that "Declarative Web Components", likely the compendium of all the ideas herein, made sense as quite different than "Declarative Custom Element", in that a custom element doesn't need shadow DOM and other specs...but at the intersection of all the "Declarative" specs a web component might later be possible in a declarative fashion.

Roughly, the various specs that I think this involves come out to:

  • declarative templating
  • declarative custom elements
  • declarative web components
  • custom element/web component modules,
  • scoped registries, possibly powered by the above modules
  • and likely more
    The scope was too heavy, so while I want to get back to it, we'll see if/when that happens.

I've gotten specific excitement for #3, so I'm focusing on that first, as it's much higher on https://w3c.github.io/webcomponents-cg/ and much more likely to benefit all people in that the places 😉

@thescientist13
Copy link

Sounds good and thanks for the extra info!

However, I get a lot of feedback from browsers that they don't want APIs, they want use cases, so in all the work I'm looking at in the spec'ing space, I'm trying to lean away from that, at least in public.

For sure. For myself it was just hard to understand what the intended outcome was relative to a given input and was just trying to visualize what you had in mind. Like they say, a picture is worth a thousand words. 🖼️

I'll keep noodling on this topic in general then on the side if that's OK since I know there is a lot of ground to cover from our various standards docs and checklists and I have some personal motivation in this area. 👍


- non-JS developers being given the power of custom elements
- having custom element definitions available as parse time without requireing the jump over to the JS thread early in the document parse
- others?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaving the multithreading/hydration/rendering optimization to the browser as no JS engaged.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • enabling CMS to expose its content and templates as DCE

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • enabling static site builders without JS yet with rich set of components. Requires external template, which is not in proposal level yet.

- [adoptedStyleSheets](https://wicg.github.io/construct-stylesheets/#using-constructed-stylesheets)
- [aria delegation](https://leobalter.github.io/cross-root-aria-delegation/) (possibly implied but also not currently "spec", only proposal)
- [scoped registries](https://github.com/WICG/webcomponents/issues/716)
- others? see [current Web Components Community Group priorities](https://w3c.github.io/webcomponents-cg/)
Copy link

@sashafirsov sashafirsov Aug 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

listed features are needed for the concept of mature DCE libs, but even partial implementation of stack is quite powerful. The static site built purely with DCE is already there. In given sample DCE is expressed via external templates, but extending it to use custom element tags is just a syntax change.

To make the maturity level comparable to current JS stack still needed:

  • lib level scope (namespace) for CSS/JS/importmaps
  • scope definitions which would allow to override CSS internal rules. Do not confuse with complete "html inlude" proposal.
  • module loader. The DCE need ability to be loaded as module with all matching perks:
    • relative path to internally referenced resources. Otherwise all urls would be resolved relatively page baseURI
    • importmaps to be controlled by app AND sub-module, Current JS-centric implementation has a gap there.

Looking into future:

  • Declarative DAL/data island/Data binding. Including transformation of event source data to targets.
  • ability to insulate and override JS VM as in microapplication. Scoped registries and importmaps fits there naturally.

<import rel="customelement" href="my-element.html" tagname="my-element" />
<!-- ... -->
<my-element></my-element>
```

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how to emphasize it, external DCE along with modules resolution is a requirement for mature libs. Without it there is no competition with current JS stack.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "external" is not limited to URL. It could be the in-page reference. To make it valuable in complex encapsulation cases, a subject for scoping. I.e. reference shall be resolved in the "scope" accounting the namespace(s) and encapsulation.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t count elsewhere on the page as “external”. With server side tooling, you might not get “external” declarative custom elements in an initial draft, much like we didn’t with declarative shadow DOM. Where implementors draw the lines of shippable will not always be where we and consumers would.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are going away from server side tooling step by step. CDN became a host for many web components. Importmaps making the use of it. The client side caching and pre-compilation makes build time optimization obsolete. The next logical step is make externalized DCE module as a standard proposal.

This technique upgrades an existing element, `<template>`, to have the side effect of attaching a shadow root the parent element within which is lives. Would we benefit from following this style of approach when addressing inline API as it seems to build on the inert nature of the `<template>` tag to begin with? This might presuppose that instead of a `<customelement>` style registration we coudl leverag something along the lines of `<template custom-element="my-tag">` for these properties when addressing a new specification.

### Module boundaries and scope
When leveraging the JS module graph either as `import ...` or as `<scropt type="module">` we are provided a new scope in which the code available therein is separate from teh rest of the JS scope. Would it make sense to allow for a custom element registered via either via import mechanism or via attribute rules to have such a boundary? In this way we could allow for techniques like scoped registries to be available as if for free with the new scope being create at these boundaries by default...

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo; scropt

Any solution put forward here would benefit greatly by being paired as soon as possible with a bundler plug-in or polyfill that would make it possible for consumers to leverage the technique _today_. Previous attempts at larger scale quality of life improvements in this area have suffered greatly from low x-browser investment that has made developer exploration, let along developer adoption, of advances difficult, if not impossible. In the case that this tool the form of a polyfill, it would be important that the polyfill were small enough to inline within the `<head>` of a document in order to mitigate any potention FOUC.

### Is it possible to make components that are valuable to users with 0 JS?
An oft confused (or similarly highly important) topic when dicussing "declarative" APIs is "does it work with no JS?" and that is something that will come up often in any conversations here. If we bind this approach to a `<script>` tag, does that imply that the "declarative" API requires JS? Could a browser vendor speak to whether or not `<script>` is the boundary at which JS being turned off the parser turns back, or is it possible that `asserttype` would allow `customelement` content within a `<script>` tag to still be run in that context? IF that is not possible, then this may already start to shape the aboslutely possibilities of this addition and point us towards alternate choices. The `<template>` tag is certainly an option for inline techniques but we would still be lacking a graph mechanism by which we could build this code. Long term web component developers might lament the loss of HTML Imports in this case, and it might be worth revisiting that concept where actual 0 JS a requirment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we bind this approach to a <script> tag,

needs a sample or at least link to. It is unclear how SCRIPT tag would interact with DCE.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reality that I can to in this conversation with myself if that a declarative custom element and a declarative web component might be different things. Once you get not “declarative” and “web component” you are talking about a host of capabilities that may not be covered by declarative “custom element”. However, all cases seem to point to not having ANY <script> tags, which means you need to go all the way to declarative attributes, which puts a load of extra stress on a proposal here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants