कस्टम एलिमेंट के साथ काम करना

परिचय

वेब पर एक्सप्रेशन की बहुत कमी है. इसका मतलब समझने के लिए, Gmail जैसे "आधुनिक" वेब ऐप्लिकेशन पर एक नज़र डालें:

Gmail

<div> सूप में कुछ भी आधुनिक नहीं है. इसके बावजूद, हम वेब ऐप्लिकेशन इसी तरह बनाते हैं. यह बहुत बुरा है. क्या हमें अपने प्लैटफ़ॉर्म से ज़्यादा की मांग नहीं करनी चाहिए?

सेक्सी मार्कअप. चलिए, इसे एक गेम बनाते हैं

एचटीएमएल हमें दस्तावेज़ बनाने के लिए एक बेहतरीन टूल देता है. हालांकि, इसमें एचटीएमएल स्टैंडर्ड में बताए गए एलिमेंट तक ही शामिल हैं.

अगर Gmail के लिए मार्कअप खराब नहीं था, तो क्या होगा? क्या होता अगर यह सुंदर होता:

<hangout-module>
    <hangout-chat from="Paul, Addy">
    <hangout-discussion>
        <hangout-message from="Paul" profile="profile.png"
            profile="118075919496626375791" datetime="2013-07-17T12:02">
        <p>Feelin' this Web Components thing.
        <p>Heard of it?
        </hangout-message>
    </hangout-discussion>
    </hangout-chat>
    <hangout-chat>...</hangout-chat>
</hangout-module>

कितना अच्छा है! यह ऐप्लिकेशन भी काफ़ी कारगर साबित होता है. यह मतलब, समझने में आसान, और सबसे अच्छी बात है कि इसे बनाया जा सकता है. आने वाले समय में, इसके डिक्लेरेटिव रीबोन की जांच करके मुझे/आपको पता चल जाएगा कि यह क्या करता है.

शुरू करना

कस्टम एलिमेंट की मदद से वेब डेवलपर, नए तरह के एचटीएमएल एलिमेंट तय कर सकते हैं. यह स्पेसिफ़िकेशन, वेब कॉम्पोनेंट के तहत आने वाले कई नए एपीआई प्राइमिटिव में से एक है. हालांकि, यह सबसे अहम है. कस्टम एलिमेंट की मदद से अनलॉक की गई सुविधाओं के बिना, वेब कॉम्पोनेंट का कोई मतलब नहीं है:

  1. नए एचटीएमएल/डीओएम एलिमेंट तय करें
  2. ऐसे एलिमेंट बनाना जो दूसरे एलिमेंट से जुड़े हों
  3. कस्टम फ़ंक्शन को एक टैग में लॉजिक के हिसाब से बंडल करना
  4. मौजूदा डीओएम एलिमेंट के एपीआई को बढ़ाएं

नए एलिमेंट रजिस्टर करना

कस्टम एलिमेंट, document.registerElement() का इस्तेमाल करके बनाए जाते हैं:

var XFoo = document.registerElement('x-foo');
document.body.appendChild(new XFoo());

document.registerElement() का पहला आर्ग्युमेंट, एलिमेंट का टैग नाम होता है. नाम में डैश (-) होना चाहिए. उदाहरण के लिए, <x-tags>, <my-element>, और <my-awesome-app> सभी मान्य नाम हैं, जबकि <tabs> और <foo_bar> सभी मान्य नाम नहीं हैं. इस पाबंदी की मदद से, पार्सर को कस्टम एलिमेंट को सामान्य एलिमेंट से अलग करने में मदद मिलती है. साथ ही, यह एचटीएमएल में नए टैग जोड़ने पर, आगे के साथ काम करने की सुविधा भी देता है.

दूसरा आर्ग्युमेंट, एक (ज़रूरी नहीं) ऑब्जेक्ट है, जो एलिमेंट के prototype के बारे में बताता है. इस जगह पर, अपने एलिमेंट में पसंद के मुताबिक फ़ंक्शन जोड़े जा सकते हैं. जैसे, सार्वजनिक प्रॉपर्टी और तरीके. बाद में इस बारे में ज़्यादा जानकारी.

डिफ़ॉल्ट रूप से, कस्टम एलिमेंट HTMLElement से इनहेरिट होते हैं. इसलिए, पिछला उदाहरण इनके बराबर है:

var XFoo = document.registerElement('x-foo', {
    prototype: Object.create(HTMLElement.prototype)
});

document.registerElement('x-foo') पर किया गया कॉल, ब्राउज़र को नए एलिमेंट के बारे में बताता है. साथ ही, कंस्ट्रक्टर के तौर पर दिखाता है, जिसका इस्तेमाल करके <x-foo> के इंस्टेंस बनाए जा सकते हैं. इसके अलावा, अगर आपको कन्स्ट्रक्टर का इस्तेमाल नहीं करना है, तो एलिमेंट को इंस्टैंशिएट करने की अन्य तकनीकों का इस्तेमाल किया जा सकता है.

एलिमेंट एक्सटेंड करना

कस्टम एलिमेंट की मदद से, मौजूदा (नेटिव) एचटीएमएल एलिमेंट के साथ-साथ अन्य कस्टम एलिमेंट भी जोड़े जा सकते हैं. किसी एलिमेंट को बड़ा करने के लिए, आपको एलिमेंट का registerElement() नाम और prototype पास करना होगा, ताकि वह उससे इनहेरिट किया जा सके.

नेटिव एलिमेंट एक्सटेंड करना

मान लें कि आप नियमित जो <button> से खुश नहीं हैं. आपको "मेगा बटन" बनाने के लिए, इसकी सुविधाओं को बेहतर बनाना है. <button> एलिमेंट को बड़ा करने के लिए, ऐसा नया एलिमेंट बनाएं जो HTMLButtonElement का prototype और एलिमेंट का नाम extends इनहेरिट करता हो. इस मामले में, "button":

var MegaButton = document.registerElement('mega-button', {
    prototype: Object.create(HTMLButtonElement.prototype),
    extends: 'button'
});

नेटिव एलिमेंट से इनहेरिट किए गए कस्टम एलिमेंट को टाइप एक्सटेंशन कस्टम एलिमेंट कहा जाता है. उन्हें HTMLElement के खास वर्शन से, "एलिमेंट X एक Y है" कहने के तरीके से इनहेरिट किया जाता है.

उदाहरण:

<button is="mega-button">

कस्टम एलिमेंट को बढ़ाना

<x-foo> कस्टम एलिमेंट को एक्सटेंड करने वाला <x-foo-extended> एलिमेंट बनाने के लिए, बस उसके प्रोटोटाइप को इनहेरिट करें और बताएं कि आपको किस टैग से इनहेरिट करना है:

var XFooProto = Object.create(HTMLElement.prototype);
...

var XFooExtended = document.registerElement('x-foo-extended', {
    prototype: XFooProto,
    extends: 'x-foo'
});

एलिमेंट के प्रोटोटाइप बनाने के बारे में ज़्यादा जानने के लिए, नीचे JS प्रॉपर्टी और तरीके जोड़ना देखें.

एलिमेंट को अपग्रेड करने का तरीका

क्या आपने कभी सोचा है कि एचटीएमएल पार्सर, नॉन-स्टैंडर्ड टैग पर क्यों फ़िट नहीं होता? उदाहरण के लिए, अगर हम पेज पर <randomtag> का एलान करते हैं, तो यह पूरी तरह से सही है. एचटीएमएल स्पेसिफ़िकेशन के मुताबिक:

माफ़ करें <randomtag>! आप स्टैंडर्ड न हैं और आपकी साइट HTMLUnknownElement से इनहेरिट की गई है.

हालांकि, कस्टम एलिमेंट के लिए ऐसा नहीं है. मान्य कस्टम एलिमेंट नाम वाले एलिमेंट, HTMLElement से इनहेरिट किए जाते हैं. आप कंसोल को सक्रिय करके इस तथ्य की पुष्टि कर सकते हैं: Ctrl + Shift + J (या Mac पर Cmd + Opt + J) और कोड की नीचे दी गई पंक्तियों में पेस्ट करें, जिससे वे true लौटाते हैं:

// "tabs" is not a valid custom element name
document.createElement('tabs').__proto__ === HTMLUnknownElement.prototype

// "x-tabs" is a valid custom element name
document.createElement('x-tabs').__proto__ == HTMLElement.prototype

अनसुलझे एलिमेंट

कस्टम एलिमेंट, document.registerElement() का इस्तेमाल करके स्क्रिप्ट से रजिस्टर किए जाते हैं. इसलिए, ब्राउज़र से उनकी परिभाषा रजिस्टर होने से पहले, उन्हें रजिस्टर किया जा सकता है या बनाया जा सकता है. उदाहरण के लिए, आपके पास पेज पर <x-tabs> का एलान करने का विकल्प है, लेकिन document.registerElement('x-tabs') को बाद में भी शुरू किया जा सकता है.

एलिमेंट को उनकी परिभाषा में अपग्रेड करने से पहले, उन्हें हल नहीं किए गए एलिमेंट कहा जाता है. ये ऐसे एचटीएमएल एलिमेंट हैं जिनका कस्टम एलिमेंट का मान्य नाम है, लेकिन उन्हें रजिस्टर नहीं किया गया है.

इस टेबल से आपको चीज़ों को व्यवस्थित रखने में मदद मिल सकती है:

नाम इनसे इनहेरिट किया गया उदाहरण
हल नहीं किया गया एलिमेंट HTMLElement <x-tabs>, <my-element>
अनजान एलिमेंट HTMLUnknownElement <tabs>, <foo_bar>

इंस्टैंशिएट करने वाले एलिमेंट

एलिमेंट बनाने की सामान्य तकनीकें, अब भी कस्टम एलिमेंट पर लागू होती हैं. किसी भी स्टैंडर्ड एलिमेंट की तरह, इन्हें एचटीएमएल में एलान किया जा सकता है या JavaScript का इस्तेमाल करके डीओएम में बनाया जा सकता है.

कस्टम टैग इंस्टैंशिएट किए जा रहे हैं

इनके बारे में एलान करें:

<x-foo></x-foo>

JS में DOM बनाएं:

var xFoo = document.createElement('x-foo');
xFoo.addEventListener('click', function(e) {
    alert('Thanks!');
});

new ऑपरेटर का इस्तेमाल करें:

var xFoo = new XFoo();
document.body.appendChild(xFoo);

एक्सटेंशन एलिमेंट को इंस्टैंशिएट करना

इंस्टैंशिएट करने वाले एक्सटेंशन-स्टाइल के कस्टम एलिमेंट, कस्टम टैग के काफ़ी करीब हैं.

इनके बारे में एलान करें:

<!-- <button> "is a" mega button -->
<button is="mega-button">

JS में DOM बनाएं:

var megaButton = document.createElement('button', 'mega-button');
// megaButton instanceof MegaButton === true

जैसा कि आपको दिख रहा है, अब document.createElement() का ओवरलोडेड वर्शन मौजूद है, जो is="" एट्रिब्यूट को दूसरे पैरामीटर के तौर पर लेता है.

new ऑपरेटर का इस्तेमाल करें:

var megaButton = new MegaButton();
document.body.appendChild(megaButton);

अब तक हमने जाना है कि ब्राउज़र को एक नए टैग के बारे में बताने के लिए document.registerElement() का इस्तेमाल कैसे किया जाता है...लेकिन इससे बहुत ज़्यादा फ़ायदा नहीं होता. प्रॉपर्टी और मेथड जोड़ें.

JS प्रॉपर्टी और मेथड जोड़ना

कस्टम एलिमेंट की सबसे खास बात यह है कि एलिमेंट की परिभाषा में प्रॉपर्टी और मेथड तय करके, एलिमेंट के साथ अपनी पसंद के मुताबिक फ़ंक्शन जोड़े जा सकते हैं. इसे अपने एलिमेंट के लिए सार्वजनिक एपीआई बनाने के तरीके के तौर पर देखें.

यहां एक पूरा उदाहरण दिया गया है:

var XFooProto = Object.create(HTMLElement.prototype);

// 1. Give x-foo a foo() method.
XFooProto.foo = function() {
    alert('foo() called');
};

// 2. Define a property read-only "bar".
Object.defineProperty(XFooProto, "bar", {value: 5});

// 3. Register x-foo's definition.
var XFoo = document.registerElement('x-foo', {prototype: XFooProto});

// 4. Instantiate an x-foo.
var xfoo = document.createElement('x-foo');

// 5. Add it to the page.
document.body.appendChild(xfoo);

बेशक, prototype बनाने के कई हज़ार तरीके हैं. अगर आपको इस तरह के प्रोटोटाइप बनाने में दिलचस्पी नहीं है, तो यहां इसी प्रोटोटाइप का छोटा वर्शन दिया गया है:

var XFoo = document.registerElement('x-foo', {
  prototype: Object.create(HTMLElement.prototype, {
    bar: {
      get: function () {
        return 5;
      }
    },
    foo: {
      value: function () {
        alert('foo() called');
      }
    }
  })
});

पहले फ़ॉर्मैट में, ES5 Object.defineProperty का इस्तेमाल किया जा सकता है. दूसरा चरण get/set का इस्तेमाल करने की अनुमति देता है.

लाइफ़साइकल कॉलबैक के तरीके

एलिमेंट अपने अस्तित्व के दिलचस्प समय में टैप करने के लिए, खास तरीके तय कर सकते हैं. इन मैथड को लाइफ़साइकल कॉलबैक कहा जाता है. हर टाइप का नाम और मकसद अलग होता है:

कॉलबैक का नाम कब कॉल किया
createdCallback एलिमेंट का एक इंस्टेंस बनाया गया
attachedCallback दस्तावेज़ में कोई इंस्टेंस डाला गया हो
detachedCallback दस्तावेज़ से कोई इंस्टेंस हटा दिया गया हो
attributeChangedCallback(attrName, oldVal, newVal) किसी एट्रिब्यूट को जोड़ा, हटाया या अपडेट किया गया

उदाहरण: <x-foo> पर createdCallback() और attachedCallback() के बारे में बताएं:

var proto = Object.create(HTMLElement.prototype);

proto.createdCallback = function() {...};
proto.attachedCallback = function() {...};

var XFoo = document.registerElement('x-foo', {prototype: proto});

लाइफ़साइकल के सभी कॉलबैक ज़रूरी नहीं हैं. हालांकि, अगर ज़रूरी हो, तो उन्हें तय करें. उदाहरण के लिए, मान लें कि आपका एलिमेंट काफ़ी जटिल है और createdCallback() में IndexedDB से कनेक्शन खोलता है. इसे डीओएम से हटाने से पहले, detachedCallback() में क्लीनअप का ज़रूरी काम करें. ध्यान दें: आपको इस पर भरोसा नहीं करना चाहिए. उदाहरण के लिए, अगर उपयोगकर्ता टैब बंद कर देता है, तो इसे ऑप्टिमाइज़ेशन के लिए संभावित हुक के तौर पर देखें.

इस्तेमाल का एक और लाइफ़साइकल कॉलबैक, एलिमेंट पर डिफ़ॉल्ट इवेंट लिसनर सेट अप करने के लिए है:

proto.createdCallback = function() {
  this.addEventListener('click', function(e) {
    alert('Thanks!');
  });
};

मार्कअप जोड़ा जा रहा है

हमने <x-foo> बनाया है और उसे JavaScript API दिया है, लेकिन यह खाली है! क्या हमें इसे रेंडर करने के लिए कुछ एचटीएमएल देना चाहिए?

यहां लाइफ़साइकल कॉलबैक काम आते हैं. खास तौर पर, हम किसी एलिमेंट को कुछ डिफ़ॉल्ट एचटीएमएल देने के लिए, createdCallback() का इस्तेमाल कर सकते हैं:

var XFooProto = Object.create(HTMLElement.prototype);

XFooProto.createdCallback = function() {
    this.innerHTML = "**I'm an x-foo-with-markup!**";
};

var XFoo = document.registerElement('x-foo-with-markup', {prototype: XFooProto});

इस टैग को शुरू करने और DevTools में जांच करने पर, यह दिखना चाहिए: राइट क्लिक करके एलिमेंट की जांच करें चुनें:

▾<x-foo-with-markup>
  **I'm an x-foo-with-markup!**
</x-foo-with-markup>

शैडो DOM में इंटरनल एनकैप्सुलेट करना

शैडो DOM खुद ही एक बेहतरीन टूल है, जिसकी मदद से कॉन्टेंट को इनकैप्सुलेट किया जा सकता है. कस्टम एलिमेंट के साथ इसका इस्तेमाल करें और देखें कि क्या होता है!

शैडो डीओएम से कस्टम एलिमेंट मिलते हैं:

  1. अपने हिम्मत छिपाने का एक तरीका, जिससे उपयोगकर्ताओं को खून-खराबे वाले तरीके से होने वाली जानकारी से बचाया जाता है.
  2. स्टाइल एनकैप्सुलेशन…बिना किसी शुल्क के.

शैडो DOM से कोई एलिमेंट बनाना, ऐसा एलिमेंट बनाने जैसा है जो बेसिक मार्कअप को रेंडर करता है. अंतर createdCallback() में है:

var XFooProto = Object.create(HTMLElement.prototype);

XFooProto.createdCallback = function() {
    // 1. Attach a shadow root on the element.
    var shadow = this.createShadowRoot();

    // 2. Fill it with markup goodness.
    shadow.innerHTML = "**I'm in the element's Shadow DOM!**";
};

var XFoo = document.registerElement('x-foo-shadowdom', {prototype: XFooProto});

एलिमेंट के .innerHTML को सेट करने के बजाय, मैंने <x-foo-shadowdom> के लिए एक शैडो रूट बनाया और फिर उसमें मार्कअप भर दिया. DevTools में "शैडो डीओएम दिखाएं" सेटिंग चालू होने पर, आपको एक #shadow-root दिखेगा, जिसे बड़ा किया जा सकता है:

<x-foo-shadowdom>
  ▾#shadow-root
    **I'm in the element's Shadow DOM!**
</x-foo-shadowdom>

यह शैडो रूट है!

टेंप्लेट से एलिमेंट बनाना

एचटीएमएल टेंप्लेट एक और नया एपीआई है, जो कस्टम एलिमेंट की दुनिया में अच्छी तरह फ़िट हो जाता है.

उदाहरण: <template> और शैडो डीओएम से बनाए गए एलिमेंट को रजिस्टर करना:

<template id="sdtemplate">
  <style>
    p { color: orange; }
  </style>
  <p>I'm in Shadow DOM. My markup was stamped from a <template&gt;.
</template>

<script>
  var proto = Object.create(HTMLElement.prototype, {
    createdCallback: {
      value: function() {
        var t = document.querySelector('#sdtemplate');
        var clone = document.importNode(t.content, true);
        this.createShadowRoot().appendChild(clone);
      }
    }
  });
  document.registerElement('x-foo-from-template', {prototype: proto});
</script>

<template id="sdtemplate">
  <style>:host p { color: orange; }</style>
  <p>I'm in Shadow DOM. My markup was stamped from a <template&gt;.
</template>

<div class="demoarea">
  <x-foo-from-template></x-foo-from-template>
</div>

कोड की ये कुछ लाइनें काफ़ी अहम हैं. आइए, देश में होने वाली घटनाओं के बारे में जानते हैं:

  1. हमने एचटीएमएल में एक नया एलिमेंट रजिस्टर किया है: <x-foo-from-template>
  2. एलिमेंट का डीओएम, <template> से बनाया गया था
  3. शैडो डीओएम का इस्तेमाल करके, एलिमेंट की डरावनी जानकारी छिपाई जाती है
  4. शैडो डीओएम, एलिमेंट स्टाइल एनकैप्सुलेशन देता है (उदाहरण के लिए, p {color: orange;} पूरे पेज को नारंगी नहीं बदल रहा)

बहुत बढ़िया!

कस्टम एलिमेंट को स्टाइल करना

किसी भी एचटीएमएल टैग की तरह, आपके कस्टम टैग के उपयोगकर्ता, सिलेक्टर की मदद से उसे स्टाइल कर सकते हैं:

<style>
  app-panel {
    display: flex;
  }
  [is="x-item"] {
    transition: opacity 400ms ease-in-out;
    opacity: 0.3;
    flex: 1;
    text-align: center;
    border-radius: 50%;
  }
  [is="x-item"]:hover {
    opacity: 1.0;
    background: rgb(255, 0, 255);
    color: white;
  }
  app-panel > [is="x-item"] {
    padding: 5px;
    list-style: none;
    margin: 0 7px;
  }
</style>

<app-panel>
    <li is="x-item">Do</li>
    <li is="x-item">Re</li>
    <li is="x-item">Mi</li>
</app-panel>

शैडो डीओएम का इस्तेमाल करने वाले एलिमेंट को स्टाइल करना

शैडो डीओएम को शामिल करने पर, यह बात बहुत ज़्यादा जटिल हो जाती है. शैडो डीओएम का इस्तेमाल करने वाले कस्टम एलिमेंट को इसके बेहतरीन फ़ायदे मिलते हैं.

शैडो डीओएम, स्टाइल एनकैप्सुलेशन वाले एलिमेंट को इंफ़्यूज़ करता है. शैडो रूट में तय की गई स्टाइल, होस्ट से लीक नहीं होती हैं और न ही पेज से बाहर दिखती हैं. कस्टम एलिमेंट के मामले में, एलिमेंट ही होस्ट होता है. स्टाइल को एन्कैप्सुलेट करने की प्रॉपर्टी की मदद से, कस्टम एलिमेंट भी अपने लिए डिफ़ॉल्ट स्टाइल तय कर सकते हैं.

शैडो डीओएम की स्टाइलिंग एक बहुत बड़ा विषय है! अगर आपको इस बारे में ज़्यादा जानकारी चाहिए, तो हमारा सुझाव है कि आप मेरे कुछ अन्य लेख देखें:

:अनसमाधानित का इस्तेमाल करके FOUC रोकथाम

एफ़ओयूसी को कम करने के लिए, कस्टम एलिमेंट में एक नई सीएसएस सूडो क्लास, :unresolved तय की गई है. इसका इस्तेमाल ऐसे एलिमेंट को टारगेट करने के लिए करें जहां से ब्राउज़र आपके createdCallback() को शुरू करता है. इसके लिए, लाइफ़साइकल के तरीके देखें. ऐसा होने के बाद, वह एलिमेंट मिट जाता है और उसे वापस लाया जा सकता है. अपग्रेड की प्रोसेस पूरी हो गई है और एलिमेंट अपनी परिभाषा में बदल गया है.

उदाहरण: रजिस्टर होने पर "x-foo" टैग को फ़ेड इन करें:

<style>
  x-foo {
    opacity: 1;
    transition: opacity 300ms;
  }
  x-foo:unresolved {
    opacity: 0;
  }
</style>

