Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Can I define extended build-in elements? #1382

Closed
2 tasks
AndyOGo opened this issue Feb 20, 2019 · 19 comments
Closed
2 tasks

Can I define extended build-in elements? #1382

AndyOGo opened this issue Feb 20, 2019 · 19 comments
Labels

Comments

@AndyOGo
Copy link

AndyOGo commented Feb 20, 2019

Stencil version:

 @stencil/core@<version>

I'm submitting a:

[x] bug report
[ ] feature request
[ ] support request => Please do not submit support requests here, use one of these channels: https://stencil-worldwide.herokuapp.com/ or https://forum.ionicframework.com/

Current behavior:

I couldn't find a clear statement about whether only <autonomous-custom-element> and/or <div is="extended-built-in-element"> are supported.

Expected behavior:

Should cleary state support for:

  • <autonomous-custom-element>
  • <div is="extended-built-in-element">

Steps to reproduce:

Nothing here https://stenciljs.com/docs/decorators nor here https://stenciljs.com/docs/browser-support

@ionitron-bot ionitron-bot bot added the triage label Feb 20, 2019
@AndyOGo AndyOGo changed the title Can I build extended build-in elements? Can I define extended build-in elements? Feb 20, 2019
@arjunyel
Copy link
Contributor

arjunyel commented Mar 8, 2019

You can't and won't be able to, Safari said they will never support is="" so unfortunately it's dead in the water

@AndyOGo
Copy link
Author

AndyOGo commented Mar 8, 2019

What a bummer, extending built-ins is a key feature.

I created a bug ticket at webkits issue tracker:
https://bugs.webkit.org/show_bug.cgi?id=195403

And here is a built-in polyfill by @WebReflection:
https://github.com/WebReflection/built-in-element

@arjunyel
Copy link
Contributor

arjunyel commented Mar 8, 2019

Unfortunately that bug will be closed :( WICG/webcomponents#509 (comment)

And even with a Polyfill I dont think stencil will support it because Stencil tries to stick to the web platform as close as possible. I would recommend not using is="" unless you dont need to support Safari

@AndyOGo
Copy link
Author

AndyOGo commented Mar 8, 2019

Ohhh, how can they do that. EXTENDED BUILTINS are living standard😲

Thanks for your feedback anyway

@WebReflection
Copy link

WebReflection commented Mar 11, 2019

FYI the right polyfill is this one.

StencilJS used to be based on document-register-element which supported already custom elements builtins.

However, Firefox and Chrome ships already CE with built-in extends, WebKit is just playing the push back but it's polyfilled with the link I've posted.

Regards

@FRSgit
Copy link

FRSgit commented May 13, 2019

@arjunyel considering whole discussion under WICG/webcomponents#509 (especially that comment) I must say that conclusion even with a Polyfill I dont think stencil will support it because Stencil tries to stick to the web platform as close as possible is pretty suprising to me.

Extending native components is a living standard already and there is no reason to oppose it.

IMO benefits coming with using <element-name is="..."> notation (accessibility, SEO, etc) outweight any problems it can bring for stencil developers.
From my company's perspective not having this feature (at least in future plans) can be a killer for using stenciljs at all :<
Do we know what's the stencil-team official position on this?

@WebReflection
Copy link

@FRSgit don't forget with MS Edge now being based on Chromium, Webkit based browsers will be the only not shipping custom elements built-in extends.

The Apple/Webkit team is very opinionated (and for reasons), but they are also quite pragmatic: when they see ther's no reason to not support something widely available elsewhere, they just go for it, even if they initially never agreed on that.

The reason they are pushing back is, in my speculative opinion, that legacy is tough to touch, and what's in HTML already should stay there where nobody needs to change a single thing.

Regardless, they are one of the best devs out there, so I think it'd be safe for Stencil to simply adopt this poly and, in the worst case scenario, be slightly slower on the already fastest platform out there: Apple hardware.

All other browsers will work out of the box.

@FRSgit
Copy link

FRSgit commented May 27, 2019

After some talks with @manucorporat (unfortunately some of my questions were left unanswered :<) I've got an info that stencil won't support this at all.
There will be one possibility to overcome that limitation with stencil one - that, new version will allow to output vanillaJS custom elements which one could of course register as extending natives. Problem is that these components would loose some of Stencil's functionalities, so probably this feature won't be so helpful in prod cases, but well, that's at least something..

@johnstrickler
Copy link

I'd like to stop re-implementing basic functionality that native elements provide but there's only two ways that I know of building off of native elements:

  • Extending native elements
  • Passing all props/attributes to a single wrapped child

I know the first isn't possible with Stencil but it'd be nice to hear the technical explanation of why it's not a priority. Is it technically not feasible? Overly complex?

Is the second option doable? Or would I have to explicitly list out every native property then pass it to the native child element?

What are other Stencil users doing? Is everyone else implementing native functionality over again?

@WebReflection
Copy link

@johnstrickler

I know the first isn't possible with Stencil but it'd be nice to hear the technical explanation of why it's not a priority. Is it technically not feasible? Overly complex?

It's already solved, you need one single script upfront and you can forget about custom elements built-in issues: https://github.com/ungap/custom-elements-builtin#all-possible-features-detections

Is everyone else implementing native functionality over again?

Not me, and I've created a project that is basically fully based on custom elements built-in extends, and it offers SSR out of the box. It's called heresy, ping me on twitter to know more 👋

@johnstrickler
Copy link

@WebReflection Thanks for the info. Great looking library :)

I was asking those questions in the context of Stencil though. Will Stencil ever be capable of re-using native elements? Frankly, it's huge waste of time, and very bug prone, to reimplement functionality that you get for free from native elements.

@AndyOGo
Copy link
Author

AndyOGo commented Jun 20, 2019

@adamdbradley @manucorporat @jthoms1 I'm sure your feedback regarding support of extended built-in elements and the is="my-element" syntax within Stencil is very welcome.
I would appreciate it a lot if you find some free time to discuss this?

@kneyugn
Copy link

kneyugn commented Dec 21, 2019

Coming from accessibility stand point, I think having this feature in Stencil will reduce a lot of time wasted reimplementing native elements and making them accessible again, as @johnstrickler said, very bug prone. Already, we see this in Ionic's core components. A lot of aria usage could be reduced. Ex: There's some of work involved in making sure the buttons have same parity with native buttons in forms. Could built-in elements have helped with this?

edit: My main concern is, is an IE11 polyfill possible? The example does not seem to work in IE11.
update: it does :) https://ungap.github.io/custom-elements-builtin/test/es5/

@WebReflection
Copy link

WebReflection commented Dec 21, 2019

@kneyugn it doesn't work on IE11 only, it works down to IE9 and, with some extra poly and caution, even IE8, plus every older mobile browser.

There are two polyfills involved here, the one for browsers that don't support customElements at all, provided by the long-time battle-tested document-register-element polyfills, which lands on legacy via a single top level script:

<script>this.customElements||document.write('<script src="https://unpkg.com/document-register-element"><\x2fscript>');</script>

This polyfill has fueled Google AMP, Mozilla AFrame, and even StencilJS, for years, providing customElements with built-in extend capabilities without major issues (issues count is zero) and for long time.

However, that poly doesn't even try to bring ShadowDOM (unpolyfillable in a reliable way), which is why I believe StencilJS ditched it, but the good thing is that there are work arounds for that too (either polyfills or basic implementations that use iframes instead), and yet every modern browser that supports customElements natively, won't need any Shadow DOM polyfill, and only WebKit/Safari can use the dedicated script that can also be implemented after feature detection, making the top level script more like:

<script>
if(this.customElements)
  try{customElements.define('built-in',document.createElement('p').constructor,{'extends':'p'})}
  catch(s){document.write('<script src="//unpkg.com/@ungap/custom-elements-builtin"><\x2fscript>')}
else
  document.write('<script src="//unpkg.com/document-register-element"><\x2fscript>');
</script>

... wait, wasn't document.write bad?

To start with, that's a legacy feature that won't go anywhere any time soon, because it would break otherwise the Web if removed from the platform.

document.write is an essential mechanism to grant execution of a script before other scripts, and even if it's blocking, like any other top level script on the page that doesn't use deferred or async, it's used only by legacy browsers, so that every modern browser won't ever reach that part of the code: it's basically unreachable death code for ~90% of the real-world surfers.

In WebKit/Safari case thought, it's necessary to grant next script, whatever that is, can already define Custom Elements built-in extends, and still it's only for WebKit/Safari, but the poly is around 1K, so it shouldn't penalize anyone out there, specially if hosted via CDN, and specially 'cause such polyfill hasn't really changed much for months (years?) 'cause it "just works" within its constructor caveats, something any library can circumvent in a way or another.

TL;DR there is a polyfill that is not obtrusive and vaporware for the majority of the Web surfers, so that arguments against it, when dozen of other polyfills are landed here and there via Babel or polyfill .io service, are always, imho, weak.

@mfranzke
Copy link

mfranzke commented Jun 26, 2020

This ticket died (got closed) very silently. Is it because everything has been said (even though not discussed to an end/finding a consens) and/or the frameworks creators opinion has even already been reflected?

@chris-dura
Copy link

Perhaps I've missed it in the thread, but currently, I'm under the impression that we can't even use the polyfill(s) with StencilJS?

So, I currently believe that if I want to extend native elements, I cannot use StencilJS for my component library ...

if that's incorrect, and we can use the polyfill as a workaround with StencilJS, someone please correct me!
(and I might ask for an example 🤣)

@RS-Sautter
Copy link

@manucorporat @adamdbradley Could you please reopen & comment on this? I think this is a important issue for many users.

@Zizico2
Copy link

Zizico2 commented Apr 30, 2021

As much as I think this feature is a key feature of the Web Components standard, for accessibility reasons mainly, I have accepted it is doomed to die and I have defaulted to setting role="presentation" (or role="none") and display: contents on the Host and use whichever element I would be extending internally. This is far from perfect but it will fix most accessibility problems. We are still stuck with manual attribute and event forwarding. If Stencil, Lit and libraries alike supported attribute forwarding it would mostly eliminate the need for extending built-in elements.

EDIT: + a single css shadow part on the "extended element" (maybe called main) for à la carte customization

EDIT: for completion's sake here's an example (imagine the attribute forwarding xd): (next comment)

@Zizico2
Copy link

Zizico2 commented May 5, 2021

For completion's sake (see the previous comment) here's an example (imagine the attribute forwarding xd):

// custom-button.ts
@Component({
  tag: 'custom-button',
  styleUrl: 'custom-button.css',
  shadow: true
})
export class CustomButton {
  render() {
    return (
      <Host role="presentation">
        <button part="main"><slot /></button>
      </Host>
    )
  }
}
/* custom-button.css */
:host {
  all: inherit !important;
  display: contents !important;
}

It's fully customizable through the main css shadow part, the forwarded attributes and it'll inherit any styles the built-in element would since the Host inherits everything.
It also appears in the accessibility tree as if it was a standalone button.

I don't know if the !important are a good practice here but it makes sure the end user can't override any styles on the Host, because of the all: inherit !important and instead they need to use the shadow part if they want to customize the button.

Building on top of this would be roughly the same as extending the built-in button.

(missing form association, I'll update this when I get around to it, for non form associated elements, this is all you need)

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

No branches or pull requests