Skip to content

Commit

Permalink
Update customized built-in elements is="" interaction
Browse files Browse the repository at this point in the history
This follows the DOM changes in whatwg/dom#566,
and is part of fixing whatwg#3402.

The normative changes are to the serialization algorithm, which now
writes out the element's is value as its is="" attribute, if no actual
is="" attribute is present. The rest of the changes are to introductory
text about customized built-in elements.

Tests: web-platform-tests/wpt#9508
  • Loading branch information
domenic authored and Alice Boxhall committed Jan 7, 2019
1 parent 8dea671 commit 644a8f0
Showing 1 changed file with 82 additions and 8 deletions.
90 changes: 82 additions & 8 deletions source
Original file line number Diff line number Diff line change
Expand Up @@ -65658,8 +65658,8 @@ document.body.appendChild(flagIcon)</pre>
what element interface it extends, as many elements share the same interface (such as
<code>q</code> and <code>blockquote</code> both sharing <code>HTMLQuoteElement</code>).</p>

<p>To use our <span>customized built-in element</span>, we use the <code
data-x="attr-is">is</code> attribute on a <code>button</code> element:</p>
<p>To construct our <span>customized built-in element</span> from parsed HTML source text, we use
the <code data-x="attr-is">is</code> attribute on a <code>button</code> element:</p>

<pre>&lt;button is="plastic-button">Click Me!&lt;/button></pre>

Expand All @@ -65668,20 +65668,29 @@ document.body.appendChild(flagIcon)</pre>
me?&lt;/plastic-button></code> will simply create an <code>HTMLElement</code> with no special
behavior.</p>

<p>If you need to create a type-extended element programmatically, you can use the following form
of <code data-x="dom-Document-createElement">createElement()</code>:</p>
<p>If you need to create a customized built-in element programmatically, you can use the following
form of <code data-x="dom-Document-createElement">createElement()</code>:</p>

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

<p>And as before, the constructor will also work:</p>

<pre>const plasticButton2 = new PlasticButton();
console.log(plasticButton2.localName); // will output "button"
console.log(plasticButton2.getAttribute("is")); // will output "plastic-button"</pre>
console.log(plasticButton2.localName); // will output "button"
console.assert(plasticButton2 instanceof PlasticButton);
console.assert(plasticButton2 instanceof HTMLButtonElement);</pre>

<p>Notably, all the of the ways in which <code>button</code> is special apply to such "plastic
buttons" as well: their focus behavior, ability to participate in <span
<p>Note that when creating a customized built-in element programmatically, the <code
data-x="attr-is">is</code> attribute will not be present in the DOM, since it was not explicitly
set. However, <a href="#attr-is-during-serialization">it will be added to the output when
serializing</a>:</p>

<pre>console.assert(!plasticButton.hasAttribute("is"));
console.log(plasticButton.outerHTML); // will output '&lt;button is="plastic-button">&lt;/button>'</pre>

<p>Regardless of how it is created, all the of the ways in which <code>button</code> is special
apply to such "plastic buttons" as well: their focus behavior, ability to participate in <span
data-x="concept-form-submit">form submission</span>, the <code
data-x="attr-fe-disabled">disabled</code> attribute, and so on.</p>

Expand Down Expand Up @@ -109718,6 +109727,14 @@ document.body.appendChild(text);
<code data-x="dom-Document-createElement">createElement()</code>, <var>tagname</var> will be
lowercase.</p>

<p>If <var>current node</var>'s <span data-x="concept-element-is-value"><code
data-x="">is</code> value</span> is not null, and the element does not have an <code
data-x="attr-is">is</code> attribute in its attribute list, then append the string "<code
data-x=""> is="</code>", followed by <var>current node</var>'s <span
data-x="concept-element-is-value"><code data-x="">is</code> value</span> <span
data-x="escaping a string">escaped as described below</span> in <i>attribute mode</i>,
followed by a U+0022 QUOTATION MARK character (&quot;).</p>

<p>For each attribute that the element has, append a U+0020 SPACE character, the <span
data-x="attribute's serialized name">attribute's serialized name as described below</span>, a
U+003D EQUALS SIGN character (=), a U+0022 QUOTATION MARK character (&quot;), the
Expand Down Expand Up @@ -109960,6 +109977,63 @@ Hello.&lt;/pre></pre>
data-x="">Hello.</code>".</p>
</div>

<p id="attr-is-during-serialization">Because of the special role of the <code
data-x="attr-is">is</code> attribute in signaling the creation of <span data-x="customized
built-in element">customized built-in elements</span>, in that it provides a mechanism for parsed
HTML to set the element's <span data-x="concept-element-is-value"><code data-x="">is</code>
value</span>, we special-case its handling during serialization.This ensures that an element's
<span data-x="concept-element-is-value"><code data-x="">is</code> value</span> is preserved
through serialize-parse roundtrips.</p>

<div class="example">
<p>When creating a <span>customized built-in element</span> via the parser, a developer uses the <code
data-x="attr-is">is</code> attribute directly; in such cases serialize-parse roundtrips work fine.</p>

<pre>&lt;script>
window.SuperP = class extends HTMLParagraphElement {};
customElements.define("super-p", SuperP, { extends: "p" });
&lt;/script>

&lt;div id="container">&lt;p is="super-p">Superb!&lt;/p>&lt;/div>

&lt;script>
console.log(container.innerHTML); // &lt;p is="super-p">
container.innerHTML = container.innerHTML;
console.log(container.innerHTML); // &lt;p is="super-p">
console.assert(container.firstChild instanceof SuperP);
&lt;/script></pre>

<p>But when creating a customized built-in element via its <span data-x="custom element
constructor">constructor</span> or via <code
data-x="dom-Document-createElement">createElement()</code>, the <code data-x="attr-is">is</code>
attribute is not added. Instead, the <span data-x="concept-element-is-value"><code
data-x="">is</code> value</span> (which is what the custom elements machinery uses) is set
without intermediating through an attribute.</p>

<pre>&lt;script>
container.innerHTML = "";
const p = document.createElement("p", { is: "super-p" });
container.appendChild(p);

// The is attribute is not present in the DOM:
console.assert(!p.hasAttribute("is"));

// But the element is still a super-p:
console.assert(p instanceof SuperP);
&lt;/script></pre>

<p>To ensure that serialize-parse roundtrips still work, the serialization process explicitly
writes out the element's <span data-x="concept-element-is-value"><code data-x="">is</code>
value</span> as an <code data-x="attr-is">is</code> attribute:</p>

<pre>&lt;script>
console.log(container.innerHTML); // &lt;p is="super-p">
container.innerHTML = container.innerHTML;
console.log(container.innerHTML); // &lt;p is="super-p">
console.assert(container.firstChild instanceof SuperP);
&lt;/script></pre>
</div>

<p><dfn id="escapingString">Escaping a string</dfn> (for the purposes of the algorithm above)
consists of running the following steps:</p>

Expand Down

0 comments on commit 644a8f0

Please sign in to comment.