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

Why do we really need hyphens? #658

Closed
trusktr opened this issue Aug 25, 2017 · 32 comments
Closed

Why do we really need hyphens? #658

trusktr opened this issue Aug 25, 2017 · 32 comments

Comments

@trusktr
Copy link

trusktr commented Aug 25, 2017

Or better question: why aren't we thinking of ways to allow any tag name inside some form of encapsulation of a component? Today we have Vue setting the example. It was React yesterday.


I know this has already been discussed.

Many frameworks already allow this.

For example, the new and highly popular Vue allows names without hyphens.

Everyone LOVES it.


What the web needs is perhaps to stop, and think about these new component models in a different way. For example, here's a proposal: the Unity Component Spec.

We simply just need a way to write components in a way where we can easily associate behaviors with any tag name. For example, if we want to define what <foo> means inside our component, let's be able to do that.

@milieuChris
Copy link

milieuChris commented Aug 25, 2017 via email

@baocang
Copy link

baocang commented Aug 29, 2017

I hate the hyphens in custom element name.
Such as calendar, The best way to use the calendar is the public attribute and method has a spec by some group or person. And a lot of developer can create a new calendar by the rule.

Then we can use the different calendar in html, just change the import from
<link rel="import" href="path/to/a/calendar.html"> to <link rel="import" href="path/to/b/calendar.html"> or replace file path/to/a/calendar.html by path/to/b/calendar.html without other modification.

But now, I needs to change the url of import, change from a-calendar to b-calendar and attribute, event and others in every files.

@web-padawan
Copy link

Hyphens are needed to dustunguish custom elements from mistyped stuff like <siv> (my personal typo), in order to render HTMLElement but not HTMLUnknownElement, aren't they?

@trusktr
Copy link
Author

trusktr commented Aug 29, 2017

Maybe what the web needs is an official component model that works on top of DOM (like Vue, React, etc), not in the DOM (Custom Elements are part of DOM, not on top of it).

Suppose we had something like a way to use selectors to associate components with DOM elements, officially, without creating anything that extends HTMLElement.

Maybe this is a good use-case for the is="", not for extension, but for association of logic. There would be the element instance, and a separate instance of the class associated by is="" that doesn't extend from (should not) window.Node.

Or perhaps we just need an official declarative way of doing what jQuery has been doing for years. F.e.

F.e., let's take a div, and let's assign many behaviors to it:

<div is="foo bar baz">
  ...
</div>
components.define('foo', class Foo {...})
components.define('bar', class Bar {...})
components.define('baz', class Baz {...})

Which would simply play nicely along the current Custom Elements.

Of course, logic in components could clash, as with any sort of programming. So some care would need to be taken.

Defined components might have lifecycle hooks similar to Custom Elements.

Components' is not the element, it is just the instance of the component, and perhaps the constructor received the target element as an argument.

I'm just trying to throw some ideas out there so we can overcome limitations (f.e. naming with hyphens).

While we're thinking about it, we should also figure a way toocally name components, perhaps using shadow roots, so that

root.components.define('foo', class Foo {...})
root.components.define('bar', class Bar {...})

root.components.define('baz', class Baz {...}, {
  // limit elements it can be used on
  allowedOn: ['div', 'p', '.some-class']
})

Just throwing ideas.

We just need something more modular and easier to scope, so different components can name their parts anything they want (just like with Vue or React components).

It would solve many problems in an official way.

@baocang
Copy link

baocang commented Aug 29, 2017

If typo is <siv></siv> why can't render it to HTMLUnknownElement? if typo is <siv></div> it's an syntax error. I think the best way is we can override build in element by custom element.
such as dialog, details, input, table ...

such as i have an old web application, it mostly used buildin element. if I can upgrade it without modify any code, it sounds so great.

such as we can just use build in element to development our web application. then, enhance the experience by custom element.

eg: development via <input type="date"> or <input type="file">, enhance the experience by custom input element. or dialog to custom dialog element.
this can make we get more semantics on web.

@trusktr
Copy link
Author

trusktr commented Aug 29, 2017

Another idea: something like lit-html, but native; perhaps a template tag function that is native, and processes HTML strings to create dom-diffable components. The element/component names can be defined per-template.

Throwing ideas out there. We don't necessarily need to be stick only with Custom Elements.

@baocang
Copy link

baocang commented Aug 29, 2017

@web-padawan At now, custom element named likes paper-input, iron-input, abc-input, is this really a better way to do custom element?
and the build in element such as input, in my experience, I was always make radio, checkbox, file transparent, then put it on a div tag to customize it appears.

@trusktr
Copy link
Author

trusktr commented Aug 29, 2017

such as i have an old web application, it mostly used buildin element. if I can upgrade it without modify any code, it sounds so great.

The above components idea would be great for that, and is within declarative HTML (whereas we can already do this with jQuery, but it is imperative, not declarative, and selectors allow us to associate behaviors with many elements at once).

So maybe we just need something as powerful, yet declarative, but not using selectors so that it is completely clear what behaviors/components are being used explicitly.

@web-padawan
Copy link

web-padawan commented Aug 29, 2017

@baocang I mean that parser needs an explicit direction about whether the element can be upgraded later on (and thus should not be treated as unknown) or not. Please see the spec for upgrading definition.

@trusktr condider the fact that user can disable JavaScript and DOM would still be rendered, see also explanation here.

@trusktr
Copy link
Author

trusktr commented Aug 29, 2017

eg: development via or , enhance the experience by custom input element. or dialog to custom dialog element. this can make we get more semantics on web.

This is an existing problem that people tried to solve with the is="" attribute.

But now that I think about it, this component is seems like a better alternative without the problem of the original (limited to only one class, and the class must extend the target element's native interface).

@baocang
Copy link

baocang commented Aug 29, 2017

@web-padawan I know about the spec. But why we can't config it in manfest or other way to tell browser we needs custom the buildin element? Why some thing jQuery can do, many developer can do, W3C can't?

I can enhance the input by jquery only one line code`$('input').enhance();

but with webcompoennts, I needs change input to hrlink-input, when i have more than 100 forms, this is not an easy job。

and if i use some element likes paper-calendar, and days after, customer likes abc-calendar, is this change so easy for a large form based application

If we have no way to change it, I will bear it. If we can change it,why don‘t do it?

By the below reason, why W3C no way to define a custom element without javascript,
just for decoration & data binding?Is means Custom Element means Javascript Component?
About this kind of Custom Element, without performance, where better than the jQuery way?
So i think custom element may not yet be completed.
And i believe that in the future,custom element will make the web more better than now.

condider the fact that user can disable JavaScript and DOM would still be rendered

@trusktr
Copy link
Author

trusktr commented Aug 29, 2017

I can enhance the input by jquery only one line code`$('input').enhance();

The thing is, Custom Element means you MUST extend a class. This isn't the same with jQuery, and this is the reason you are experiencing difficulty.

The web may need a NON-extending form of components.

condider the fact that user can disable JavaScript and DOM would still be rendered, see also explanation here.

That's fine, that is also the graceful fallback behavior that users of the current is="" attribute want. They also don't need to extend elements, they just need to add functionality. (See that long thread). So I think this component is a good way to achieve that without the complications that the other long thread is about.

A non-extending way to associate JS behavior is much simpler to implement, it is just attaching logic to some elements.

We could also make it selector based:

components.define('.nav-link', class {...})

But that might be too heavyweight, needing selectors to be fired on every DOM change.

Maybe a native API that allows us to pass the same component classes to act in a NodeList would be great, and we'd be one more step closer to what jQuery has already proven over and over works, for the non-declarative folks:

components.create(document.querySelectorAll('.nav-link'), 'foo')
// or similar

using the defined component by name there. This imperatively adds foo to all the selected elements' is="" attribute.

And boom, we have an official way to augment any DOM without all those problems that seem to be related to extending and element's class in that other long thread. In many cases, we just need to manipulate an element, we do that actually need this to be the element if something else like passing the element into the constructor works.

We can even pass it into all the lifecycle methods, and then allow people to create Singleton components where only one instance is made, and lifecycle hooks get passed the element to operate on:

components.define('foo', class {
  connectedCallback(el) {
    // do something with the connected element.
  }
}, {
  singleton: true
})

This idea is much more desirable than the current is="" attribute!

@trusktr
Copy link
Author

trusktr commented Aug 29, 2017

The concept is: we learn from jQuery and other libs, and we make official ways to enhance DOM without being required to extend specific elements.

This component idea is interesting, because it would still be possible to make shadow-dom based components with them, without extending the manipulated elements.


The nice thing about Vue and React, for example, is that virtual JavaScript components map to DOM output. That is an interesting concept, and I don't see why we can't also explore a native version of that.

It doesn't have to be based on dom-diffing, for example see Turbine for a clean non-diff way of mapping state changes to DOM.

@trusktr
Copy link
Author

trusktr commented Sep 6, 2017

Sorry, I took this issue slightly off topic by moving from naming to the component idea I described. I've made a new issue for the component idea here: #662

@wiredearp
Copy link

wiredearp commented Sep 6, 2017

What @milieuChris said, this is really a namespace problem at the core and the technology that would allow us to "name things locally in any way we chose" was called XSLT (or XQuery or XProc to suit your needs). Developers didn't "want" this for various suspect reasons and without any such "response filter" mechanisms we are left to hardcoding our HTML directly in the output, reminding ourselves all this time that the "X" in these acronyms would stand for "extensible". It may not be the custom elements you want, but it is the custom elements we deserve and it is the custom elements we need: At least the resulting syntax is very explicit about the use magic it involves.

There's no reason why a high level framework cannot be rigged to output <form> as <my-form> when it can already render <MyForm> as a <form> (@baocang), so I'm still lacking some motivation for introducing this potentially confusing behavior into the one specification we have left :/

See also #634 for plausible solution to hyphen-free components that doesn't reinvent the wheel.

@Jamesernator
Copy link

@wiredearp XSLT is very heavyweight from what I've seen of it, realistically I'd rather just a minimal tool for choosing names e.g.:

<import src="./my-web-component.???" as="my-component-name" />

<!-- my-component-name would be strictly scoped to this document not
     other documents (not even shadow roots) that way we can be certain
     that there's never any name collisions

     There'd probably be a `document.customElements.define` or something
     like that for scoping elements to a specific document in this idea
-->
<my-component-name>...</my-component-name>

With that sort've approach I don't see any reason you couldn't permit hyphen-less names as well (as long as they're document scoped):

<import src="./my-progress-component.???" as="progress" />

<!--- The import would shadow the outer progress but only this document
      can actually observe that, before upgrading it'd probably just appear
      as a regular progress element
-->
<progress>My progress content</progress>

Of course this idea has the wider issue that there's no canonical way to distribute a Custom Element (given that WebKit doesn't want to implement <link rel="import"...) so that would need to be added for this to even make sense.

Maybe something like (yes this idea is basically just ES import/export in HTML instead):

<template id="content">
    <link rel="stylesheet" href="./fizz-buzz.css">
    ...
</template>

<!-- Basically just `<script type="module"` except that it's obviously
     assigned extra meaning in the context of custom elements
-->
<script type="export">
    export default class MyElement extends HTMLElement {
        constructor() {
            super()
            // ... Clone template[id="content"].content etc here
        }
    }
</script>

<!-- And in another file -->
<import src="./my-element.html" as="foo" />

<foo></foo>

This would arguably be even nicer with the proposed html modules from that issue e.g.:

// component.js
import content from "./content.html" as DocumentFragment

// Given that Custom Elements *require* JavaScript to define them why
// not make that what's imported to register them:
export default class MyElement extends HTMLElement {
    constructor() {
        super()
        const shadowRoot = this.attachShadow({ mode: 'open' })
    }
}
<import src="./component.js" as="my-component-name" />

// component.js would be `import`-ed then `document.customElements.define`
// would be called on the resulting module

@treshugart
Copy link

@Jamesernator fwiw we've been spiking some ideas around a single-file-component structure using as in https://github.com/skatejs/wc-parser. I like your suggestion about using HTML modules. It might be simple to try and proof of concept this within the mentioned parser.

@nektro
Copy link

nektro commented Oct 11, 2017

From the Custom Elements spec: https://www.w3.org/TR/custom-elements/#valid-custom-element-name

They contain a hyphen, used for namespacing and to ensure forward compatibility (since no elements will be added to HTML, SVG, or MathML with hyphen-containing local names in the future).

@matthew-dean
Copy link

matthew-dean commented Nov 2, 2017

IMHO the requirement of hyphenated names for custom elements is like requiring underscore-prefixed variable names in JavaScript in order to declare const. And the namespacing-collision thing is kind of the same argument. I'm sure it's possible there were JS libraries who declared Map as an object name before that was introduced, yet there's no restriction there on what people can call things because of collision fear. The language changes over time, we all get that. Let developers accept the risk and define a spec that just supports whatever you want to call things. If developers think the risk of un-hyphenated names is too high, THEY WON'T USE THEM. There's no reason such a requirement should be part of the spec.

The convenience of hyphen-less elements greatly outweighs the down-the-road concern that some element with the same name will be introduced. I agree it's part of what makes Vue so easy-to-use and keeps templates concise.

@nektro
Copy link

nektro commented Nov 2, 2017

It's the same in JavaScript too. It's always been suggested to not use the global scope or directly access native prototypes. For instance, instead of adding Array.prototype.map() underscore.js uses _.map(), and jQuery has $() since document.querySelector() was later added.

@trusktr
Copy link
Author

trusktr commented Nov 4, 2017

If we had a way to scope element names, the problem could be solved. But I can't yet imagine how to polyfill a proposed solution, because the solution would have to somehow prevent the global customElements registry from working inside Shadow roots. Perhaps a new customElements_sample global registry would need to be created, where Custom Elements and scoped per-shadow-root naming are implemented in entirety as a polyfill.

@nektro
Copy link

nektro commented Nov 4, 2017

I don't exactly what you mean by you want to scope custom elements. They already are in the sense that custom elements are only available if you define them in your document. Scoping them per-shadow root seems a bit overkill imo as custom elements seem like they were more designed for the main document but every developer is free to do as they please. Which wraps back to the hyphen issue. The web as it stands right now is all about forwards compatibility. The lack of hyphens in custom element names is simply a contract between the nice folks over at whatwg/html and us site developers that the tags they make and the tags we make are in a different space; thus ensuring a tag you make today isn't going to conflict with an official element added later on.

@krieven
Copy link

krieven commented Nov 8, 2017

I think there is a lot of use cases for Custom Elements, but defining all range of components in one namespace - is not good idea for large enterprize apps. I belive - the DOM is the better framework for web development, but it provides not all what we need - we need just native way for combining it all together and hide implementation in modules. Custom Elements should be local inside HTML module as local variables, functions and classes in JS modules to avoid name conflicts.
I have my short solution of this problem - it is that i expected from Web Components ...
It may looks naive but is working.

@nektro
Copy link

nektro commented Nov 8, 2017

@vitalydmitriev1970 your comment isn't really related to the hyphen issue as there are no namespaces in custom elements. As far as making custom elements more declarative, there is Polymer as well as the project you made and many more.

@Jamesernator
Copy link

@trusktr Just in response to a couple things from the other thread that are more relevant here.

Just like with variable shadowing in practically any programming language

The thing is it's more like variable reassignment given that if the tag already has a value it somehow has to be assigned. This isn't unique to global tags in document, even if a tag is part of the shadow DOM if behavior of the tag changes after the element has been filled then there's a period of standard DOM behavior.

then, who cares if the browser introduces a new element later

And this is the thing I'm getting at is depending on the behavior of this new HTML <magic> tag you might either not notice at all, or perhaps it's a metadata tag that just happens to have a name collision with your tag which changes some semantics drastically (e.g. something like <base> which changes whole other parts of the HTML algorithm).

Now detecting usage of this sort've thing is improving with browser efforts so it might be that WHATWG can just ask browser vendors to detect usage of a certain word if they want to add new tags so it might not be that risky in practice.

Sometimes I do something dumb like just to get around the limitation and keep the single element, which is awkward.

Trailing dashes are valid in custom element names so you can avoid cutting words by using <stupid->/<link-> instead for now which is still an improvement if hyphen-less never happens.


ASIDE

Most uses of custom elements I've seen don't bother to use custom attribute names and just use single words which risk clashing with future global attributes (e.g. id-like). So perhaps developers don't really think the risk is that high.

ASIDE ASIDE

Interesting vue even goes so far as to abuse technically invalid attribute names like @click="myHandler" to add special vue behavior (even though usage of such attributes is very limited). So this indicates even more that developers aren't too concerned about risks introduced by invalid HTML that could break in future by changes to the HTML spec (although common usage ultimately just makes it impossible for such extensions to be added to HTML more so than breaking consumers).

@trusktr
Copy link
Author

trusktr commented Feb 13, 2018

@nektro

They already are [scoped] in the sense that custom elements are only available if you define them in your document.

Correct me if I'm wrong, but a vast majority of web applications consist of a single document. That argument there is like trying to convince React team to force everyone to globally register all components by name, per document, which would result in a huge storm of frustrated developers.

We need scoping inside a single application, and because most applications consist of a single document, we need scoping inside of documents, and shadow roots are the obvious unit of encapsulation for that (for all other Web Component encapsulation).

thus ensuring a tag you make today isn't going to conflict with an official element added later on.

That's not going to happen in shadow roots. Once a scoped name is defined in a shadow root, introducing a new native builtin will do absolutely nothing because the root's definition of the element will continue to be the same, because it shadows the outer scope.

This is the same in just about all programming languages.

@Jamesernator

even if a tag is part of the shadow DOM if behavior of the tag changes after the element has been filled then there's a period of standard DOM behavior.

The simple good practice of defining the element names before rendering the DOM content would be useful here.

There's possible ways to solve it for everyone: Maybe overrides can only be defined before any such elements exist in the root, otherwise a helpful error can be thrown, and the define() call fails. This will force people to design custom elements where all Elements that will be inside the shadow root are defined before ever being placed in the DOM.

@annevk
Copy link
Collaborator

annevk commented Feb 18, 2018

I'm going to close this since hyphen-less names were considered and rejected as they would conflict with future built-in element names. And a unified scheme that both built-in elements and custom elements could use was also considered, but nobody could figure out how to make it work.

@brandondrew
Copy link

The lack of hyphens in custom element names is simply a contract between the nice folks over at whatwg/html and us site developers that the tags they make and the tags we make are in a different space; thus ensuring a tag you make today isn't going to conflict with an official element added later on.

You could still have that contract and allow custom elements without hyphens. Anyone who wants the safety of the contract would use hyphens, and anyone who wants to take their chances could do without them.

But let's consider what the worst thing is that could happen: if I introduce (for example) a <string> custom element, and use it, and then an official <string> element is added to browsers, my site continues to use my custom element instead of the new official element (since custom elements should always override official ones!) How is that bad? Everything continues to work as I expect. I don't see any downsides at all.

@EisenbergEffect
Copy link

I'm no expert, but it seems that enabling custom elements to override built-ins could be a security problem.

@bathos
Copy link

bathos commented May 14, 2023

A builtin element becoming another underived element underfoot (as opposed to upgrading to a more-derived custom element that still has the same native brand/slots) doesn’t seem plausible or desirable. The number of new HTML behaviors that would need to be defined and implemented to account for the states this would make possible which hadn’t been before seems enormous. Despite the low value of most such possible states for users and developers, if they become possible at all, they must have defined behavior. For example, what happens when a builtin ceases to be that builtin during script execution when...

  • it’s an <img> or <link> with an associated ongoing fetch?
  • it’s an <iframe> with an associated ongoing navigation? what happens to its nested browsing context / document lifecycle?
  • it’s a <form> losing its formness in reaction to its own submit event being dispatched?

Even in non-upgrade cases, consider all the implications for parsing if a script could have previously redefined:

  • <base>
  • <meta>
  • <body>
  • <script>
  • <noscript>
  • <template>
  • etc

Also, ECMAScript objects branded with cross-realm slots cannot suddenly stop having those slots. While technically it wouldn’t violate a language-level invariant, it is an invariant-in-practice for all branded intrinsic and host objects and must remain so.

I too yearn for hyphenlessness but I think the right call was made :)

@blueforesticarus
Copy link

The lack of hyphens in custom element names is simply a contract between the nice folks over at whatwg/html and us site developers that the tags they make and the tags we make are in a different space; thus ensuring a tag you make today isn't going to conflict with an official element added later on.

This is the whole problem. I should be able to build off of html as a format, and have those extensions be first class, not some weird tacked on thing. They are custom elements from the BROWSERS point of view, not the documents point of view. All the good things about HTML come from it being a semantic data format. Sometimes I need more semantics than the built-in set, and I should be able to add a tag to represent those, with a semantic name.

The JS custom element thing is just display logic. And view should be written to conform to the model not the other way around.

I suggest the "nice folks over at whatwg/html" put the elements they make in a namespace, and let me have the default one.

@brandondrew
Copy link

I'm no expert, but it seems that enabling custom elements to override built-ins could be a security problem.

If you have no description of how the ability to override tags is a security risk, then how can anyone take your claim seriously? Do you think that all custom tags are a security risk? Why would custom tags with no hyphens suddenly create a risk?

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

No branches or pull requests