The is="" attribute is confusing? Maybe we should encourage only ES6 class-based extension. #509

Closed
trusktr opened this Issue May 31, 2016 · 364 comments

Projects

None yet
@trusktr
trusktr commented May 31, 2016 edited

(copied from comment below): The is="" API can be confusing. For example (in current v0 API):

<my-el></my-el>
class MyEl extends HTMLElement { /*... */ }
MyEl.extends = 'div'
document.registerElement('my-el', MyEl)

// ...

document.querySelector('my-el') instanceof MyEl // true or false?

The spec says:

Trying to use a customized built-in element as an autonomous custom element will not work; that is, <plastic-button>Click me?</plastic-button> will simply create an HTMLElement with no special behaviour.

But, in my mind, that's just what the spec says, but not that it has to be that way. Why has it been decided for it to be that way?

I believe that we can specify this type of information in the customElement.define() call rather than in the markup. For example, that very same document shows this example:

customElements.define("plastic-button", PlasticButton, { extends: "button" });

Obviously, plastic-button extends button as defined right there in that call to define(), so why do we need a redundant is="" attribute to be applied onto button? I think the following HTML and JavaScript is much nicer:

<!-- before: <button is="plastic-button">Click me</button> -->
<plastic-button>Click me</plastic-button>
// before: const plasticButton = document.createElement("button", { is: "plastic-button" });
const plasticButton = document.createElement("plastic-button");

The necessary info for the HTML engine to upgrade that element properly is right there, in { extends: "button" }. I do believe there's some way to make this work (as there always is with software, because we make it, it is ours, we make software do what we want, and this is absolutely true without me having to read a single line of browser source code to know it), and that is="" is not required and can be completely removed from the spec because it seems like a hack to some limitation that can be solved somehow else (I don't know what that "somehow" is specifically, but I do know that the "somehow" exists because there's always some way to modify software to make it behave how we want within the limitations of current hardware where current hardware is not imposing any limitation on this feature).

@domenic
Contributor
domenic commented May 31, 2016

This was previously discussed at length in the other bug tracker, and it's explained in the spec in the sentence above that:

Customized built-in elements require a distinct syntax from autonomous custom elements because user agents and other software key off an element's local name in order to identify the element's semantics and behaviour. That is, the concept of customized built-in elements building on top of existing behaviour depends crucially on the extended elements retaining their original local name.

@trusktr
trusktr commented May 31, 2016 edited

@domenic That quote that you referred to makes me think exactly the same thing as I just wrote:

The necessary info for the HTML engine to upgrade that element properly is right there, in { extends: "button" }. I do believe there's some way to make this work (as there always is with software, because we make it, it is ours, we make software do what we want, and this is absolutely true without me having to read a single line of browser source code to know it), and that is="" is not required and can be completely removed from the spec because it seems like a hack to some limitation that can be solved somehow else (I don't know what that "somehow" is specifically, but I do know that the "somehow" exists because there's always some way to modify software to make it behave how we want within the limitations of current hardware where current hardware is not imposing any limitation on this feature).

You're pointing to something that exists in a spec, but I'm saying it doesn't have to be that way, specs can be modified. There is a solution (I don't know what that solution is specifically yet, but I know that the hardware on any computer that runs a browser nowadays isn't a limitation, and the only limitation is in the software we write, which can be modified). I simply can't understand why an HTML engine must need <button is="super-button"> (besides the fact that current algorithms require that) when clearly there's a JavaScript way to make the HTML engine understand that <super-button> means the same as <button is="super-button"> due to the fact we're defining that in the call to customElement.define.

I wish I had the time and resources to read the Chromium source in order to point to an actual solution (someone else can write the spec, as I'm not even good at reading those), but in the meantime, I'm 100% sure a backwards-compatible programmatic solution exists.

@domenic
Contributor
domenic commented May 31, 2016

Yes, everything is Turing machines and everything can be implemented. However, there are real-world constraints---both in implementation complexity and in ecosystem impact---that make it not desirable.

@trusktr
trusktr commented May 31, 2016 edited

Some things are complex to implement, but this particular change doesn't seem to be. :]

Would you mind kindly pointing to the complexity and impact that make it non-desirable?

Is it because if the element isn't registered (i.e. with JS turned off) that the browser won't know to at least render a fallback <button>? I think that's perfectly fine, because without JS the app probably won't work anyways, and I'm willing to bet that most people who will write JavaScript-based Custom Elements won't care if the app doesn't work with JS turned off. The Nike website doesn't work with JS turned off, and they care. Most people won't care. Developers who do care can just as easily use <noscript> and place a <button> in there, which makes much more semantic sense anyway.

What other reason might there be?

@trusktr
trusktr commented May 31, 2016 edited

When someone who comes from React tries to learn Custom Elements for the first time (which is more likely to happen than someone learning Custom Elements first due to the mere fact that specs are hard to read compared to things like React docs, unfortunately, because specs are meant for implementers, and the actual usage docs if any are sometimes limited or hard to find), they'll face these weird things like the redundant is="" form of extension and globally-registered custom elements that are not registered on a per-component basis.

This is what classes are for, and in the case of the HTML engine where multiple types of elements may share the same interface (which is probably a partial cause to any current problems) the third argument to customElements.define is there to clarify things. The is="" attribute is simply redundant and out of place from an outter API perspective (which may matter more than whatever extra implementation complexity there may be) because we already specify the extension in the define() call.

I'd take this further and propose that every single built in element should have a single unique associated class, and therefore ES2015 class extension would be the only required form of extension definition.

Just in case, let me point out we must currently specify an extension three whole times. For example, to extend a button:

class MyButton extends HTMLButtonElement {} // 1
customElements.define('my-button', MyButton, { extends: 'button' }) // 2
<button is="my-button"></button> <!-- 3 -->

That's three times we've needed to specify that we're extending something, just to extend one thing. Doesn't this strike you as a bad idea from an end-user perspective?

It should ideally just be this, assuming that there is a one-to-one relationship between built-in elements and JS classes:

class MyButton extends HTMLButtonElement {} // 1
customElements.define('my-button', MyButton)
<my-button></my-button>

I get what you're saying about complexities and real-world world constraints, but I think "breaking the web" might actually fix the web in the long run. There can be an API cleansing, and websites may have to specify that the new breaking-API is to be used by supplying an HTTP header. Previous behavior can be supported for a matter of years and finally dropped, the new API becoming default at that time. Sites that don't update within a matter of years probably aren't cared for anyways.

I'm just arguing for a better web overall, and breaking changes are sometimes necessary. It seems I may be arguing for this forever though. Unless I am an employee at a browser vendor, I'm not sure my end-user viewpoints matter much. The least I can do is share them.

@rniwa
Contributor
rniwa commented Jun 1, 2016 edited

The problem here is that UA internally checks local name e.g. element.localName == aTag to do various things, and all of that code needs to be updated to account for the fact there could be an intense of HTMLAnchorElement whose local name is not a.

Now I'm going to re-iterate that Apple objects to extending subclasses of HTMLElement using is= as currently spec'ed for various reasons we've stated in the past and this feature won't be supported in WebKit.

@treshugart treshugart referenced this issue in webcomponents/webcomponentsjs Jun 6, 2016
Closed

V1 custom elements - missing functionality #551

@trusktr
trusktr commented Jun 7, 2016

The problem here is that UA internally checks local name e.g. element.localName == aTag to do various things, and all of that code needs to be updated to account for the fact there could be an intense of HTMLAnchorElement whose local name is not a.

I think that relying on element tag names might be a bad idea, especially if we give users ability to scope elements on a per-shadow-root basis (now that's a good idea!). If we can allow end users of a custom element to assign any name they wish to that custom element used within the user's component (within the user's component's inner shadow tree), then we can avoid the global mess that window.customElements will be when an app gets large and when people widely adopt Web Components (wide adoption is one of the goals here).

In React (by contrast) the creator of a component never decides what the name of that component will be in the end user's inner tree. The end user has full control over the name of an imported component thanks to ES6 Modules. We can encourage a similar concept by introducing a per-shadow-root custom element registration feature.

If we can map names to classes without collision and without two names assigned to the same class (i.e. without elements like <q> and <blockquote> sharing the same class), then we should be able to use instanceof instead of checking tag names, and element inheritance can be based solely on ES6 class extension, as it should be (rather than having the extra is="" feature). The change that would be needed here would be to ensure that the native elements map to separate leaf classes so it's possible to tell a <q> element apart from a <blockquote> element with instanceof and therefore encouraging that sort of checking over tag names.

This API is still v0 in practice, so I think there's room for modification even if v1 is on the verge of coming out.

Apple objects to extending subclasses of HTMLElement using is=

I think Webkit not implementing is="" may be a great thing.

If we continue with globally registered elements, it will be inevitable that some two components in an app will have a name collision, and that the developer of that app will attempt to fix the problem by modifying the source of one custom element (possibly requiring forking of an NPM module, pushing to a new git repo, publishing a new module, etc, time consuming things) just to change the name of that element; it'd be a pain and can introduce unexpected errors if parts of the modified code are relying on the old tag names.

TLDR, if we put more care into the JavaScript aspects of an element (f.e. choosing which class represents an element, which is already happening in v1) then we'll have a more solid Web Component design, and we can drop is="". It will also require fixing things like the <q>/<blockquote> problem.

@trusktr
trusktr commented Jun 7, 2016

@domenic Can you describe the "ecosystem impact" that you might know of?

@domenic
Contributor
domenic commented Jun 7, 2016

I am referring to the various tools which key on local name, including JavaScript frameworks, HTML preprocessors and postprocessors, HTML conformance checkers, and so on.

@trusktr
trusktr commented Jun 7, 2016

I think I know what you mean. For example, search engines read the tag names from the markup in order to detect what type of content and how to render it in the search results. This point may be moot because today it completely possible to use a root <app> component with a closed shadow root. In this case a search engine might only ever see

<html>
    <head>
        <title>foo</title>
    </head>
    <body>
        <app></app>
    </body>
</html>

That's functionally equivalent to an app with no shadow roots and made entirely of randomly named elements:

<html>
    <head>
        <title>foo</title>
    </head>
    <body>
        <asf>
            <oiur>
                ...
            </oiur>
            <urvcc>
                ...
            </urvcc>
        </asf>
    </body>
</html>

Based on that, I don't think it's necessary to keep element names.

I imagine a couple remedies:

  1. Allowing both forms and let users decide which to use: <button is="awesome-button"> or <awesome-button> and let users decide which to use as they so wish.
  2. Allowing overriding of native elements (which pairs well with the idea of per-shadow-root element registrations as in "hey, let me define what a <p> element is within my component that has no paragraphs."). Then <button> could behave like <awesome-button>, and search engines or other tools would be able to receive the same semantic meaning. This idea only works if the elements are in Light DOM.
@domenic
Contributor
domenic commented Jun 7, 2016

Remedy 1 is what we have consensus on.

@rniwa
Contributor
rniwa commented Jun 7, 2016

I'll note that we've vocally and repeatedly objected to having is=, and in fact, stated publicly that we won't implement this feature, but somehow the WG kept it in the spec. I wouldn't call that a consensus. We extremely reluctantly agreed to keep it in the spec until it gets removed at risk later.

@Zambonifofex

Itโ€™s important to note that a lot of elements are implemented partially (or completely) with CSS. So, in order to support this and allow user agents to continue to implement elements like they do today, a new CSS pseudo-class would be needed: :subtypeof(button)

@chaals
Contributor
chaals commented Jun 11, 2016

a new CSS pseudo-class would be needed: :subtypeof(button)

Not really. The point of the is= approach is that since you have a button, that already matches CSS selectors for button. If you want to match a specific subtype you can do button[is=broken-button] โ€ฆ

@Zambonifofex

@chaals right. You would need the pseudo-class if using a custom element that extends a native button could be done like <awesome-button> instead of <button is="awesome-button">.

@Zambonifofex

Also, like @trusktr said, if this and whatwg/html#896 become a thing, I think itโ€™ll be possible to remove altogether the extends property from the options argument. We would then write customElements.define("awesome-button", class extends HTMLButtonElement{}, {}), which I really like.

Offering this as an alternative to the current way of defining extending native elements โ€” allowing user agent developers and authors to choose which they want to use โ€” is the best solution in my opinion. As @trusktr said, โ€œI think โ€˜breaking the webโ€™ might actually fix the web in the long runโ€.

@chaals
Contributor
chaals commented Jun 11, 2016

(@Zambonifofex it's generally not clear to me what you mean when you say "this", which makes it hard to engage)

As @trusktr said, โ€œI think โ€˜breaking the webโ€™ might actually fix the web in the long runโ€.

I've tried breaking the Web, at the turn of the century when it was smaller, to do something that would have been really useful. It failed. For pretty much the reasons given by people who say "you can't break the web".

Although user agent developers are less reluctant to break things than they were a decade ago, they're still very reluctant, and I believe with very good reason.

I think a strategy reliant on breaking the Web to fix it is generally a non-starter, even if the alternatives are far more painful.

@chaals
Contributor
chaals commented Jun 11, 2016

For what it's worth, I agree with @rniwa's characterisation - we have an agreement that we won't write is= out right now, but I don't see a strong consensus behind it. (Although as an individual I'm one of those who think it's pretty much indispensable to making this stuff work).

@Zambonifofex

@chaals

(@Zambonifofex it's generally not clear to me what you mean when you say "this", which makes it hard to engage)

When I say โ€œthisโ€ I mean โ€œthis issueโ€; the suggestion made by @trusktr in the first comment of this thread.

But, honestly, โ€” not that Iโ€™d be able to know, as Iโ€™ve never touched any browserโ€™s code โ€” I think that this would be a much easier change to make for user agent developers than you guys are making it out to be.

@Zambonifofex
Zambonifofex commented Jun 12, 2016 edited

I mean, sure, it could be slightly annoying to go and change all of the checks for the tag name to something else, but would it be actually hard?

@trusktr
trusktr commented Jul 2, 2016 edited

The is="" API can be confusing. For example (in current v0 API):

<my-el></my-el>
class MyEl extends HTMLElement { /*... */ }
MyEl.extends = 'div'
document.registerElement('my-el', MyEl)

// ...

document.querySelector('my-el') instanceof MyEl // true or false?
@domenic
Contributor
domenic commented Jul 2, 2016 edited

That API does not reflect the current custom elements API.

@trusktr
trusktr commented Jul 2, 2016 edited

We should make the result of instanceof be obvious. I think this could be better in v1 (without is="" and without options.extends):

<my-el></my-el>
class MyEl extends HTMLDivElement { /*... */ }
customElements.define('my-el', MyEl)

// ...

document.querySelector('my-el') instanceof MyEl // true!
@trusktr
trusktr commented Jul 2, 2016

I forgot this line too, in the previous comment:

document.querySelector('my-el') instanceof HTMLDivElement // also true!
@trusktr
trusktr commented Jul 2, 2016 edited

(@domenic I'm still using v0 in Chrome)

@trusktr
trusktr commented Jul 3, 2016 edited

@rniwa

there could be an intense of HTMLAnchorElement whose local name is not a.

I think you meant "instance" instead of "intense"? This seems to be the reason why is="" exists, making it possible to create new elements that extend from elements that inherit from the same class, but that possibly have new behavior added to them in their definitions along with differing nodeNames. This is also the reason for the {extends: "element-name"} (I am calling it options.extends), which effectively accomplishes the same thing. I feel like this may be an anti-pattern considering that we now have ES6 classes for describing extension.

I am against both of those methods of defining extension, as I believe encouraging ES6 Classes as the the tool for defining extension will reduce room for confusion.

@trusktr trusktr changed the title from Why must the is="" attribute exist? to The is="" attribute is confusing? Maybe we should encourage only ES6 class-based extension. Jul 3, 2016
@trusktr
trusktr commented Jul 3, 2016

Perhaps existing native elements should be re-worked so that any differences they have should rather be described (explained) by using class extension, and not using those other two methods (is="" and options.extends). An example of native elements that are defined with the same interface/class but with different nodeNames are q and blockquote which share the HTMLQuoteElement interface. We should attempt to describe the difference (if any) between these elements with class extension rather than is="" combined with options.extends. If there is no difference except for nodeName, then if they are both instanceof the same class that is fine too as long as the behavior for both elements is entirely defined in the shared class, and not by other means.

@rniwa
Contributor
rniwa commented Jul 5, 2016

FWIW, we're against subclassing subclasses of HTMLElement (e.g. HTMLInputElement, etc...) for various reasons, so WebKit isn't going to support this feature anyway. Extension of builtin elements are much better served with mixins.

@Zambonifofex

@rniwa if you could enumerate a couple of these โ€œvarious reasonsโ€ or link to some previous discussion on this subject that lead to this conclusion, itโ€™d be appreciated.

@bedeoverend

@rniwa I second @Zambonifofex, would love to know the rational behind this. In the case of needing features exclusive to native elements, how would someone use these features on a custom element without extending it?

An example my company is dealing with is replicating the sizing of a native img element, so far we haven't found any cross browser way to replicate the way it sizes, therefore having an element extension, so right now using is, is the only way to achieve this.

@Zambonifofex

@bedeoverend I donโ€™t think they are against extending native elements, they are simply against classes extending subclasses of HTMLElement. So you would still be able to extend native elements using the extends property of the customElements.define method. What would be illegal is the class passed to the method to extend a subclass of HTMLElement.

@rniwa
Contributor
rniwa commented Jul 6, 2016

We won't be supporting extends either.

One fundamental problem is that subclassing a subclass of HTMLInputElement or HTMLImageElement often leads to a violation of the Liskov substitution principle over time. Because they're builtin elements, they're very likely to be extended in the future. Imagine that we had this feature supported before type=date was added. Then your subclass of HTMLInputElement must also support type=date in order to satisfy the substitution principle. Similarly, imagine we had added this feature before srcset was added to HTMLImageElement and you wrote a subclass of HTMLImageElement. Then not supporting srcset results in the violation of the principle again.

In addition, none of the builtin elements are designed to be subclassed, and in fact, we don't have builtin subclasses of HTMLElement that are also builtins. This limits the usefulness of any sort of subclassing. Furthermore, we don't have any hooks for the processing models and internal states of builtin elements such as the dirtiness of HTMLImageElement's value and when and how HTMLInputElement picks the appropriate image.

Finally, the whole design of is= is a hack, and it would harm the long term health of the Web platform.

@trusktr
trusktr commented Jul 6, 2016 edited

FWIW, we're against subclassing subclasses of HTMLElement (e.g. HTMLInputElement, etc...) for various reasons, so WebKit isn't going to support this feature anyway. Extension of builtin elements are much better served with mixins.

One fundamental problem is that subclassing a subclass of HTMLInputElement or HTMLImageElement often leads to a violation of the Liskov substitution principle over time.

@rniwa True, which is why we should avoid subclassing when we can, but I think it's needed in order to fix the mistake that was made with q and blockquote. Otherwise, how does the web manifesto explain the difference between <q> and <blockquote>? I.e. How would the customElements.define() calls for q and blockquote differ in order to theoretically satisfy the web manifesto?

Maybe we would need to reserve HTMLQuoteElement for the q tag, and make a new HTMLBlockQuoteElement for the blockquote element, both of which extend from HTMLElement. I can see how that would be one way to satisfy the web manifesto and remain closer to Liskov's substitution principle.

@rniwa
Contributor
rniwa commented Jul 6, 2016 edited

Yeah, there has been a discussion about that for q and blockquote. A more likely consensus is to introduce two subclasses of HTMLQuoteElement, e.g. HTMLInlineQuoteElement and HTMLBlockQuoteElement and have q and blockquote each use it. It's a bit more hairly story for h1 through h6, which seems to require an introduction of six subclasses of HTMLHeadingElement from HTMLH1Element through HTMLH6Element.

@trusktr
trusktr commented Jul 6, 2016

I believe that would be totally fine along with agreement that subclassing in general is better avoided when possible. Nothing's perfect, but having those new subclasses for end-webdevs to extend from is already better than is=""+options.extends.

@domenic
Contributor
domenic commented Jul 6, 2016

having those new subclasses for end-webdevs to extend from is already better than is=""+options.extends.

While I can agree is="" is not perfect---perhaps even "a hack", although IMO a pretty reasonable one---I think this opinion is just wrong. Web devs and users both benefit greatly from the ability to extend built-in elements, and is="" is the most practical solution so far. That is why the consensus was to keep is="" in the spec and let implementations decide its fate: because it allows developers to write less code and get more correct behavior, and because it helps users---especially disabled users---interact with web pages in a more predictable and easy manner.

You can talk about how you dislike the technical aspects of is="" as a solution, but I think it's very unfair to say that omitting is="" is better for webdevs (or even "end-webdevs", although I'm not sure what those are).

@ebidel
ebidel commented Jul 6, 2016 edited

I've built web components for many years and talk with a lot of web developers regularly about them. I'd like to look at this question from their perspective. Devs don't care about implementation challenges or diving into the weeds.

We need to keep customized built-in elements. CE v1 is not a spec without a way to extend existing HTML elements. My talk at the Progressive Web App Summit highlights some of the reasons why it's important to keep:

  • is="" is 100% progressive enhancement!
  • Utilize built-in a11y features of the element. This is one of the primary reasons to keep it. I've seen far too many devs build custom elements that miss out on basic a11y...forget it altogether ๐Ÿ‘Ž.
  • More DRY. One gains native features for free (keyboard behavior, imperative API, and styling). Even recreating all the benefits of <button> requires way too much code.
  • Autonomous elements don't have the black magic that native elements have (e.g. creating an element that participates in <form> is painful). Same with extending other types of children.
  • Existing tools understand built-in elements
  • Existing CSS theming libraries work better with it
  • In Polymer, folks really love the extended helpers (<template is="dom-repeat">, <template is="dom-if">,`. They're easy to reason about, declarative, and simple to use. You know exactly what you're getting.
  • I talk to a lot of web developers. They don't mind is="".
  • No other component library gives you all ^ for free.

Whether is="" is the way to extend elements or not doesn't matter to much. But we definitely need a solution rather than no solution and currently, that's is="". Personally, I see nothing wrong with is="". It's worked great for the last couple of years in Chrome's v0 implementation. It's been implemented in a browser and proven. There may be edge cases with subclassing certain elements, but TBH, I haven't seen many (any?) developers run into them.

Ultimately, developers have to write less code with is="". That's huge. Extensions bring more reuse and keep best practices to our platform. Not less. Let's not remove such a useful feature.

@Zambonifofex
Zambonifofex commented Jul 6, 2016 edited

@domenic

Web devs and users both benefit greatly from the ability to extend built-in elements, and is="" is the most practical solution so far. That is why the consensus was to keep is="" in the spec and let implementations decide its fate: because it allows developers to write less code and get more correct behavior, and because it helps users---especially disabled users---interact with web pages in a more predictable and easy manner.

Thatโ€™d hopefully still be the case if is="custom-button" gets removed in favor of <custom-button>.

@rniwa
Contributor
rniwa commented Jul 6, 2016

I don't get why people keep making claims that is= improves accessibility. It simply doesn't except the very simple scenario in which the entire UI of the builtin form control is preserved (e.g. just adding JS methods).

In reality, a lot of custom form controls exist on the web for the sole purpose of customizing appearances against their builtin counterparts. Unfortunately, as soon as you've attached shadow root on a builtin element which is not even supported in shadow DOM v1, there is no accessibility benefit from using is= because UA can't determine how elements in a shadow tree corresponds to what UI actions without explicit annotations by the author.

@esprehn
esprehn commented Jul 6, 2016

is@ is critical for supporting reasonable AX for links. We tried to replicate the subtle focus and keyboard behavior of <a> with a custom element for quite a while before giving up and doing <a is="...">. Nesting a link inside an element breaks styling since my-link:visited etc. stop working.

I could be convinced that we don't need to allow subclassing input, but I think links are super important. Note also that developers have been using template with is@ very successfully over the past 3 years.

Fwiw we also hope to introduce a unique class per tagName, so we would add all six classes for headers etc. It makes the platform make much more sense. :)

@WebReflection

My 2 cents, FWIW, <a is=""></a> or <img is=""> confuses nobody about the intent, <shena-nigans></shena-nigans> is a complete wonder of what the heck is that tag about.

Crawlers, old and new users, browsers themselves before they load non blocking async info about the custom elements, just to name few that benefits from is

It also shipped 3 years ago and it worked de-facto pretty well on real-world production sites.

I'm not sure why this bug is still opened or still considered as something to be changed.
AFAIK not a single developer I've talked to said it was confusing (I also gave a talk about this)

@treshugart
treshugart commented Jul 13, 2016 edited

Whatever happens here, platform consistency should be considered highly important. If all browsers but WebKit support is, anyone with a valid use-case for using it will have to not use it, or remove Safari from their browser support matrix. There are good reasons for both sides of the argument, but I think there should be some compromise.

@WebReflection

WebKit works well through this polyfill of v0 that will eventually be upgraded to support v1 as soon as it's stable (I don't want to repeat the effort for something not final yet)

Best of all, you can IE8 or even IE5 this page and always see where's your business.
That's just a tiny demo of how powerful is the is attribute.

http://webreflection.github.io/document-register-element/test/examples/x-map.html

You can disable everything you want, you gonna see what the map is supposed to show anyway
( ok, not if you're using a text only browser ยฏ_(ใƒ„)_/ยฏ )

@WebReflection

@rniwa if it's been proved it works and scale well, I am not sure why WebKit would avoid it at all costs.

The result might be some nasty user-land overwrite/interception in order to make it work in there too (like a polyfill would do).

Moreover, the argument about violating the Liskov substitution principle doesn't feel appropriate for the Web environment. The entire global scope/context can be polluted (and it is) dozens of times by all libraries out there, with or without a namespace.

That doesn't prevent standard bodies to implement MyLibrary or fetch if that's an appropriate name for a new feature, isn't it?
Of course, modules partially solve this but polyfills will still do feature detections and pollute globally.

As summary: in a parallel universe where developers couldn't change the environment your point would be more than valid, but I think that's not really how the real-Web-world moved forward for the last 20 years.

If every other vendor agreed, please consider to follow this de-facto need and pragmatic solution for the sake of the Web, thank you.

@Zambonifofex

@WebReflection

I'm not sure why this bug is still opened or still considered as something to be changed.

Well, since noโ€one else seems to agree with me and @trusktr, I think Iโ€™m fine with this being closed. I still donโ€™t like is, but I can live with it.

@WebReflection
WebReflection commented Jul 14, 2016 edited

@Zambonifofex the DOM is old and not perfect, neither is the is attribute as solution. However, it solves everything every native HTMLElement has solved during the last 25 years without any need to reinvent the wheel. Moreover, it doesn't require O(n^2) amount of nodes (named custom elements plus eventually native links/input/whatever inside) and also it makes it possible to better integrate with the Web platform.

An example over every other, is the bloody tr that cannot be wrapped around a custom-tr element because it will break and table are still the best, semantic, accessible way to display tabular data.

TL;DR nobody likes is but whoever worked with it will admit is the most pragmatic, easy-peasy, cross platform friendly and working solution we have so that every developer moved forward building great stuff based on such attribute.

The previous x-img tag goes even further, using CSS like img[is=x-map], x-map {} to have common styles for before and after the upgrade which replaces the image with something else that has nothing to do with an image (it's a Leaflet canvas/iframe/different-world)

Why not closing this chapter and move forward then, since there are no equivalent solutions that either work or that have been even proposed?

So please, let's implement is and move forward the Web. Thank you!

@rniwa
Contributor
rniwa commented Jul 18, 2016

FWIW, we're going to iterate our opinion that we're not going to implement is attribute in WebKit.

@ebidel
ebidel commented Jul 18, 2016

That's very unfortunate.

@paulkinlan wrote a great piece on platform inconsistencies recently, "The Lumpy Web".

  • Platform inconsistencies hurt us more than big feature differences, we should start to try and prioritize aligning the platform
  • We need better tools to help us understand what the inconsistencies are and guidance on how to manage them
  • Developers should raise more issues to keep browser vendors accountable when there are differences

I hope this inconsistency doesn't become detrimental to the adoption of Custom elements.

@rniwa
Contributor
rniwa commented Jul 18, 2016

The thing is, Apple has been objecting to this feature from the get go, and the only reason it remains in the spec is because Google kept objecting to it being removed from the spec.

The fact of matter is, we only agreed to keep it in the spec to wait until the feature becomes at-risk at CR stage so that it can be removed.

It's extremely frustrating for you to then make arguments to implement this feature after the fact. We've had this discussion before, and nothing has changed. So why do you think keep making the same arguments would change anything?

@WebReflection

'cause we're all thinking, reasonable, people and Custom elements with is attribute have been already adopted and not only by Google and Chrome.

@ebidel
ebidel commented Jul 18, 2016 edited

It's extremely frustrating for you to then make arguments to implement this feature after the fact.

Sorry, I don't mean to minimize previous spec discussions. There are a ton of historical conversations that have taken place outside this bug...over many many years! It's hard to follow Webkit's full reasoning without that reasoning being documented here. Would be nice to have a summary on this bug.

I think what you're seeing now is feedback from the actual dev community. Web developers don't participate in spec discussions. Github bugs makes things more approachable.

@chaals
Contributor
chaals commented Jul 19, 2016

Feedback from stakeholders - developers, toolmakers, end users, etc - is valuable. I'm grateful that people have provided it in a constructive and polite manner, because attacking individuals isn't helpful.

There doesn't seem to be new information here. There are people who think is= is a bad idea, and people who think it is worthwhile. I think we should close the discussion, and let the W3C Process operate.

@rniwa isn't unique in opposing is=. He is a thoughtful intelligent person who disagrees with the apparent majority of the 10 participants in this discussion.

Apple is not unique as an organisation in opposing the attribute.

At the same time, there are many who think it is a good idea. Personally I agree with @WebReflection that it is of limited, but real value and we are better off having it than not. As chair, that doesn't mean I can impose it.

The attribute is in there for now, with supporters and detractors. Given the obvious lack of consensus to either keep or remove it, the W3C Process includes testing whether there is a likelihood of interoperable implementation which will probably boil down to looking at actual implementation. Nobody is obliged to implement, we will look at what the market does.

Apple (and others who share their dislike for is=) know how to suggest that something is removed from a specification on technical grounds, and have said clearly before that they don't intend to support this. Others have said they do.

The Web doesn't develop in lock step because it isn't imposed by a single actor, and overall that seems to be a strength. It is quite reasonable in a market for some players to decide not to implement something. It is unfortunate that this produces inconsistency at the bleeding edge, but it also gives us great power to let innovations come from anywhere instead of only market-dominating players being able to do it for us.

Our process enables this deliberately, for reasons beyond the above. One of them is to make sure our work is not illegal anti-competitive industry collusion. That's important to a lot of companies who are important in this area. Anyone who wants to go further down that topic, which is beyond the scope of the Working Group, can buy me a beer and lecture me or let me lecture them. But please, not here.

@chaals chaals closed this Jul 19, 2016
@zeitiger zeitiger referenced this issue in WebReflection/document-register-element Jul 21, 2016
Closed

Custom Elements v1 #58

@matthewp

An alternative to is="" could be custom attributes. @rniwa mentioned mixins and this would be a form of that (maybe you had something else in mind). I think it solves the issues that people on boths sides have, and could have a very similar API to custom elements. Something like:

class FooBarAttr {
  attachedCallback() {
    console.log('was created for first time');
  }

  changedCallback(newValue, oldValue) {
    console.log('it changed');
  }
}

customAttributes.define('foo-bar', FooBarAttr);

This would be super simple to polyfill with MutationObservers as well.

@seaneking seaneking referenced this issue in SimplaElements/simpla-img Sep 1, 2016
Open

Refactor, and extend native <img> #37

0 of 5 tasks complete
@EduardoRFS

@rniwa A solution to this element.localName == aTag is easily, hack that. Create internally two elements, linked in properties(css and javascript), is really hard to implement that? Ok performance is not excelent but is really more slow than actual "is" implementation? Perdon if this is bullshit

@Zambonifofex

@matthewp

If you havenโ€™t already, maybe you should create a new issue thread asking for this. It sounds like an excellent idea thatโ€™d get more attention if it was in its own thread.

@trusktr
trusktr commented Sep 10, 2016

@matthewp @Zambonifofex

I believe attributes should be on a per-custom-element basis, otherwise globally registered attributes will get messy quickly. Many custom elements may depend on values of attributes with the same name (I.e. name clashing can become a nasty problem).

In native HTML, style="" is common across many elements, if not all. This type of thing should happen through extension. If my custom element has special behavior based on a foo="" attribute, and you extend it to make your own custom element, then your element will inherit that attribute behavior. Likewise, we can explain the style attribute the same way due to the fact that custom elements can inherit it from HTMLElement (I think that is where style behavior is defined?).

@Zambonifofex

@trusktr

What about being able to define both global attributes and attributes on specific elements?

customAttributes.define("foo-bar", HTMLElement, FooBarAttr); // Global attribute
customAttributes.define("foo-baz", MyElement, FooBazAttr); // Elementโ€specific attribute

Still, I like to encourage the practice of pseudoโ€namespaces. That is, when writing a library, named, say, โ€œmy libraryโ€, instead of having a fancy-button element, have a my_library-fancy_button element. Similar thing with attributes.

@tomalec
tomalec commented Oct 16, 2016

I would like to put my small feedback as a web-developer and would like to add another point to @ebidel 's list why is is important for my team and our products (custom elements).

It simplifies and optimizes not just styling, accessibility but also parsing.

We've created a number of vanilla CEs that extends <template> (far away from Google, Polymer, and their templating magic). The most important thing here is the inertness of element, which we cannot implement by ourselves . Probably, we can get it by just extend HTMLTemplateElement but it still will not solve the problem completely.
Before element definition is (lazily) loaded <our-template>...</our-template> will render ....

Removal of is (or equivalent/Custom Attributes) will require CE users to write <our-template><template>...</template></our-template>. Which not only look redundant and counter-intuitive, require more code on CE user side, as well as on CE dev side (as mentioned above), but what's most important <our-template> will still take part in regular rendering (could get styled, etc.) until it's definition is loaded.

@WebReflection
WebReflection commented Oct 16, 2016 edited

This is just a reminder that my V1 polyfill forces is="native" feature in browsers that don't support it, and it uses it natively where available.

I think we, developers, will find a way to implement is="native" feature in a way or another; I just wish they (browser vendors) will stop pushing back instead of understanding its use cases that are simply or practically impossible to reproduce otherwise.

template, tr, body, and even html are just few examples of what we're missing as extending possibility for the whole Web platform, present and future.

@EduardoRFS

@tomalec or just <our-template></our-template> is not removal of is= but deprecate, like all other features on web. Actually polymer use template with <template is="dom-repeat">, if is= turn optional allow that <dom-repeat>

@richardkazuomiller

There's been a lot of argument here about why some people like is="" and others don't, but I'd like to hear constructive suggestions from the anti-is side of how we can extend custom elements without using is while preserving all of the functionality of the native element and compatibility with browsers that don't support custom elements at all.

Consider this custom element:

<a is="fancy-anchor" href="/something">Fancy Anchor</a>

If is="" isn't an option, I'm assuming that the element would look like this:

<fancy-anchor href="/something">Fancy Anchor</fancy-anchor>

If that's the case, how does one implement it so all of the following are true?

  • A screen reader can always recognize that it is a link to another page
  • Clicking on the link opens /something when JavaScript is disabled
  • fancy-anchors can be focused using the tab key in IE8
  • The script that defines fancy anchor can be loaded asynchronously
  • A search engine will be able to tell that there is a link to /something on that page.
@matthewp

@richardkazuomiller You have MutationObservers at your disposal, so you can mimic everything is gives you in normal JavaScript unless you depend on synchronous callbacks. So you don't need to create a <fancy-anchor> element but rather can use a data-fancy-anchor attribute on a normal anchor, use mutation observers to know when the element is connected/disconnected and when attributes change.

@richardkazuomiller

@matthewp That defeats the whole purpose of having custom elements and introduces a whole other set of issues. The whole point is that once a custom element is implemented it can be created anywhere and treated the same as any other element. If upgrading the <a> to a fancy anchor depends on a MutationObserver, that means they will never be upgraded until they're inserted into the observer's target. If we need it to be upgraded it before it's inserted into the DOM we need to call some other function every time we want to create a fancy anchor, which means more code that doesn't follow a standard, probably more dependencies, and we're back where we started.

We at least all agree that being able to create a subclass of a native element โ€“ with or without is= โ€“ is a good idea right?

@seaneking

@richardkazuomiller Webkit is opposed to subclassing native element subclasses outright, see comment from @rniwa above (#509 (comment))

@richardkazuomiller
richardkazuomiller commented Oct 27, 2016 edited

Oh, I misunderstood subclasses of native element subclasses to mean subclasses of user-defined subclasses. My mistake.

So I guess the answer to my (admittedly mostly rhetorical) questions really are "don't use custom elements". That's worse than I thought. In that case I'd like to rebut some of the points made by the anti-is side, from my point of view as a developer.

The is="" API can be confusing

I've never heard of anyone who found it confusing. The intent of it is clear. Besides, if we bikeshedded every confusing part of the web until everything was perfect we wouldn't have browsers at all.

subclassing ... often leads to a violation of the Liskov substitution principle

Things breaking because of an update to a superclass's implementation happens is a fact of life. It should be avoided wherever possible, but eliminating subclassing altogether is not the answer. The possibility of a hypothetical input type being added is not worth throwing away all the possible custom input types developers could be making. Don't throw the baby out with the bathwater

none of the builtin elements are designed to be subclassed

I can say from experience that whether they were designed for it or not, subclassing native elements works very well. While there may be limitations when extending inputs, for example, it's easy to work within those limitations.

I don't get why people keep making claims that is= improves accessibility. It simply doesn't except the very simple scenario in which the entire UI of the builtin form control is preserved (e.g. just adding JS methods).

I think you're assuming that preserving the builtin UI isn't exactly what a lot of devs are doing. Look at Polymer's iron-input. No crazy shadow DOM stuff, just key bindings and a validator but that alone is very powerful. I've extended HTMLInputElement in my own applications to build things that are very complex, but thanks to custom elements I can just add is="whatever-input" to another input so they are also portable.

One might suggest that instead of extending native elements, we should create some kind of wrapper or bind events when the document loads or something, but custom elements v1 works with elements created with document.createElement, appended to another element as HTML, rendered as the HTML in the first request streams in, or any other way elements get created, without requiring any extra JS. If WebKit decides not to implement is=, thereby making progressively enhanced native elements impossible and forcing developers to write more code, people are just going to keep using the polyfill.

I'm just a lowly webdev, so while I have opinions about the big-picture future-of-the-platform stuff, I'll leave that to you folks. I hope you'll consider my perspective when implementing (or not implementing) the spec.

@pete-otaqui

I would really like to have the ability to use the unreproducible features of native elements in custom ones. I don't really mind if that's through inheritance or some other "mixin" approach.

Beyond even accessibility, which to me seems to be the biggest reason to want this, there are things like <datalist> which (in browsers that support it, hint hint) will produce a dropdown menu that overflows the browser window. Clearly no (sane) web dev is going to attempt to rebuild that from the ground up. I would love to be able to extend <datalist> to have custom matching routines, for example. Of course, I'd also love it if the native element was in Webkit in the first place ;)

The problem with <datalist> is that it's really not extensible. The existing implementations aren't fabulous - but they are so close, and could be made amazing with just a few extra touches.

The same thing applies with the venerable <select> too - especially on mobile platforms. There are interactions there that are simply not possible with a purely custom element - and not even possible (or at least straightforward) with custom elements that wrap / utilise the native ones inside. The fact that we web devs can't simply use those powerful native capabilities without recreating them from scratch, or hacking around with composing them, is a real shame for the web.

As I said, I'd be fine with mixins instead of inheritance - has any effort been put into specifying that? Would it mean I could still get all the unreproducible behaviours, of let's say a <select> tag, and add my own implementation pieces?

@WebReflection

FWIW, since "yurak is working on this", I guess all we have to do is wait that Firefox and Edge would follow and keep polyfilling WebKit (hopefully not forever).

This is a page to check builtin extend status.

This is the same page using my polyfill.

@oleersoy
oleersoy commented Nov 2, 2016

Suppose I'm using for example <app-drawer> or <chat-app> in my app. At this point is there any point to me considering the is syntax?

I'm not trying to argue for or against it, just trying to understand the When it is of interest part better.

@tomalec
tomalec commented Nov 2, 2016

@oleersoy I don't think so. is is supposed to customize/extend built-in elements, so you could use their parsing, accessibility features, etc. even before your element is upgraded. For example: <input is="spaceship-coordinates">, <template is="enhanced-template">.

@oleersoy
oleersoy commented Nov 3, 2016 edited

So I just want to confirm that if I'm using <app-drawer then there is no point in using the capabilities of is because the <app-drawer> element is not something that is amenable to progressive enhancement?

In other words there is no point in doing is="spaceship-coordinates", because even though that part could fall back to a normal input field for browsers that don't understand what the is is for, the <app-drawer> element would completely break, so essentially the app would be an airplane with the wings missing?

@WebReflection

@oleersoy the is="enriched-element" has different use cases than <custom-element>. If you want to have exactly same native behaviour and extend it on top, you need the is attribute through the builtins extend way. There are no valid and universally compatible alternatives to this approach, so it's a matter of when rather than if these are needed.

template, th, tr, body, head, html are just few examples where you simply cannot use a custom tag with same/needed element inside because the result would be breaking for the surrounding HTML or the page itself.

a, button, input, iframe, form are, on the other hand, things well handled and known by browsers and bring in a lot of things automatically. In these cases you can wrap these native builtins around through redundant, not needed, verbose HTML, or create them at runtime (and once) on connectedCallback losing completely graceful enhancement.

A canvas-3d could be created with both approaches, but if you put a canvas inside a canvas-3d you are still in redundant-land but it's not such big deal since canvas is not much accessible
anyway. Everything else with builtins special meanings is problematic to reimplement.

Last, but not least, if you have a custom element that doesn't need to extend any special functionality beside what HTMLElement provides already, you'd go with the regular extend through the tag name and basic definition.

Most of the time, that's all you need but as you can see, developers can, and will, use Custom Elements in various ways.

I hope I've clarified most common use cases.

@richardkazuomiller

@WebReflection Those are some great examples (^_^)

@oleersoy To add to the previous comment, <app-drawer> wouldn't necessarily break in browsers that don't support custom elements if it's implemented in the right way. You should check out this video of how to make a progressively enhanced accordion custom element by the Chrome Dev team (more links below). Try looking at it (in Chrome) with and without JavaScript. It's just a demo so it doesn't go as far as checking for custom element support in browsers other than Chrome, but you can get the idea.

The reason an <app-drawer> doesn't need is="something" is because it doesn't need to fall back to a particular element type. When is= is not used, a custom element will just fall back to a plain HTMLElement and it will work, because all of the browsers will display an element with any tag name. Luckily, that's been in the spec since long before custom elements have been a thing and will work regardless of the fate of is=.

Chrome Developers Supercharged - Accordion
Source code from the video
The final product

@oleersoy
oleersoy commented Nov 4, 2016

So I'm trying to make my question really simple because I'd like a straightforward answer. If this cannot be answered in terms of yes or no please let me know why.

Again I'm asking whether the minute I add the Polymer <app-drawer opened></app-drawer> to my app, it effectively obsoletes previous work done to make a progressively enhanced app?

BTW - I'm saying Polymer specifically because I prefer not get into "Well if it was implemented this way theory". If we expend enough effort we can do anything. Just ask the Microsoft team that tried to integrate the browser into the desktop.

@richardkazuomiller

@oleersoy The approach I suggested will work with Polymer's app-drawer. Just use CSS to make the app-drawer show its contents before it's upgraded and remove those styles if Polymer is available. You can probably get more specific and helpful answers about a particular Polymer element if you open an issue on that element's repository.

@oleersoy
oleersoy commented Nov 4, 2016

@richardkazuomiller Thanks that seems reasonable. What if the <app-drawer> uses the shadow-dom - will it continue to render and work as expected, given that we override the css used to display the element initially? @rniwa IIUC seems to be saying that any custom element that uses the shadow dom will terminate the progressive enhancement capability afforded to us by is?

@rniwa
Contributor
rniwa commented Nov 4, 2016

If you're using an autonomous custom element (i.e. not using is attribute in your code), all of that is irrelevant. Regardless of whether app-drawer uses shadow DOM or not, it functions as expected.

@trusktr
trusktr commented Nov 5, 2016 edited

Regardless of whether app-drawer uses shadow DOM or not, it functions as expected.

Not necessarily true for custom elements in general. Try using ShadowDOM with the A-Frame Custom Elements that are available at http://aframe.io, and you'll see that they won't work as expected (jsfiddles). A-Frame (and any other Custom Element libraries used for constructing custom render trees) need to be able to construct an internal representation of the final flat tree which is the result of composed shadow trees, and then the internal representation of the flat tree can be used (for example) to render a scene in WebGL or Canvas 2D.

@rniwa
Contributor
rniwa commented Nov 5, 2016

Not necessarily true for custom elements in general. Try using ShadowDOM with the A-Frame Custom Elements that are available at http://aframe.io, and you'll see that they won't work as expected (jsfiddles).

That's pretty orthogonal to what we're discussing here. That's just a limitation on the current shadow DOM API.

@ebidel
ebidel commented Nov 5, 2016

@oleersoy Custom elements go through an upgrade process, which means PE is a built-in feature of the API. Consume components under the assumption that JS may never run. Then, sometime in the future JS does run, registers the elements. Boom. You're progressively enhancing that markup.

This article and my presentation the PWA summit earlier this year discusses the notion of "progressively enhanced markup". Video.

@oleersoy
oleersoy commented Nov 5, 2016 edited

@ebidel just saw your comment now. Huge fan of your articles! I'll amend my comment a bit in light of yours.

OK - Let me reboot my simple scenario and limit it to custom elements and javascript in general.

SIDE NOTE

My background and primary reason for looking at all the specs is that I think custom elements and the shadow dom are fantastic tools for simplifying my apps, and my gut feeling is that anytime I create an element that does something beyond just special effects, the app will break given that the custom element API is not supported / The element upgrade has not yet kicked in. I'll illustrate what I mean.

END SIDE NOTE

So suppose I wrote an app consisting of two custom elements <custom-broadcast> and <custom-receiver> that talk to each other. The <custom-broadcast> elements sends messages on a configurable attribute channel and <custom-receiver> receives them on a configurable attribute channel.

I could also have a FancyButton configured as <button is="fancy-button">Broadcast</button>. When I click the button it will tell the <custom-broadcast message="Cubs win!!!" channel="1"> element to start broadcasting Cubs win!! and the <custom-receiver channel="1"> will just log that to the console.

So I load this app in a browser that does not support custom elements or will not upgrade them for some reason. The FancyButton falls back to a normal not so fancy button, and when clicked nothing works.

So to me it seems as if I want an app that works well on all browsers, then I'm better off with a non custom element approach, but if I want to go bleeding edge and throw some users with dusty browsers under the bus then I would choose custom elements.

In other words I simply don't see what advantage is is offering?

@rniwa
Contributor
rniwa commented Nov 5, 2016 edited

Right, that was one of the arguments we (WebKit team) made to argue against is. Progressive enhancement based on is sounds nice in theory but in practice, any app that relies on JS / DOM "enhancements" made by customized builtin code would break.

Similarly, anytime a shadow root is attached on a builtin element, we can't simply assume the ARIA role of the underlying element. For example, imagine input's type=date didn't exist and we were building it as a customized builtin element. Then by attaching a shadow root on input (which is not even allowed in shadow DOM API at the moment), and introducing controls for changing months, etc... in the shadow tree, we're effectively rewriting the semantics that need to be communicated with the assistive technology. So, in practice, user agents would need to use the flat tree to construct the accessibility tree anyway except all but the simplest of the simplest case.

@richardkazuomiller
richardkazuomiller commented Nov 5, 2016 edited

If your app breaks because a certain API is not available, you're doing progressive enhancement wrong.

The argument that a feature doesn't have any advantages because it might break in old browsers could be made about literally any new browser feature and if we accepted that we'd never make anything new.

As for the shadow DOM stuff, I honestly don't think that has anything to do with is. Attaching a shadow root to a builtin element might introduce complexity, but as a few people have said already, there are many use cases for custom elements that don't have anything to do with shadow DOM. This has already been proven by the fact that custom elements are already being used in production when shadow DOM is still only in Chrome. Shadow DOM and custom elements are often used together, but discussions about the two should be kept separate.

@seaneking
seaneking commented Nov 5, 2016 edited

@oleersoy in that scenario no, fancy-button wouldn't offer progressive enhancement because you're not progressively enhancing a button, you're giving it core functionality that your app is broken without.

There are lots of good examples of progressive enhancement enabled by extended builtins (eg: iron-input mentioned above). An example from our own work - we're building a wc content management library, and by extending builtins we can render content to elements before upgrading with editing behaviours, and therefore support legacy browsers, pre-rendering, etc. Without extension this becomes infinitely harder.

Also prog enhancement is only one (admittedly very important) upside of type extension. Another is inheriting unreplicable native behaviours (eg: template, anchor, button, img, html, etc). We've found that the 'just wrap the element' hack often falls short (eg: wrapped templates existing in doc flow, losing 1:1 interop with native elements). Given, this could be provided with mixins rather than is, but then you lose the prog enhancement benefits.

@oleersoy
oleersoy commented Nov 5, 2016

If your app breaks because a certain API is not available, you're doing progressive enhancement wrong.

So how would I progressively enhance my very simple app the right way?

The argument that a feature doesn't have any advantages because it might break in old browsers could be made about literally any new browser feature and if we accepted that we'd never make anything new.

That's not the argument I'm making. The first thing I try to do when convincing someone that a feature has clear advantages in terms of:

  • Improving developer productivity
  • Improving code maintainability
  • Improving runtime efficiency and speed
  • Reducing delivery time
  • Improving user experience
  • And in general just making overall components of the solution simpler

Is to come up with a really simple example that shows how it does this across the board. I think custom elements, shadow dom, etc. all do this and they are complete no brainers. However I personally don't see a application development scenario where the is feature is like "YES!!!! - Hallujah finally we have this feature!!!".

I provided a very simple application scenario that illustrates my thinking. If @richardkazuomiller and @seaneking could come up with an equally simple scenario that illustrates what you are saying and causes us all to realize that the benefit of implementing is across browsers is a great thing, then that would be super helpful.

If I'm telling a team to consider progressive enhancement and specifically to use the is capability I need solid ammo, and right now I don't have any. In other words I cannot lead a team and say "If you see this scenario or this scenario or this scenario, then use the is capability" to do progressive enhancement. And by scenario I mean a simple example like the one I provided so that my team members have something concrete to go by / reference.

@oleersoy in that scenario no, fancy-button wouldn't offer progressive enhancement

I think the point of progressive enhancement is that it's progressive. From what @ebidel is saying there are two ways of looking at it. One is that the API for using a component is simply not there so that the component falls back to a more lightweight way of operating. It still works, just not with all the bells and whistles we would like. In the other scenario, the API / native capability is there but the the browser or script has not had a chance to upgrade the element yet.

So in this case it's not that the button is not offering PE. It offers it because of how it is declared <button is="fancy-button">.

because you're not progressively enhancing a button

That's true because that's up to the runtime (Although I have tried progressively enhancing a few things, but my wife always objects, so I've mostly given up).

you're giving it core functionality that your app is broken without.

I think what you are saying is precisely what I'm trying to illustrate. I have a button that can be progressively enhanced and two custom elements that form the entire app. If those custom elements don't work, the app is broken. So why then use custom elements at all? We are assuming that the is capability is generally going to be blended with the usage of custom elements right? Otherwise why have it in the v1 spec?

Also prog enhancement is only one (admittedly very important) upside of type extension. Another is inheriting unreplicable native behaviours (eg: template, anchor, button, img, html, etc).

This I totally agree with. I almost tattooed "Just wrap the element" on my forehead once, before getting more smarterer. I would love to see one example that uses custom elements in a minimal and realistic app that demonstrates how is is better than just extending and creating a <fancy-button> using a more minimal API that excludes the is capability.

Again if there is one way to do it, and we say that we can also do it this way, then there should be some significant advantage over the next 4 years to doing it both ways. Otherwise we are just introducing more stuff to learn about and make decisions with and possibly further complicate a already fairly advanced set of tools with a fairly steep learning curve that we use to produce awesome things and this does does not just waste our time, but the time of millions of developers, maintainers, product managers, and investors.

@seaneking

So how would I progressively enhance my very simple app the right way?

I think discussing that is out of the scope of this issue.

I provided a very simple application scenario that illustrates my thinking. If @richardkazuomiller and @seaneking could come up with an equally simple scenario that illustrates what you are saying and causes us all to realize that the benefit of implementing is across browsers is a great thing, then that would be super helpful.

See the example in my previous comment

@oleersoy
oleersoy commented Nov 6, 2016

I think discussing that is out of the scope of this issue.

Of coarse why would the practical application of the technology you are recommending be in the scope of the issue?

See the example in my previous comment

I have not seen a single example that makes sense in an application context. If you think that one component makes an application and progressively enhancing a single component in a vacuum is a great reason to ask millions of developers and product managers to understand this topic then good luck convincing Apple and MS. "Here guys this is going to useful to you 0.0000000001% if the time. Bon appetit!!".

@WebReflection
WebReflection commented Nov 7, 2016 edited

@oleersoy

So I load this app in a browser that does not support custom elements or will not upgrade them for some reason. The FancyButton falls back to a normal not so fancy button, and when clicked nothing works.

Your example, a specific use case that ignores all other already discussed in here, relies heavily on JS regardless the usage of the is attribute.

So, if your question is if you should use a polyfill or not, that covers also the is attribute like dre does, then you are the only one that can answer such question: are your target browsers already spec-compliants? Then don't, otherwise go agead and use a poly based on features detection 'till that day.

I have not seen a single example that makes sense in an application context.

This is a good old example from V0 era that shows just one of the huge amount of benefits of the is attribute. It's a cross map and it works down to IE8 and Android 2 or iOS 5 (and BB7, webOS, etc)

Somebody took that example saying "you could've just used a wrapper element" but that would be meaningless and redundant on the layout, and it might cause gotchas on IE8 side which is incompatible with randomly named elements (and CSS).

The curent polyfill now fallbacks to V0 but it brings in V1 as much as it can (there are parts of V1 that cannot be polyfilled these days) and your specific use case would be covered too.

Somebody went further away with the map element using layers and much more, still Custom Elements only: https://customelements.io/Maps4HTML/Web-Map-Custom-Element/

Last, but not least, I've used Custom Elements for years now and never together with ShadowDOM due greediness of the old polyfill with WeakMaps that were breaking all over.
That doesn't meen ShadowDOM is bad or anything, it's actually pretty amazing, but it's absolutely complementary with Custom Elements, not mandatory at all.

@oleersoy
oleersoy commented Nov 7, 2016 edited

relies heavily on JS regardless the usage of the is attribute.

So what is the minimum amount of that JS that you would like the broadcasting example to contain in order to make it work well with the isattribute?

So, if your question is if you should use a polyfill or not

Where in the simple broadcasting example I provided did I ask that?

This is a good old example from V0 era that shows just one of the huge amount of benefits of the is attribute. It's a cross map and it works down to IE8 and Android 2 or iOS 5 (and BB7, webOS, etc)

What's the benefit? Specifically what is the is attribute doing that if it were not present you could not do?

It's already a custom element x-map - so it has to be upgraded in order to work ... so how is the is attribute even relevant? It's supposed to be used on non custom elements like <button>, etc. right?)

Last, but not least, I've used Custom Elements for years now and never together with ShadowDOM due greediness of the old polyfill with WeakMaps that were breaking all over.
That doesn't meen ShadowDOM is bad or anything, it's actually pretty amazing, but it's absolutely complementary with Custom Elements, not mandatory at all.

I looked at your x-map repository and it's obvious that you are a very talented developer, so I'm really hoping that you can come up with something that overcomes our doubts about the value of the is attribute. If you can rearchitect the simple broadcasting example I provided to somehow work well and provide value using the is element according to some of the criteria I have outlined above that would be really great.

@WebReflection
WebReflection commented Nov 7, 2016 edited

your demo example does not work without JS and unless you have a live editable version of it I'm not sure what you are asking for but I have a counter question: how would you create a fancy-button without is?

The fact you don't consider all examples already described like template or even html does not mean these don't exist: it's you ignoring them and thinking only about your use case.

That one, I am afraid, I cannot fix.

@oleersoy
oleersoy commented Nov 7, 2016 edited

your demo example does not work without JS

Neither do custom elements.

The fact you don't consider all examples already described like template or even html

Why would you want to PE the html tag? Or more importantly how many developers want to PE the html tag and when do they want to do this?

The is might be useful in certain cases. Sort like a nail and a 2X4 could be useful on an oil platform. The dude's on the platform might be like "Umm....What are you doing with that 2X4?

That one, I am afraid, I cannot fix.

I know. And that is what the core argument should be about. I'm guessing 99.9999% of developers are going to be looking at exactly this scenario. So should we add to the developer learning curve with is to support 0.00001% of use cases?

And if it's really easy to handle those cases with what we already now, then why is the is even in the spec?

@Zambonifofex

Honestly, Iโ€™m starting to agree with @rniwa and Apple more and more that it might be better to simply not allow extending builtโ€in elements; at least not in the same way we extend custom elements.

It might be a genius point for now. Instead of extending built ins, replicate the features of the built ins in external classes, extend those classes to get the features needed, and then consolidate that with Web IDL, and finally we will have a clean fit.

ahem #567 ahem

@oleersoy

@Zambonifofex I see you did a little thinking about this - Lightweight, simple, unobtrusive, puts the power in the hands of the developer. But seriously, this would be like using a scalpel to perform surgery. Who's going to go for that?

@oleersoy

BTW @WebReflection I probably offended you. I just call it the way I see it, but it is not my desire to offend you or make you go away. I think if we all take a solid look at this we will come up with something great that is a good fit for all of us. We can all win.

@trusktr
trusktr commented Dec 14, 2016

The solution with c.innerHTML = c.innerHTML.replace('<table', '<my-table').replace('<tr', '<my-tr') Would trigger a lot of unnecessary DOM mutations, re-paints, FOUC, etc.

So would is="", because <tr is="some-thing"> may first render as <tr> until some-thing is ready, then it will re-render to <some-thing>.


I have a crazy but awesome idea: How about browsers take the "native" elements and re-write them entirely with JavaScript using Web Components APIs. This would make them moldable/hackable/monkey-patchable/extendable/breakable/mixinable/etc to the web developer's needs. If we did this first with problem elements (table, tr, form, input, etc), then web developers would inevitably solve the problems in various ways. Imagine the "native" (non-interpreted) side of a browser is merely a platform that allows for elements to be defined (Custom Elements), and that all pre-existing elements are merely custom elements. The used-to-be-"native" elements would still be native, just that they are defined in the browser's native JavaScript context, not the web app's context, and would still work even if javascript is "disabled". This will give us all a clear picture of how the web works and how to modify it. It would be a big undertaking, but would have awesome results.

@Zambonifofex
Zambonifofex commented Dec 14, 2016 edited

@trusktr

I think literally everyone here would want that. Itโ€™s simply not realistic. How would one implement template? script? style? html/body/head? audio/video/picture/source/img?

@oleersoy

It seems a lot of the people advocating for is really wanted to be able to PE the table element. Specially they wanted to do things like:

<table>
   <rainbow-row>

IIUC this blows up because <rainbow-row> gets booted by the parser as it's building the dom model. I think it's fine though if a <rainbow-table> is provided correspondingly.

Anyways since this scenario is so important to many of the is advocates here I'm just placing an appeal that it be one of the primary scenarios driving the investigation of the API and hopefully one of the first test cases for any V2 API improvements.

I'd also like to appeal to everyone to focus in on the "Why?". You want the is element, but "Why?" do you want it? If we can deliver the "Why?" fast natively for given concrete scenarios without a big bang approach like is then hopefully no one feels like they are being left out in the cold.

@prushforth I know you have been doing a lot of work on PE maps, so I hope the underlying considerations there become one of the primary drivers / test cases as well.

@oleersoy

Just want to point out one more thing that should probably be incorporated into the design framework. With native components we can use BEM modifiers like this (From Philip Walton's Extending Styles article):

<!-- Using a BEM modifier -->
<button class="Button Button--small">Download</button>

With custom elements that maps to:

<!-- Using a Web Component with an attribute for variation -->
<my-button small>Download</my-button>

My only point here is that it is less than straightforward to consolidate this type of architectural approach with the is attribute. So it's an example of how the is attribute puts a constraint on the element designer.

@appunnicer13

I think W3C should go with is="" .
Reason 1 : People don't always live in Cities where internet is a basic need. There are more villages than cities . So internet speed is not so great in those places. If the default behaviour is not set then what they see when page loads will be some spaghetti half eaten. So by using is="", we will have that basic support for elements by default.
Reason 2 : I use 100 different buttons in a page, almost every actionable item is a button, round button , rect button , elliptical button etc ... So It will be very tedious otherwise to select all buttons of a page at the same time . From a web developers's view if you think, We need this not only for just implementing , we are having to maintain this from time to time, so if we want to add tracking code or anything it will be another story .

@oleersoy

Reason 1 : People don't always live in Cities where internet is a basic need.

If you are designing for these cities then keep it light weight. The is attribute is not light weight. By using is you are implying that you will be pulling in additional javascript to support the implementation of what the is attribute is targeting. Thus your page will flicker as the elements are being upgraded and the user will end up having a poor experience. In other words the is attributes guarantees that your comment:

If the default behaviour is not set then what they see when page loads will be some spaghetti half eaten.

Will be true.

I use 100 different buttons in a page, almost every actionable item is a button, round button , rect button , elliptical button etc ...

These are all CSS core concerns. You can do these without the is attribute and you will have a cleaner design. Use SUIT-CSS, BEM conventions, etc.

The is attribute could also cause your maintenance and user experience support scenarios to turn into a nightmare.

A lot of companies are afraid to touch their CSS because the way they went about implementing it resulted essentially in a stack of wine glasses. None of the glasses can be touched without fear of the entire stack tumbling. You risk the same thing with the is attribute.

@JosefJezek

Create extra polyfill modul for Safari, then we can use this service https://polyfill.io/v2/docs/features/ or other serving solution. ;-)

@csuwildcat
csuwildcat commented Feb 18, 2017 edited

I have kept myself generally informed of Custom Element progress, but have been out of active development in this area for a couple years (I was a contributor to this spec in the v0 phase). Now that I am revisiting this area of dev to do meaningful work, I'm honestly astonished to see this is still unresolved.

Being able to extend native elements in a way that leverages existing accessibility mechanisms/strategies, while providing a clear declaration syntax in markup, is something this group needs to account for - full stop

The is attribute, or any API option for that matter, has its nits and rough edges, but I have seen nothing compelling enough on the anti-is side to dissuade me from the opinion that anti-is-ers are acting as the perfect-seeking enemies of good.

Do the right thing - get this resolved.

@rniwa
Contributor
rniwa commented Feb 19, 2017 edited

First, please be aware of the Code of Ethics and Professional Conduct that governs your participation in this repository. Name calling people by saying "anti-is-ers are acting as the perfect-seeking enemies of good" would not result in any productive conversation.

There are many technical reasons we strongly opposed to having the is attribute. Use cases presented for is attribute such as being able to make custom elements accessible and participating in form submissions are valid. What we don't agree is the approach taken by is (as we've explained many times over the last four years).

For accessibility, we've suggested adding the capability to define the default accessibility role in options to customElements.define, and have been working with other vendors on accessibility object model. For form submissions, we've been advocating for a generic mechanism to make any element participate in a form submission.

@csuwildcat
csuwildcat commented Feb 19, 2017 edited

@rniwa first off, I'll immediately ask that you not manipulate my words: you just-so-happened to leave out the words "acting as" in your cherry picked snippet of my statement. My critique was of perceived behavior, and not intended or grammatically structured to be an ad hominem personal attack.

I'll review the content you linked to, but please take care not to falsely accuse me again - I appreciate it even less than I have restrained myself to articulate here.

@rniwa
Contributor
rniwa commented Feb 19, 2017 edited

Corrected. I still find your statement extremely offensive and vastly inappropriate way of participating in this discussion.

@csuwildcat
csuwildcat commented Feb 19, 2017 edited

I submitted an honest, assertive opinion based on over half a decade of work in this technical area, and carefully crafted the cited portion to avoid a fallacious personal attack. To label that "extremely offensive and vastly inappropriate" in the age of Trump, I feel, is a tad ridiculous.

@toriningen

Today I learned that applying "Perfect is the enemy of good" aphorism is extremely offensive and vastly inappropriate.

@oleersoy

Now that I am revisiting this area of dev to do meaningful work

What is the meaningful work that you want to do? We can be a lot more productive if we stick to simple examples and specifics.

Do the right thing - get this resolved.

I like the spirit! Tom Brady just kept yelling THINK!!! at his players in the super bowl, and all of a sudden the Patriots celebrating the championship. A few more posts like that and the whole thing will be settled.

@csuwildcat
csuwildcat commented Feb 19, 2017 edited

@oleersoy good idea, let's talk simple examples - namely, brass tacks product requirements - and craft a solution that fits:

  • Extension of natives should be possible, and be specified via common code mechanisms (classes, attributes, etc.)
  • An extended native should be recognizably, visually associated with its base element in HTML and CSS source
  • Extending natives should be a simple addition to a Custom Element declaration/definition

I'm still reading through material, but let me know if there is a proposed solution that checks these boxes.

@csuwildcat

preemptive laugh emoji

@rniwa
Contributor
rniwa commented Feb 19, 2017

I don't think we can agree on that list of requirements because what constitutes a good design is often subjective and requirements can be arbitrarily restrictive as to favor one design over another. What we can agree on, however, are use cases.

For example, being able to add a new JS API on each row a specific table is one. is attribute solved this problem by extending tr element.

Creating a credit card input element which participates in the form submission and can be associated with a label element like other form control element is another.

And the list can go on. Note that not all use cases need to be addressed by a single proposal or solution. Often times, we need to look at the wholistic picture of the entire Web platform, and decide whether a given use case should be addressed in one or another because what we're designing here will stay with us for another 20 years, if not 50 years.

@csuwildcat

@rniwa no need for paternalistic recitation of the general purpose and responsibilities of web specs, I'm well aware of the process and implications of developing web standards.

Now, on to actual discussion:

The items I mentioned are not subjective, and ironically, are backed by the same need to account for the sort of long-term impacts you replied with. Namely, what kind of web do we want, and what should be present to ensure common ergonomics, utilities, and features continue to be supported.

One of these is View Source. I realize in an age where some apps choose to render code primarily on the server and output amorphous blobs to the client, it's tempting to cut View Source from the requirements list. I believe that's a mistake, again, for the very reasons you outline. View Source, and the ergonomics of scanning code in markup and declarative contexts, is unbelievably important and a fundamental web convention that should be retained. The winds of client code and app frameworks are ever changing, and I'd almost never bet on their pendulum staying to one side for long. As such, it's incredibly important that we not entrench APIs in the imperative JS context. I believe it abandons developers and use cases that benefit from the inherent linkage of markup and declarative code to its semantic intent and functional purpose.

After looking over the links presented here, why isn't this a case of "Yes, and"? There are clear benefits provided by the lengthy API/specs you cited, but what isn't clear is why their pursuit should be at the exclusion of something like is.

@oleersoy

Extending natives should be a simple addition to a Custom Element declaration/definition

This is not a simple self contained example. You are starting with the technology first and making the assumption that your solution is a great one. That may be, but start with the end goal (simple end result example first) and work backwards to the solution. I would start with simple examples illustrating the meaningful work that you want to do.

@pete-otaqui
@csuwildcat
csuwildcat commented Feb 19, 2017 edited

This is not a simple self contained example

True, this is a user-driven feature description. But because you are so passionate about abstracting needs from tech, we should leverage another tool that separates need from technology even more so than a utilization-centric use-case: User Stories.

Here are 3 critical User Stories for this spec issue:

  1. "As a dev-user, I want to create components that leverage native element capabilities and UI in as few steps as possible."

  2. "As a dev-user, I want to work with code that is easy to visualize and reason about across declarative and imperative contexts, even if I didn't write it."

  3. "As a dev-user, I want to ensure the code I write is easily understood by external parties that consume and rely on my code, such as crawlers, partner apps, and other entities."

These are empirical statements of need that should drive the discussion. Solutions should be graded, in large part, on their ability to optimize for these needs.

@oleersoy
oleersoy commented Feb 19, 2017 edited

"As a dev-user, I want to create components that leverage native element capabilities and UI in as few steps as possible."

And one example of such a component is (Real world example - something from the meaningful work that you want to do)?

@csuwildcat

@oleersoy an enhanced button that allows for icons, custom states, and other goodies, while retaining the event interplay, attribute features, and cross-context declaration ergonomics of <button>, without having to recreate any of the native bits in user code.

@pete-otaqui
@oleersoy

@oleersoy an enhanced button that allows for icons, custom states, and other goodies, while retaining the event interplay, attribute features, and cross-context declaration ergonomics of , without having to recreate any of the native bits in user code.

And the markup for this button is?

@csuwildcat
csuwildcat commented Feb 20, 2017 edited

@oleersoy I'll answer by not specifying the exact markup, because remember, we're trying to get to the answer without prescription

Ideally, the markup should:

  • leverage the existing semantic markup and conventions devs use today, which other services rely on for all sorts of things

  • not require review of code from different contexts to understand what native APIs the markup offers

  • be as simple as possible for devs to write and reason about, while fulfilling the two basic conditions above

After examining developer needs and optimal ergonomic configurations, it seems you'd want the combination of a native tag + some unique indication of its custom element nature.

So you tell me, what does that logically reduce to?

@matthewrobb

@csuwildcat Curious how you'd feel about a solving this problem through composition instead of direct inheritance. My thoughts stem from React and Higher Order Components that render out props.children.

<my-field>
  <input />
</my-field>

In the above case <my-field> doesn't have a traditional CE light/shadow dom. It becomes a virtual wrapper / proxy element for the <input>. By way of being a proxy element it would inherit the behavior and accessibility of the target.

Ideally this would be able to support arbitrary depths of nesting:

<my-provider>
   <my-behavior>
     <select>
       ...
     </select>
  </my-behavior>
</my-provider>

From the DOM perspective, selecting a decorator/proxy element would ultimately give you it's target.

You could define a decorator/proxy element the same way you do a custom element now but provide a flag to denote that it is a decorator/proxy.

@rniwa I'd be interested to hear what your thoughts on this are as well.

@oleersoy

So you tell me, what does that logically reduce to?

You being an english major.

@rniwa
Contributor
rniwa commented Feb 20, 2017

@matthewrobb Indeed, nesting elements like that to fallback to native elements was what we suggested as one alternative to many use cases raised by people advocating for is. In fact, this is precisely how fallback works on the Web.

Let it be canvas, iframe, etc... when those elements aren't supported, the browser shows the content inside of it. e.g. you might place img inside canvas to fallback to non-interactive element in a browser that doesn't support canvas. For progressive enhancement purposes, this works perfectly fine.

What it comes short of is when you want to leverage the capability of builtin elements. For example, it's not easy to replicate all the functionalities various input element types provide. For those use cases, we've argued that we need to:

  1. Provide a proper API to participate in a form submission
  2. Provide a mechanism to customize the appearance of form controls. Like -webkit-appearance but more powerful and standardized.

Why? Because in vast majority of use cases we studied, what Web developers want is the ability to override or customize the appearance or the user-interaction model of builtin input element types. Since input doesn't support shadow DOM at all, this isn't even possible even if we had the support for is attribute.

@csuwildcat

@oleersoy how kind of you; I suppose you assume that because I try to articulate ideas in a certain written form (ftr, I was a biz/econ major). Given the style of communication a person uses appears to be sufficient criteria for guessing their major, did you happen to convince an educational institution to issue you a degree in trolling?

Thank you for that comical interlude, Ole. Given the contentiousness of the topic we're discussing, I appreciate that you took a moment to provide me with a laugh.

@oleersoy

I'm from Norway, so Trolling is in my nature. Did not have to go to school for that. Here's the thing. You said you have meaningful work that you want to do. So surely you have one example with real code and markup that you can show us?

@csuwildcat
@treshugart
treshugart commented Feb 20, 2017 edited

It really feels like this should be the way to extend built-ins:

class CustomTableRow extends HTMLTableRowElement {}
class CustomListItem extends HTMLLiElement {}
class CustomInput extends HTMLInputElement {}
// ...

This follows the standard way to extend things and is how you extend custom elements. It'd make sense if this was consistent across the board, without any indirection (is etc).

Unfortunately:

// true
document.createElement('q').constructor === document.createElement('blockquote').constructor

I remember reading somewhere that changing this at the browser level is hard. But being that we're discussing ideals, extending builtins via the standard mechanism would be ideal, no?

This would also assume the parser is updated so that you can place custom elements inside of elements that currently restrict their child list like lists and tables.

@oleersoy
oleersoy commented Feb 20, 2017 edited

Thanks for asking though.

Ok - Great - You did all that and you still can't provide some simple examples?

@matthewrobb

@treshugart You cannot instantiate built in HTML elements for one thing. You also would still need to register the new element class.

Just because ES has a class concept with extension doesn't really justify that model for this use case in my opinion.

@csuwildcat
csuwildcat commented Feb 20, 2017 edited
@oleersoy

I've already provided an extremely simple example

Where's the markup?

@csuwildcat

@matthewrobb I definitely feel composition patterns are useful and a very good option in various cases, but to force management and interaction across an element tree, vs simply leveraging native elements and their existing protos directly, results in suboptimal ergonomics and various other issues I listed. Within the X-Tag community, we have suggested composition from time to time for devs who faced issues in this vein. The reaction from developers using the library consistently sounded like this: "Ok, that's pretty gross and not what I would choose if I could, but I guess we'll have to deal with it."

I believe the approach here should be "Yes, and". Something like is clearly provides a logical and ergonomic way to leverage native elements for a significant portion (if not majority) of direct extension cases, without forcing devs to recreate countless API and interaction combinations in their own code. This bears careful consideration: one reason you really want devs to use native elements and do a little roll-your-own native recreation/composition as possible is that the outcome tends to be an Uncanny Valley of sorts, where users are constantly confronted with elements that appear to be native, but act in slightly different ways than expected. That said, other scenarios may benefit from the APIs/specs folks like @rniwa mentioned, or as you noted, a composition-style strategy.

@treshugart
treshugart commented Feb 20, 2017 edited

@matthewrobb Registration was implied. I'm trying to not constrain myself by what browsers can currently do. We're discussing ideals, right?

The reason I propose this is that - other than limitations due to the way browsers may implement them - it makes zero sense to me why there's a double standard between built-ins and custom elements. There's no tangible benefit to this. At the end of the day, they're all just elements that have different levels of prototype chains stemming from the common HTMLElement constructor. They all follow the same core semantics, so why are there two different sets of rules for them?

My ideal would be taking the example from https://www.w3.org/TR/custom-elements/#custom-elements-customized-builtin-example:

<script>
  class PlasticButton extends HTMLButtonElement {}
  customElements.define('plastic-button', PlasticButton, { extends: 'button' });
</script>
<button is="plastic-button">Click Me!</button>

And being able to do something like the following instead:

<script>
  class PlasticButton extends HTMLButtonElement {}
  customElements.define('plastic-button', PlasticButton);
</script>
<plastic-button>Click Me!</plastic-button>

Though, it's not much more concise, that is secondary to consistency, predictability and extensibility, IMO. Ideally a browser would know that your plastic button derives from the built-in button and you get form participation and accessibility for free. If browsers fixed the q / blockquote deriving from the quote constructor issue (and possibly others), then we can get all the information we need from the super class.

I just thought I'd give my 2c in terms of ideals. Digressing, I get that ideals aren't reality and that we have to make compromises. I'd be more than happy using both extends and is if browser vendors could compromise here.

At the end of the day, we need to be able to do:

  • Custom table rows, list items etc
  • Custom elements that have inputs in shadow roots (currently they don't serialise on submit)
  • Custom elements that have reset / submit buttons in shadow roots (currently they don't do anything)

Surely I've missed something, but these aren't just contrived use cases. Every single item in that list contributed to reasons we stopped using web components for our component library. At the end of the day, we just wanted a solution regardless of if it was ideal or not. It should add weight to this that I'm the author, and still a maintainer of, the second most popular web component library out there.

We need to look at the big picture here. If people can't do what they need to do with web components they're going to turn to something else, even if it's a divergent solution. Web components were introduced in 2011. At the time of this writing, that's six years ago. How much of this time has been spent arguing about is? In just this issue, that's 9 months developers have been without a solution to solve some of the more difficult, and important, use cases that they want a solution for.

@rniwa
Contributor
rniwa commented Feb 20, 2017 edited

The trouble is that the builtin elements aren't written to be extensible in browser engines. Any algorithm that appears in the HTML specification directly looks up the internal state of each element the browser engine holds without going through the JavaScript gets and sets. e.g. the associated form control element of a label element.

As we've stated, if we're supporting a proper subclassing of HTML elements, at minimum, we would have to define what kind of things need to be overridable and provide hooks for authors to customize their behaviors for each builtin element we make subclassible as done for builtin JS types such as Set and Map.

However, there is an alternative approach. Instead of looking builtin elements as some sort of a magic box which provides a bag of functionalities and capabilities, we can decompose them into a small set of primitive APIs that let each element provide such capabilities. For example, an input element uses the capability to make itself focusable, has a shadow tree with a contenteditable, and participates in a form submission process along with many other things.

In our view, it is more fruitful to spec and introduce a small set of these primitives that authors can use to create components of their likings instead of forcing them to extend existing builtin elements, many of which have horrible API surface and surprising behaviors (e.g. value content attribute sets the default value and value IDL attribute sets/gets the current dirty value on an input element).

@treshugart
treshugart commented Feb 20, 2017 edited

However, there is an alternative approach. Instead of looking builtin elements as some sort of a magic box which provides a bag of functionalities and capabilities, we can decompose them into a small set of primitive APIs that let each element provide such capabilities. For example, an input element uses the capability to make itself focusable, has a shadow tree with a contenteditable, and participates in a form submission process along with many other things.

@rniwa That is such a cool, outside-of-the-box suggestion. It would be iterative, too, which would hopefully mean that devs could be drip-fed the solutions they're yearning for.

I'm interested in exploring the path this is going down because it feels like, if there is a direction for this, library authors can start providing abstractions similar to how these might be used natively, thus not only giving a stop-gap API that is similar to the WC future, but also being able to provide extensions in a similar manner.

That said, would I be correct in saying this is still pretty far off? People seem to want a solution for their problems sooner rather than later and are willing to compromise for that.

@rniwa
Contributor
rniwa commented Feb 20, 2017

@rniwa That is such a cool, outside-of-the-box suggestion.

Haha, it's not so outside-of-the-box if you work on the browser engine. We have a whole bunch of C++ classes various elements use to behave the way they behave. It's not like we implement each element as one monolithic C++ class. If you think of it, the whole idea of shadow DOM came out of the internal implementation detail of input and textarea elements in WebKit, which Dave Hyatt modeled after XBL2.

I'm interested in exploring the path this is going down because it feels like, if there is a direction for this, library authors can start providing abstractions similar to how these might be used natively, thus not only giving a stop-gap API that is similar to the WC future, but also being able to provide extensions in a similar manner.

Great. We're interested in exploring this space. I think a good start would be providing a mechanism to participate in a form submission. The accessibility object tree API would go a long way to address the accessibility concern, but providing the default accessibility role in customElements.define is also a great small step forward. We probably don't want to tackle all these issues in this thread though.

Also, this is precisely why I was interested in the list of use cases. Because given use cases, we can come up with an iterative API which address each one of them.

@treshugart
@oleersoy

Since there are so many stakeholders monitoring this now, it might be fine to just start hashing some of the use cases out here, and then if anyone objects, move them to a separate issue.

@csuwildcat

Instead of looking builtin elements as some sort of a magic box which provides a bag of functionalities and capabilities, we can decompose them into a small set of primitive APIs that let each element provide such capabilities.

This is exactly why I mentioned the Uncanny Valley of pseudo-native Custom Elements. We must carefully consider the resulting reality that the above will create if it's offered as the go-to, singular mechanism for leveraging native element functionality. Here's what I firmly believe will occur if you don't go with a "Yes, and" multiple choice implementation that includes is as an option for many cases:

Dev A: "I need a button that does X% of what a native button does, and I only care enough to wire up Y% of the remaining using @rniwa's roll-it-all-yourself solution, because it takes more code and effort."

Dev B "I want a button that does X% of what a native button does, and I only care enough to wire up Y% of the remaining using @rniwa's roll-it-all-yourself solution, because it takes more code and effort."

Dev C "I want a button that does X% of what a native button does, and I only care enough to wire up Y% of the remaining using @rniwa's roll-it-all-yourself solution, because it takes more code and effort."

Devs A, B, and C all add various bits of native button functionality to their 'buttons', some based on need, others based on time and effort, but all of them, even the ones who try to achieve nearly the same thing, will result in heterogeneous native-recreation attempts. What you end up with is hundreds of common button-esque implementations that are unintentionally jagged, just-off versions of native, expected button functionality.

That solution strategy is a bit like saying: "We realize most people just want to add new wheels or a stereo to a car they buy, but wouldn't it be super cool if the only way to get a car with custom wheels was to have the car and wheels shipped to your house as a giant pile of parts that you need to assemble yourself?!"

Please don't force drivers to roll their own cars from a pile of parts when all they want is to add custom wheels.

@oleersoy

Please don't force drivers to roll their own cars from a pile of parts when all they want is to add custom wheels.

This at least makes sense conceptually. Sort of like saying, please don't cut down the entire rain forest so orangotangos have a place to live!

@rniwa
Contributor
rniwa commented Feb 20, 2017

Devs A, B, and C all add various bits of native button functionality to their 'buttons', some based on need, others based on time and effort, but all of them, even the ones who try to achieve nearly the same thing, will result in heterogeneous native-recreation attempts. What you end up with is hundreds of common button-esque implementations that are unintentionally jagged, just-off versions of native, expected button functionality.

But how would that be different in the world of is? One can override some aspects of builtin elements using is without fully making other aspects compatible. For example, you can just attach a shadow root on a builtin element, insert a bunch of divs to change the appearance, and then forget to specify ARIA. The browser engine then has no way to making it accessible.

@WebReflection
WebReflection commented Feb 20, 2017 edited

FWIW I'd be more than happy to see the following in the future:
#509 (comment)

But all cases about graceful enhancement keep being ignored.

Maybe by the time this thread will be resolved all browsers and textual Web surfers on the world will be natively capable of Custom Elements V1 so that graceful enhancement for this matter could be abandoned.

customElements.define(
  'my-button',
  class extends HTMLElement implements HTMLButtonBehavior {} // ???
);

Once we have these composable behavior I wonder if these can be multiple and/or created upfront.

customElements.defineBehavior(
  'button-like',
  {implements: [
    HTMLFocusBehavior,
    HTMLDataListBehavior,
    HTMLEditableBehavior
  ]}
);

customElements.define(
  'my-button',
  class extends HTMLElement {},
  // ???
  {behavior: 'button-like'}
);

Just curious what other developers have in mind for this.

Regards

@matthewrobb
matthewrobb commented Feb 20, 2017 edited

I love the idea of breaking all native "specialness" out into element-traits so to speak. Personally I'd like to see this go in this order:

  1. Create an exhaustive list of "magic native traits" that exist on built-in elements today.
    1a. Create a repo to track the overall progress of adding this layer of abstraction
    2b. Eventually an or any other built-in should be little more than a vendor-provided custom element that is composed of element-traits.
  2. Add a way to buy into buckets of these traits based on existing elements when defining a custom element. (effectively this would meet most of the needs of this discussion)
  3. Break said traits out into fully separated bits that can be mix/matched/composed

It is worth noting however that this approach will have one major drawback in the end. Since we don't have proper interfaces in javascript it won't be easy to select elements in css or via dom api's that are effectively input boxes or any other built-in. Perhaps a pseudo for these traits would be in order?

@csuwildcat

I really like @WebReflection's take on this, because it strikes a balance between "here's a mess of parts, good luck" and an all-in-one inheritance approach. Here's a slight tweak I was considering after reading Andrea's comment:

customElements.defineExtension(
  'button-like',
  {
    implements: [
      HTMLImageBehavior,
      HTMLButtonBehavior,
      HTMLButtonAppearance
    ]
  }
);

Hopefully you could target these bundles in CSS too, consider:

form *:extensions(button-like) {

}

It would be nice to have behavior and appearance buckets that map 1:1 to their native element roots. I feel this would result in elements that are more cohesive across custom implementations.

@matthewrobb

@csuwildcat I honestly think it might be a good idea to call these things "Element Interfaces".

As for css you hit the nail on the head for what I was trying to get at but maybe here is where the is word would be nice:

form *:is(button-like) {

}

Which leads to the next piece: Declaratively adding interfaces to elements

<input is="button-like" />

Thoughts?

@csuwildcat

@matthewrobb love your changes (is = simpler + existing mind share), and customElements.defineInterface() seems like a more fitting name.

@OvermindDL1
OvermindDL1 commented Feb 20, 2017 edited

As long as it works via progressive enhancement, like I still want my special-button to work in ELinks, and is="special-button" handles that case perfectly.

EDIT: I.E. It needs to fall-back in such a way that the page is still 'usable', if not pretty, without javascript what-so-ever.

@WebReflection

@matthewrobb not to be ironic but you basically wrote native built-in extends as these are defined already in the current V1 specification.

The selector though, should rather be:

form *[is=button-like] {

}

to not reinvent the wheel on CSS land too.

If is attribute won't be used as defined in both V0 and V1 I'd finally agree with this thread topic: the is attribute is confusing (and at this point it will break if not patched for those browsers that shipped either V0 or V1 already)

@WebReflection

@csuwildcat I like your refinement, I just think maybe extensions should be kept singular for consistency with the rest of the language (CSS has no plural forms, only eventually third parts)

form *:extension(button-like) {}
extension(button-like) and extension(select-like) {}

This would play nice with the semantic used in

customElements.defineExtension(
  'button-like',
  {
    implements: [
      HTMLImageBehavior,
      HTMLButtonBehavior,
      HTMLButtonAppearance
    ]
  }
);
@matthewrobb
matthewrobb commented Feb 20, 2017 edited

@WebReflection The main difference with my suggestion is that rather than saying that some native element IS another element it would be a way of adding native interfaces to existing elements. My example was confusing:

<my-button is="button-like"></my-button>

And for the css case I intentionally used a pseudo because the goal is not to select elements that JUST contain an attribute (also while not stated I imagined that this attribute would take multiple values e.g. <foo-bar implements="input-like other-thing" />. So the goal is to select elements that implement the interface which may have been defined at registration time in script or have been an existing interface on current built-ins.

:implements(input-like) {}

The above would select any existing form input elements plus anything that has the interface regardless of whether it was added in markup or at definition time.

From a naming perspective I understand there would be conflict potential to use is="" and is:() but they would be MY PERSONAL ideal.

EDIT: Just to clarify as it may not be obvious I also definitely support the following form and am not entirely sold on a declarative way of doing this:

customElements.defineExtension(
  'button-like',
  {
    implements: [
      HTMLImageBehavior,
      HTMLButtonBehavior,
      HTMLButtonAppearance
    ]
  }
);
@WebReflection
WebReflection commented Feb 20, 2017 edited

@matthewrobb :implements(input-like) {} would be already an improvement, IMO, but it touches a mined territory 'cause it has to avoid confusion with possible implements reserved word in JS.

If we drop things that has to be defined in 3 different places (HTML, CSS, and JS counter part) whatever it is will ship sooner than later, which is IMO essential.

Semantically speaking you also define an extension, not an interface ... so it's already a bit misleading to say you implements 'button-like' when this is defined as extension that implements itself other traits/interfaces/mixins.

That being said, I'd like to understand what browser vendors have in mind (if anything) and ideally an ETA accordingly with the decision (I'm honestly tired to wait for this to ship and 3rd parts frameworks already won here because sadly nothing is apparently happening on the standard side).

Regards

@matthewrobb

@WebReflection I was only thinking about HTML, CSS, JS in terms of eventual completeness. I agree 100% that effort should ultimately be put behind making it happen in JS first.

@treshugart
treshugart commented Feb 20, 2017 edited

It'd be nice if decorators were further along in TC39 because they're a perfect fit for this in JS land. It doesn't solve the CSS issue as presented here, but it could quite easily if there was someway to hint to the CSS engine about the custom element directly on the constructor, similar to observed attributes.

I'd much rather leverage existing JS language semantics if possible rather than add options and global names into the mix.

On mobile, but I can flesh this out a bit more later.

@WebReflection
WebReflection commented Feb 20, 2017 edited

it could quite easily if there was someway to hint to the CSS engine about the custom element directly on the constructor

ehr ... like what? CSS and HTML are a separate world, which is why customElements is a registry exposed to JS land in order to hook elements into DOM world.

Let's not make this impossible for everyone to achieve in less than year, maybe?

We already have a registry for elements, extending it for behaviours/composed interfaces seems easier for everyone.

I'd much rather leverage existing JS language semantics

decorators are Stage 2 and not even close to be shipped.

I'd rather be pragmatic and move the Web forward, specially because any procedural way can be easily extended later on through decorators. That's the whole point, giving us the ability to simplify otherwise cumbersome low-level patterns, which is why we all wrapped CustomElements API somehow, right? ๐Ÿ˜‰

@treshugart
treshugart commented Feb 20, 2017 edited

ehr ... like what?

...

similar to observed attributes

...which I will expand on after addressing a few things.

Let's not make this impossible for everyone to achieve in less than year, maybe?

Decorators imply that, however, decorators are just functions and always have been; this part of the API isn't contentious and is the part I wanted to focus on.

Decorators are Stage 2 and not even close to be shipped.

Which I explicitly noted by also saying:

It'd be nice if decorators were further along in TC39 because they're a perfect fit for this in JS land.

I'll try and flesh this out a bit more. I think we're suggesting very similar things, but I'm trying to cut back the API a little bit.

JS

As stated above, decorators are just functions. These are the same thing:

function withFormParticipation (Base) {
  // ...
}

@withFormParticipation
class MyElement extends HTMLElement {}

// is the same thing as...

const MyElement = withFormParticipation(class extends HTMLElement {});

Decorators can be composed:

function likeFormElement (Base) {
  return withFormAccessibility(withFormParticipation(Base));
}

@likeFormElement
class MyFormElement extends HTMLElement {}

// or, of course...

const MyFormElement = likeFormElement(class extends HTMLElement {});

You go on to say:

I'd rather be pragmatic and move the Web forward, specially because any procedural way can be easily extended later on through decorators. That's the whole point, giving us the ability to simplify otherwise cumbersome low-level patterns, which is why we all wrapped CustomElements API somehow, right?

I was never against this, in fact, if you read in to my suggestion, I'm espousing the lowest-level way of doing this: functions. Decorators at this point are not worth their weight alone, but worth discussing as they emphasise functions as the composition mechanism because they are a future feature of ES that we'd be able to leverage if following this path.

CSS, but also JS sugar

This is where the likening to observedAttributes comes in. Instead of adding behaviours as an option to the third argument of customElements.define(), there already exists the convention of adding information like this to the constructor. The third argument only exists for extends anyways, which is what we're trying to propose alternatives to. Orthogonal to this, I see no reason why extends wasn't specified as a static member in the first place. Anyways.

If behaviours were added as a static member, subclasses would automatically inherit them, which is what I'd expect to happen when extending something that has specific behaviour. If we pass it as the third argument, this doesn't happen explicitly, if at all.

customElements.defineBehaviour('like-form-element', [
  withFormAccessibility,
  withFormParticipation
]);

class MyFormElement extends HTMLElement {
  static get behaviours () {
    return ['like-form-element'];
  }
}

// This automatically behaves like-form-element because of the prop.
class MyFormElementSubclass extends MyFormElement {
  // ...
}

Really, the static behaviours property and defineBehaviour is syntactic sugar for having to compose them manually, and serves as a stop-gap for decorators, for the time being. However, static behaviours could also be used as the hint to the CSS engine similar to what was being discussed above.

My concern here is that many prefer to ship custom elements without defining them to avoid naming conflicts and leave it up to the consumer to define them. If we introduce both defineBehaviour() and a way to tie those behaviours to custom elements using the registered names (static behaviours, or the third argument to customElements.define()), this either requires the builder to pre-define these names, or the consumer to hook them up manually. It would be odd to ship a form element and require the user add accessibility and form participation on their own accord. If we simply use functions, we get around this issue, entirely.

I think it's worth touching on this point to ensure we don't pigeonhole ourselves, however, I'm not convinced we should spend too much time on it. Shipping the JS part is of utmost importance. I think it would be pragmatic to keep it as simple as possible for now and to see how libraries handle it.

@JosefJezek
JosefJezek commented Feb 21, 2017 edited

I created responsive html table with <iron-selector> using is, check out this link https://www.webcomponents.org/element/StartPolymer/s-table

@bicknellr

I don't think the custom elements API should introduce a new, single-scenario composition / inheritance mechanism (defineBehavior, defineExtension). If there are features that built-in elements have that can't be emulated by custom elements because they aren't exposed by the platform, we should be working to expose them (@rniwa's suggestion) rather than claiming that they exist because of a separate, element-only method of composition.

Given that the features in question aren't currently exposed in any form (other than as part of the built-in elements), why concede that we need a special way to compose them? Wouldn't it be preferable to expose them in a way that makes them composable in plain JavaScript? Further, if this new, custom-elements-only composition API then isn't necessary for using these features in your custom element, why should it become part of (read: add complexity to) the custom elements API? This seems like a 'solution' looking for a problem.

@treshugart

@bicknellr 100% agree. If this is in reference to the second part of my comment (maybe not?), then maybe I wasn't as clear as I should have been about leaving it out of this first iteration. I don't believe it's necessary, at all, but if done, I wanted to try and explore a simpler API for it, is all. To be clear, I have exactly zero use cases for styling against behaviours. Just because you can does not mean you should.

@WebReflection

@treshugart I know what are decorators and how to use them, but indeed these are something always deliverable in user-land, DOM APIs aren't.

I'm also concerned about possible polyfills, if we have unpolyfillable features, we need transpilers, and transpilers can have bugs that make the feature unusable (e.g. extending native classes)

@treshugart
treshugart commented Feb 21, 2017 edited

@WebReflection I wasn't trying to be patronising, it was more for posterity than your benefit. For the record and to be as clear as possible: I'm advocating for functions. Just functions. They take a single argument that is the class. No additional API additions to customElements or customElements.define().

I'm also concerned about possible polyfills, if we have unpolyfillable features, we need transpilers, and transpilers can have bugs that make the feature unusable (e.g. extending native classes)

Polyfills aren't immune to bugs. Case in point: one of the reasons we stopped using web components is that the polyfills were horribly unstable.

Maybe an alternative way to look at this would be to document the workarounds instead of forcing a solution down a particular path because it must be constrained to the ability to be polyfilled.

Some workarounds that we've used fitting the items I outlined earlier:

I think this would have a far more positive outcome because workarounds can be documented now and users can start consuming then now. To add to this, documentation on ways to do things with web components seems to be the largest contributor to misinformation about them as well as confusion as to what's possible and how to do things.

Even if "is" was settled on, it would take time to finalise and ship. I'm optimistic as to where this discussion is headed, which I definitely couldn't say a few days ago. Props to @rniwa for being objective here.

@WebReflection

I'm advocating for functions. Just functions. They take a single argument that is the class. No additional API additions

You seemed to forget why namespaces are useful. Your functions cannot be just global scope pollution, those functions belongs to Custom Elements, so let's put them in the only global namespace introduced for the goal: the customElements registry, or its CustomElementRegistry class (I don't like typing that much, I'm being honest)

Polyfills aren't immune to bugs. Case in point: one of the reasons we stopped using web components is that the polyfills were horribly unstable.

This is upside down. I've been advocating against using transpilers because these are the one causing instability! Have you read this bug at all? You cannot trust transpilers, not polyfills!!!

I'm growing white hair to advocate about transpilers problems, or suggest solutions,or create libraries immune to transpilers, and you tell me the problem is my super stable and tested polyfill used even by the production delivered Google AMP Project?

Sorry but it's clear we're not on the same page here so I'll happily re-drop this thread.

I also suggest you to watch my talk at wcremoteconf, you were giving yours too the day after.

Best Regards.

@treshugart

You seemed to forget why namespaces are useful. Your functions cannot be just global scope pollution, those functions belongs to Custom Elements, so let's put them in the only global namespace introduced for the goal: the customElements registry, or its CustomElementRegistry class (I don't like typing that much, I'm being honest)

I'm speaking in terms of "pure" functions. As in, technically they may be called "methods" because they're on an object instance, but they don't store any state or have any side effects other than, quite possibly, mutating the class that's passed in as to avoid long prototype chains (if this is even an issue). I'm 100% behind them being in the customElements namespace.

This is upside down.

I don't think it's anyone's place but ours to determine the validity of our reasoning.

Have you read this bug at all?

Yep.

You cannot trust transpilers, not polyfills!!!

Subjective. Objectively, polyfills were proven to be an issue for us.

I'm growing white hair to advocate about transpilers problems, or suggest solutions,or create libraries immune to transpilers, and you tell me the problem is my super stable and tested polyfill used even by the production delivered Google AMP Project?

I never mentioned your polyfill. Specifically, it was mostly the shadow DOM polyfill, though we had some issues with others, they were fairly minor. I apologise if you're taking this personally, but I think it's best if we try and get this discussion back on track.

@rniwa what are your thoughts on using simple functions that are compatible with the decorator pattern, sitting within the customElements namespace, or similar? If you think this is a place you'd like to take the discussion, I'm happy to try and make a more end-to-end proposal.

It would be good for other WG members to weigh in, too.

@oleersoy

It would be great if someone could just put the pieces back on the board again...or leave most of the pieces off and just focus on one use case and the corresponding API?

@rniwa
Contributor
rniwa commented Feb 22, 2017 edited

I think it's premature to try to come up with a set of compassable features like that. I think we need to first come up with a list of use cases that aren't adequately addressed by the current Web API (besides is attribute), and spec API for those.

Once we have those primitive APIs to address use cases, I can see bundling some of them up to make it easily compassable seems as a sensible approach but perhaps this is an area we can leave to library/framework authors first. Once it became obvious that every library/framework is having some basic set of feature as a composable function/class, etc... then we can standardize them.

In general, adding new features to browsers is a slow & painful process so we should be adding things that are already well vetted in JS library/framework.

@treshugart

I think it's premature to try to come up with a set of compassable features like that. I think we need to first come up with a list of use cases that aren't adequately addressed by the current Web API (besides is attribute), and spec API for those.

Sure. I'll mention the use cases we've had again:

  • Custom table rows, list items etc
  • Custom elements that have inputs in shadow roots (currently they don't serialise on submit), related #187
  • Custom elements that have reset / submit buttons in shadow roots (currently they don't do anything)
@justinfagnani

@treshugart I don't think decorators are the right solution for platform mixins because they are applied to the wrong thing - the concrete subclass of HTMLElement that the developer is writing.

Class mixins do the right thing, because they apply to the prototype chain above the target class. Methods can be override, super calls, etc:

class MyGlobalLikeThing = WindowOrWorkerGlobalScope(Object) {
  fetch(input, init) {
    // do something
    return super.fetch(input, init);
  }
}
@treshugart

@justinfagnani decorators were a mistake to mention, if only because they are distracting from my core proposal: functions. In your case WindowOrWorkGlobalScope is a function that takes a constructor and I assume does something like return class extends Object {}; internally, right?

FWIW decorators use the return value of functions, so you could rewrite this as:

@WindowOrWorkerGlobalScope
class MyGlobalLikeThing {}

See http://codepen.io/treshugart/pen/zZOrYX?editors=1010 for an example of this with a custom element.

@WebReflection

@treshugart

I never mentioned your polyfill. Specifically, it was mostly the shadow DOM polyfill

like I've said in my talk, Shadow DOM is one of that things that cannot be polyfilled, like WeakMaps or Proxy. It was their fault not to warn about inevitable issues a polyfill would've caused, and your responsibility to not use it, since not essential for Custom Elements (indeed it's a different specification)

I think it's best if we try and get this discussion back on track.

Agreed. However, we already wrote ideas but @rniwa says he needs more use cases or libraries implementing something impossible to implement without is="" so we're fully stuck in a circle here.

I've no idea how to move forward.

@treshugart
treshugart commented Feb 22, 2017 edited

@WebReflection for posterity, you are incorrect on all accounts in terms of our use cases. Please, if you want to discuss this further, I am more than happy to take it offline. Here is not the place.

@treshugart
treshugart commented Feb 22, 2017 edited

@justinfagnani actually I stand corrected. While you can mixin with decorators, it applies the proto chain the other way around. Still: functions :)

@rniwa
Contributor
rniwa commented Feb 22, 2017 edited

I think it's best if we try and get this discussion back on track.

Agreed. However, we already wrote ideas but @rniwa says he needs more use cases or libraries implementing something impossible to implement without is="" so we're fully stuck in a circle here.

Why do you think it's impossible to implement? My proposal is to find use cases which can't be satisfied without is, e.g. setting default accessibility role, and fix those problems by adding new API. Once we've done that, library/framework can use mixins, pure functions, etc... to make it developer friendly as they wish. If one or another approach proves to be superior to others and all libraries / frameworks end up duplicating the work, we can just standardize it. It is pretty clear to me at this point that many people have different opinions on how to approach this, and it's probably best to let Web developers experiment it first (in terms of how to make it developer friendly, not to add those APIs).

My take on future directions of Web components is to chip away many small pieces. e.g. form submission participation, default ARIA roles for custom elements, etc... Some of those incremental improvements can be polyfiable but others may not be if we're exposing a fundamentally new capability to the Web. But that's okay.

@treshugart

Also a fan of this. ๐Ÿ’ฏ

@WebReflection

My proposal is to find use cases which can't be satisfied without is

You have these use cases since the very beginning of this thread and @treshugart just added few.

It is pretty clear to me at this point that many people have different opinions on how to approach this

we're just speculating on what could be the implementation of what you proposed but so far the entirety of the Web did just fine with is="" attribute in V0 and polyfilled V1.

it's probably best to let Web developers experiment it first

We cannot extend native builtins so how/what are we supposed to experiment, exactly?

The data-boo is an experiment born as a joke that wraps native builtins inside their related CE, where it's possible, yet it would use promotion or upgrade builtin elements where encountered because, in case it's not clear yet, we cannot:

  • extend native builtins
  • define table rows as custom elements
  • use smarter img tags
  • inherit aria

etcetera ...

@rniwa
Contributor
rniwa commented Feb 22, 2017

it's probably best to let Web developers experiment it first

We cannot extend native builtins so how/what are we supposed to experiment, exactly?

I'm not suggesting to start experimenting anything right now. The first step is to expose native builtin elements' capabilities as mandated by use cases.

  • extend native builtins

This is not a use case. A use case would must be an user scenario which one may wish to extend native builtins to address.

  • define table rows as custom elements

Again, this is not a use case. A use case would be an user scenario in which one may wish to customize table rows, and for which one may wish to address it by defining it as a custom element.

  • use smarter img tags

Again, this is not a use case, and did you actually want to change some parser behavior with respect to img or you meant to say img elements? If so, what do you want to change about img elements?

  • inherit aria

Setting the default ARIA role is something I've suggested time and time again. Here's an actual use case: I wish to create a toolbar component and set the toolbar ARIA role without having to add a content attribute visible to the component users.

@WebReflection

If so, what do you want to change about img elements?

Promote gracefully higher resolution automatically only if devicePixelRatio is more than 1 and connection is WiFi/3G+ and there's no roaming involved. I guess this is not a use case neither, isn't it?

I also would like to have the freedom to improve inputs as I need for my daily tasks, as well as textareas for editing related tasks and everything else you can do today with builtins.

I'd like to have table rows I can drag and drop and resize accordingly with their content or container, I want a mechanism to be able to setup whatever is placed on the document that is a known type.

I'd like to have Custom Elements primitives for any element I need so that other libraries using innerHTML don't have to worry about setting up the content and I don't want to listen via MutationOserver all the time to every node 'cause I have connectedCallback and disconnectedCallback to do it and per each element I've defined.

Are these use cases?

@matthewrobb

I think it's premature to try to come up with a set of compassable features like that. I think we need to first come up with a list of use cases that aren't adequately addressed by the current Web API (besides is attribute), and spec API for those.

Once we have those primitive APIs to address use cases, I can see bundling some of them up to make it easily compassable seems as a sensible approach but perhaps this is an area we can leave to library/framework authors first. Once it became obvious that every library/framework is having some basic set of feature as a composable function/class, etc... then we can standardize them.

In general, adding new features to browsers is a slow & painful process so we should be adding things that are already well vetted in JS library/framework.

Honestly the use cases are equal to or greater than those of the built-ins themselves. We aren't sitting around justifying why anyone would ever want to provide input to a web page so why should we re-justify the use cases that drove each and every currently existing built in element and ultimately brought along special features to support those use cases.

My WORRY about this pave the cowpaths argument is twofold. For one the cowpaths are already paved by the built ins which we can really just consider User-Agent Defined Custom Elements. If we solve each and every case one by one then we are narrowing our vision and likely to end up with many awkward solutions spread out all over the spectrum.

I really think for this case it is considerably more practical on all accounts to come up with solution that is broad-sweeping. The use case: Allow developers to build custom elements with all the same affordances, conveniences, and behaviors to built-ins. Requiring a user-story other than this is a political movement that we all know will block or stall progress on this issue for YEARS if not indefinitely.

@rniwa
Contributor
rniwa commented Feb 22, 2017

Promote gracefully higher resolution automatically only if devicePixelRatio is more than 1 and connection is WiFi/3G+ and there's no roaming involved. I guess this is not a use case neither, isn't it?

This is a great use case. However, we found that exposing information about whether an user is on WiFi, 3G, or otherwise using roaming is a great way to track users so we have to come up with some solution that doesn't involve directly exposing such information.

I also would like to have the freedom to improve inputs as I need for my daily tasks, as well as textareas for editing related tasks and everything else you can do today with builtins.

This is not a use case. We must state what those improvements are. Use cases state end results, not means to get there.

I'd like to have table rows I can drag and drop and resize accordingly with their content or container

This is a great use case too. It seems like what you want is draggable and dropzone attributes that's being deleted from the HTML specification, and make it work with table rows. We should come up with a better mechanism for drag & drop since this is an area we're facing serious accessibility issues.

I'd like to have Custom Elements primitives for any element I need so that other libraries using innerHTML don't have to worry about setting up the content and I don't want to listen via MutationOserver all the time to every node 'cause I have connectedCallback and disconnectedCallback to do it and per each element I've defined.

But presumably, those primitives or library need to be compassable? e.g. if you want to make a helper to make an element focusable, and another to make it participate in the form submission, you may want to use both.

In that case, what we need might be something like adding the support to MutationObserver to observe connected/disconnected.

@prushforth

My use case is this: I want to be able to extend the declarative web with new features/behaviour for existing elements. Even if I have to completely re-write the features I need for an element in script i.e. it inherits nothing except the name (not perfect, but easy, I guess). I want to use this facility to propose new features for HTML, and I want to be able to provide a customised built-in as a polyfill for the day when the feature is implemented in some browser but not others/all. In this way, I see customised built-in elements alleviating some of the political pressure to implement features natively which could otherwise continue to happily exist as community-supported customised built-in elements.

@trusktr
trusktr commented Feb 23, 2017
@oleersoy

accounts to come up with solution that is broad-sweeping. The use case:
Allow developers to build custom elements with all the same affordances,
conveniences, and behaviors to built-ins.

I don't think anyone disagrees with this.

Requiring a user-story other than
this is a political movement that we all know will block or stall progress
on this issue for YEARS if not indefinitely.

We all want Aladdins Lamp. Everyone agrees that this is the ultimate end game. The point of having concrete real world user stories in addition to this end game is to ensure that we have real world test cases to verify progress against. It's possible to approach this from both ends. Personally I have a much easier time looking at something concrete, and then extrapolating what the API should be from there. For example take this boostrap markup from the dropdown example:

<div class="dropdown">
  <button class="btn btn-default dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
    Dropdown
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
    <li><a href="#">Action</a></li>
    <li><a href="#">Another action</a></li>
    <li><a href="#">Something else here</a></li>
    <li role="separator" class="divider"></li>
    <li><a href="#">Separated link</a></li>
  </ul>
</div>

This would be far more elegant as a few custom elements. So what is the API for creating those elements? What native capabilities should these elements inherit? Do they need everything that the native element has or is it better to use mixins to allow for precise features / behaviors?

The point of a simple concrete use case is not to stand in the way of Aladdins Lamp. It's to evaluate ways to get the lamp. Once we look at this long enough the best way to get the lamp will be obvious, but we have to start looking at concrete real world cases, otherwise we will be stuck in this Mad Hatter world forever. GIVE ME THE LAMP!!!

@csuwildcat
csuwildcat commented Feb 23, 2017 edited
@oleersoy

Let's not confuse user stories with use cases.

We want a factory to build anything. Lets at least try to build a car and a motorcycle with the prototype for that factory, and lets watch the parts flow through the routing (API) to make sure everyone likes what they see.

(one being a button with an icon and
custom events)

Where's the markup? This is important because it will end up driving the workflow for web / html developers. The two core things we are trying to do here is provide us (The component makers) with the flexibility to make the best components we can for the broadest audience (Folks that need screen readers, etc.) while at the same time providing the simplest most effective workflow for the html developers that are going to put these new components / elements to use, as well as the developers that will be maintaining this work.

@oleersoy

@csuwildcat you're a biz guy (Complement - I'm a biz guy too) so perhaps you read the case studies on Xerox quality issues during the height of their copier empire. The customers kept complaining that the machines were hard to use and very difficult to fix when they broke down. The engineers kept saying that that was just balony. It was not until the engineers had to use their own copiers and maintain them that the issues got fixed. Lets run some copies before we start throwing copiers on the market.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment