-
Notifications
You must be signed in to change notification settings - Fork 377
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
[idea] Ability to define Custom Element attributes (and optionally enable getters/setters for those attributes). #517
Comments
The Alternatively, it could be a method: class MyElement extends HTMLElement {
constructor() {
super()
// optional
this.defineAttributes([
"foo",
"bar",
])
// optional, but does nothing if no attributes are defined.
// It's opt-in, otherwise setAttribute/getAttribute work as before, backwards
// compatible with current spec.
this.enableAttributeSettersGetters()
}
// if "foo" attribute was specified during creation (HTML engine would check
// this after the constructor call), then it will use (if present) the
// specified matching getter/setter on the instance to get/set values for the
// attribute. This could be nice because it would mean that
// this.getAttribute('foo') could return an object instead of a string, and
// this.setAttribute('foo', ...) could accept anything, not just strings!
set foo(value) { ... }
get foo() { ... }
}
// ...
let el = document.querySelector('...')
console.log(el.getDefinedAttributes()) But I think I like the |
The behavior of the |
The current limitation in Skate.js, X-Tag, and Polymer is that |
We specifically discourage people from adding attributes inside a constructor because no builtin elements add attributes during construction. As such, this is somewhat of an anti-pattern in custom elements land. |
@trusktr Skate already provides a way to do something similar to what you want. I don't think allowing non-string values to go to, or come back from Skate offers an API to Not sure exactly if this answers your questions, but if you have a question about Skate specifically, please feel free to raise it there. |
It may be true now, but the spec can be modified. That's not what the element's currently do, but that could be what they do in the future, as part of what explains how things work (following the Extensible Web Manifesto)...
That seems like a performance bottle neck when it comes to passing data from outer component to inner component, and so on. It'd be nice for anything that is passed via attributes to remain exactly as it is until it gets to where it needs to be (the thing being passed might flow into some inner, inner tree). What I'm imagining is that component layers might go deep in a big application (layers of nested Shadow DOM trees, and possibly with encapsulated component registration as in #488). Imagine this horrible performance scenario:
Doesn't that sound bad? In general, any framework or platform (in this case Chrome, Firefox, Edge, Safari) should aim for not using serialization/deserialization until the very last moment, or not at all. Nothing should need to be serialized until necessary (f.e. DevTools may need to show the values in the element inspector, but if DevTools are never used, serialization/deserialization may never even need to happen). Serialization/deserialization should only need to happen when some data needs to be displayed as text unless the data is text, or when saving/loading state from somewhere like a backend database. Serialization/deserialization would be great for server-side rendering, but should be completely avoided until the last minute when it is needed. The average web UI today doesn't not need serialization/deserialization except for when reading from HTML directly (i.e. the initial parsing of HTML coming from a server, using In contrast to that Idea, serialization/deserialization is the current default behavior, no matter what the use case, and in my opinion that's awful because it requires unnecessary performance costs. I'd like to see HTML interfaces being used to create immersive 3D experiences (games or other 3D applications). This is beginning to happen, and as an author of 3D content I would highly appreciate the performance improvement that this change would bring. |
Explain what? That's just not how HTML works. When you create a HTML element, it doesn't have any attributes until a parser, DOM API, etc.. adds one. |
With this change, it'd make the use of things like JSX with native DOM API possible. Imagine JSX compiling to a native DOM API instead of a bunch of the React-like implementations that currently exist. Many of those libraries listed there give us the ability to pas around plain JavaScript data without serializing until the very end when the libraries have to generate real DOM. It would be absolutely great to remove that serialization step. Imagine if the let element = document.createElement('div', {
attributes: {
id: "someDiv",
array: [1,2,3]
},
children: [
document.createElement('span', {children: [
document.createTextNode('hello')
]})
]
}) This would open the doors to JSX-like libraries used with native DOM API, so the above could be written as: let element = (
<div id="someDiv" array={[1,2,3]}>
<span>hello</span>
</div>
) Notice how the array literal would get passed without performance loss from serialization. |
I know, which is why I've made the overall suggestion of this issue. I've mentioned above that
Currently, the DOM API around HTML attributes expects everything to be serialized/deserialized to/from strings 100% of the time if HTML attributes are to be used for passing data (which will happen betweenWeb Components). What I'm suggesting is that serialization/deserialization does not need to happen 100% of the time, and in many cases it can be entirely avoided depending on the needs of the application. For example, I imagine I'll want to serialize things when saving to a server, and would want to deserialize things when receiving the initial HTML payload from a server. But, as far as dynamic application go ("single-page apps", "ajax", client-side routing, etc), serialization and deserialization during runtime are completely unnecessary. I believe that the current state of strings-only for attributes stem from the old days when everything was server-side rendering of HTML, so strings were fine. But, we're in a new era where single-page apps allow for dynamic experiences, and to make this change will help improve those experiences. |
Opened #519 specifically about attributes accepting anything besides strings. |
Sure, performance could degrade but what you want isn't possible without overriding |
@treshugart HTML elements are the standard that everyone uses. You've proposed a workaround, but it's not really a solution because libraries (React, Angular, virtual-dom, Riot.js, etc) can't guess what properties a Custom Element uses. f.e., React won't know which property to use for Now that we'll be writing ES6 classes, there's no reason why |
@trusktr What I was saying was more akin to what Seb was saying in #519: prefer properties, in general. IMO a better solution would be for HTML, when parsed, to take the attributes and apply them as properties. You may have a dash-case / camelCase problem then, but that's easily solvable by applying the same property descriptor to the dash-case version and the camelCase version. |
I think I like that too, but is that backwards compatible? Current native elements don't all do that, so then we'd be adding a rule that doesn't explain existing technology properly (web manifesto) because existing elements don't follow it, and we can't change those elements to follow it because backwards compatibility. So, what can be the backwards-compatible solution? Ability to specify certain attributes as properties/getters/setters agrees with web manifesto because then for existing native elements that don't have the properties we can just say that those elements just didn't define them as per this new API. |
Let's close this. It appears to be something that is better done with a library. |
Skate.js, X-Tags, and Polymer all have a feature that allows a Web Component creator to specify attributes and associated setters/getters.
I think this is a really good idea because it makes things easy, but more importantly, it can enable integrations with other libraries more easily.
For example, suppose we can specify attributes somehow. Imagine a setter/getter on the HTMLElement prototype possibly:
This has two major benefits from a programming perspective:
jQuery
would be able to reliably determine which attributes are explicitly defined on an element, and would therefore be able to automatically create getter/setter proxies. For example, this would allow the following jQuery code to be possible without string conversion (assuming jQuery takes advantage of a such a feature when/if it becomes reality):js // assign an attribute value to all selected elements! $('#awesome-element').attr('hello', new AnythingThatIsNotAString()) // or $('#awesome-element').hello = new AnythingThatIsNotAString()
I think that right there lends to some powerful new possibilities and could be one way to avoid having to convert everything to/from strings! Of course, things like Chrome's element inspector would then ultimately call
toString
on the things returned from the attribute setters/getters, so we might see things like the following when care is not taken:But, this presents the opportunity for component developers to define
toString
methods! Furthermore, just like now, developers can continue to accept string input (that may match theirtoString
output format), which would be really cool!! This even presents an opportunity for DevTool to possibly show objects instead of strings (f.e. right click > "Show value in console") and then the non-string value can be inspected!There's performance benefits!
The text was updated successfully, but these errors were encountered: