From 305ff9e4f93fc72cfebedc54732757df06c73bc3 Mon Sep 17 00:00:00 2001 From: Chad Hietala Date: Mon, 12 Mar 2018 11:03:02 -0700 Subject: [PATCH 1/4] Attribute and property rationalization --- ...0000-attribute-property-rationalization.md | 115 ++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 text/0000-attribute-property-rationalization.md diff --git a/text/0000-attribute-property-rationalization.md b/text/0000-attribute-property-rationalization.md new file mode 100644 index 0000000000..5904d2883f --- /dev/null +++ b/text/0000-attribute-property-rationalization.md @@ -0,0 +1,115 @@ +- Start Date: 2018-02-20 +- RFC PR: (leave this empty) +- Ember Issue: (leave this empty) + +# HTML Attribute and Property Rationalization + +## Summary + +This RFC's goal is to rationalize how to set attributes and properties of an `HTMLElement` as defined by a template. Today, we have a set of implicit rules of when to set an attribute using `setAttribute` and when we simply set a property on the element. For example: + +```hbs +
+

{{firstName}}

+ + +
+``` + +Will result in the following DOM operations if the context is `{ color: "red", firstName: "Chad" }`: + +```js +let div = document.createElement('div'); +div.setAttribute('class', 'red'); + //
+let p = document.createElement('p'); +p.setAttribute('class', 'preview'); +let name = document.createTextNode('Chad'); +p.appendChild(name); +div.appendChild(p); + //

Chad

+let input1 = document.createElement('input'); +input1.value = 'Chad'; +input1.onkeydown = () => {...}; +div.appendChild(input1); + //
+ //

Chad

+ // + //
+let input2 = document.createElement('input'); +input2.setAttribute('value', 'Submit'); +input2.setAttribute('type', 'button'); +input2.onclick = () => {...}; +div.appendChild(input2); + //
+ //

Chad

+ // + // + //
+``` + +This illustrates the setting inconsistencies based on the attribute name and if the value is dynamic or not. To remove these inconsistencies we would like to move to the [HTML semantics](https://html.spec.whatwg.org/multipage/dom.html#attributes) by always setting attributes. At the same time we will introduce a `{{prop}}` and `{{on}}` modifier for explicitly setting properties and events on `HTMLElement`s. The above template would be transformed to look like the following to retain the semantics of today: + +```hbs +
+

{{firstName}}

+ + +
+``` + +By moving to these new semantics we will shore up long standing confusion in this area, unify HTML serialization and DOM construction, and open the door for first class support for custom elements. + +## Motivation +This proposal: + +- brings clarity and [addresses confusion](#appendix-a) as how to set a property on an element +- enables the usage of [custom elements](https://custom-elements-everywhere.com/) +- fixes HTML serialization issues for server-side rendering +- removes the need for `TextSupport` mixin for supporting input events +- removes the need for `{{textarea}}` and `{{input}}` + +## Detailed design + +To move to this more explicit syntax in a backwards compatable we will convert well-known properties to use the `{{prop}}` and `{{on}}` modifiers via a codemod and retain the runtime setting rules for `attributeBindings`. + +### Transforming Through Codemod +Due to the declarative nature of HTML we are able to see exactly which attributes are being set on which elements. This allows us to understand where we need to set properties and where we can safely rely on setting attributes. Using the list of [HTML attributes](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes) and [WAI-ARIA attributes](https://www.w3.org/TR/wai-aria-1.1/) we can then determine which attributes in templates need to be converted to use either `{{prop}}` or `{{on}}`. + +### Runtime Rules +With Ember Components we have the notion of `attributeBindings` to set attributes on the wrapping element as defined by the `tagName` on the component class. For this case we will continue to use the setting rules we have today. Notably, [Glimmer Components](https://glimmerjs.com/guides/templates-and-helpers) have adopted the "Outer HTML" semantics long ago and the experience has been very positive. This means that when Glimmer Components become available in Ember they would be covered by the codemod as described above. + +Furthermore, we would deprecate the usage of `{{textarea}}`, `{{input}}`, and the `TextSupportMixin`. This will require a deprecation guide for showing developers how to convert to use these new primitives. + +## How we teach this +The vast majority of the time you want to be setting attributes on elements. The cases in which you need to set properties are when you are setting a dynamic value to an element that takes user input e.g. ``, `