ध्यान रखें कि :unresolved सिर्फ़ उन एलिमेंट पर लागू होता है जिन्हें ठीक नहीं किया गया है. यह HTMLUnknownElement से इनहेरिट किए गए एलिमेंट पर लागू नहीं होता. एलिमेंट को कैसे अपग्रेड किया जाता है देखें.

<style>
  /* apply a dashed border to all unresolved elements */
  :unresolved {
    border: 1px dashed red;
    display: inline-block;
  }
  /* x-panel's that are unresolved are red */
  x-panel:unresolved {
    color: red;
  }
  /* once the definition of x-panel is registered, it becomes green */
  x-panel {
    color: green;
    display: block;
    padding: 5px;
    display: block;
  }
</style>

<panel>
    I'm black because :unresolved doesn't apply to "panel".
    It's not a valid custom element name.
</panel>

<x-panel>I'm red because I match x-panel:unresolved.</x-panel>

इतिहास और ब्राउज़र के लिए सहायता

फ़ीचर का पता लगाना

सुविधा का पता लगाना यह जांचना है कि document.registerElement() मौजूद है या नहीं:

function supportsCustomElements() {
    return 'registerElement' in document;
}

if (supportsCustomElements()) {
    // Good to go!
} else {
    // Use other libraries to create components.
}

ब्राउज़र समर्थन

document.registerElement() ने सबसे पहले Chrome 27 और Firefox ~23 में किसी फ़्लैग के पीछे काम करना शुरू किया. हालांकि, तब से इस स्पेसिफ़िकेशन में काफ़ी बदलाव हुए हैं. Chrome 31, अपडेट किए गए स्पेसिफ़िकेशन के साथ काम करने वाला पहला वर्शन है.

जब तक ब्राउज़र सपोर्ट बेहतरीन नहीं हो जाता, तब तक polyfill की सुविधा होती है. इसका इस्तेमाल Google का Polymer और Mozilla का X-Tag करता है.

HTMLElementElement का क्या हुआ?

मानक तय करने के काम का पालन करने वाले लोगों को पता है कि पहले <element> था. यह वाकई शानदार था. इसका इस्तेमाल, एलान के तौर पर नए एलिमेंट रजिस्टर करने के लिए किया जा सकता है:

<element name="my-element">
    ...
</element>

बदकिस्मती से, अपग्रेड की प्रोसेस, कॉर्नर केस, और आर्मगेडन जैसी स्थितियों में समय के साथ बहुत सारी समस्याएं हुईं. <element> को शेल्फ़ में नहीं रखना पड़ा. अगस्त 2013 में, दिमित्री ग्लेज़्कोव ने सार्वजनिक-वेबऐप्लिकेशन पर पोस्ट करके, हटाने की घोषणा की, कम से कम अभी के लिए.

ध्यान दें कि Polymer, <polymer-element> के साथ एलिमेंट रजिस्ट्रेशन का एलान करने वाला फ़ॉर्म लागू करता है. कैसे? इसमें document.registerElement('polymer-element') और टेंप्लेट से एलिमेंट बनाना लेख में बताई गई तकनीकों का इस्तेमाल किया गया है.

नतीजा

कस्टम एलिमेंट की मदद से, हमें एचटीएमएल के शब्दकोश को बढ़ाने, नई तरकीबें सिखाने, और वेब प्लैटफ़ॉर्म का इस्तेमाल करने में मदद मिलती है. इन्हें शैडो डीओएम और <template> जैसे नए प्लैटफ़ॉर्म प्राइमिटिव के साथ जोड़ें, तो वेब कॉम्पोनेंट की तस्वीर साफ़ तौर पर दिखने लगती है. मार्कअप फिर से सेक्सी हो सकता है!

अगर आपको वेब कॉम्पोनेंट का इस्तेमाल करना है, तो हमारा सुझाव है कि आप Polymer देखें. इसमें बहुत सारी चीज़ें हैं, ताकि आप आगे बढ़ सकें.