aboutsummaryrefslogtreecommitdiff
path: root/files/es/web/web_components/using_templates_and_slots/index.html
blob: d8047d325b4caf72da0230b32bc8cfab62864826 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
---
title: Usando plantillas y slots
slug: Web/Web_Components/Using_templates_and_slots
tags:
  - Componentes Web
  - Template
  - shadow dom
  - slot
translation_of: Web/Web_Components/Using_templates_and_slots
---
<div>{{DefaultAPISidebar("Web Components")}}</div>

<p class="summary">Este artículo explica como puedes usar los elementos {{htmlelement("template")}} y {{htmlelement("slot")}} para crear una plantilla flexible que luego puede ser usada para rellenar el shadow DOM de un componente web.</p>

<h2 id="La_verdad_acerca_del_elemento_&lt;template>">La verdad acerca del elemento &lt;template&gt;</h2>

<p>Cuando tienes que reutilizar las mismas estructuras de lenguaje de marcado repetidas veces en una página web, tiene sentido utilizar algún tipo de plantilla en lugar de repetir la misma estructura una y otra vez. Esto ya era posible hacerlo antes, pero ahora es mucho mas fácil con el elemento HTML {{htmlelement("template")}} (que está bien soportado en los navegadores modernos). Este elemento y su contenido no son renderizados en el DOM, pero pueden ser referenciados vía JavaScript.</p>

<p>Echemos un vistazo a un ejemplo sencillo:</p>

<pre class="brush: html">&lt;template id="my-paragraph"&gt;
  &lt;p&gt;Mi párrafo&lt;/p&gt;
&lt;/template&gt;</pre>

<p>Esto no aparecerá en tu página hasta que hagas una referencia a él con JavaScript y luego lo agregues al DOM, usando algo parecido a lo siguiente:</p>

<pre class="brush: js">let template = document.getElementById('my-paragraph');
let templateContent = template.content;
document.body.appendChild(templateContent);</pre>

<p>Aunque de una manera simple, ya puedes empezar a ver su utilidad.</p>

<h2 id="Usando_el_elemento_&lt;template>_con_componentes_web">Usando el elemento &lt;template&gt; con componentes web</h2>

<p>Las plantillas son útiles por si mismas, pero trabajan aún mejor con componentes web. Definamos un componente web que use nuestra plantilla como el contenido de su shadow DOM. Lo nombraremos <code>&lt;my-paragraph&gt;</code>:</p>

<pre class="brush: js">customElements.define('my-paragraph',
  class extends HTMLElement {
    constructor() {
      super();
      let template = document.getElementById('my-paragraph');
      let templateContent = template.content;

      const shadowRoot = this.attachShadow({mode: 'open'})
        .appendChild(templateContent.cloneNode(true));
  }
})</pre>

<p>El punto clave a tener en cuenta aquí es que agregamos un clon del contenido de la plantilla al shadow root creado usando el método {{domxref("Node.cloneNode()")}}.</p>

<p>Y debido a que estamos agregando su contenido a un shadow DOM, podemos incluir cierta información de estilo dentro de la plantilla en un elemento {{htmlelement("style")}}, que luego se encapsula dentro del elemento personalizado. Esto no funcionaría si nosotros solo lo agregásemos al DOM estandar.</p>

<p>Por ejemplo:</p>

<pre class="brush: html">&lt;template id="my-paragraph"&gt;
  &lt;style&gt;
    p {
      color: white;
      background-color: #666;
      padding: 5px;
    }
  &lt;/style&gt;
  &lt;p&gt;Mi párrafo&lt;/p&gt;
&lt;/template&gt;</pre>

<p>Ahora podemos usarlo simplemente agregándolo a nuestro documento HTML:</p>

<pre class="brush: html">&lt;my-paragraph&gt;&lt;/my-paragraph&gt;
</pre>

<div class="note">
<p><strong>Nota: </strong>Las plantillas están bien soportadas en los navegadores: la API del Shadow DOM  es compatible por defecto con Firefox (version 63 en adelante), Chrome, Opera y Safari, Edge está trabajando en una implementación.</p>
</div>

<h2 id="Añadiendo_flexibilidad_con_el_elemento_&lt;slot>">Añadiendo flexibilidad con el elemento &lt;slot&gt;</h2>

<p>Hasta aquí bien, pero el elemento no es muy flexible. Solo podemos mostrar una parte de texto dentro de él, lo que quiere decir que, hasta el momento, es menos útil que un párrafo normal. Podemos mostrar diferente texto en cada instancia de elemento de una forma declarativa agradable usando el elemento {{htmlelement("slot")}}. Este tiene un soporte más limitado que el elemento {{htmlelement("template")}}, disponible desde Chrome 53, Opera 40, Safari 10, Firefox 59, pero aún no disponible en Edge.</p>

<p>Los slots son identificados por su atributo <code>name</code>, y te permiten definir marcadores de posición en tu plantilla que pueden rellenarse con cualquier fragmento de marcado cuando el elemento es usado.</p>

<p>Así que, si queremos agregar un slot dentro de nuestro ejemplo sencillo, podemos actualizar el elemento de párrafo de la plantilla de la siguiente manera:</p>

<pre class="brush: html">&lt;p&gt;&lt;slot name="my-text"&gt;<span class="tlid-translation translation" lang="es"><span title="">Mi texto predeterminado</span></span>&lt;/slot&gt;&lt;/p&gt;</pre>

<p>Si el contenido del slot no está definido cuando el elemento se agrega al marcado, o si el navegador no soporta el elemento slot, <code>&lt;my-paragraph&gt;</code> solo contiene el texto alternativo "<span class="tlid-translation translation" lang="es"><span title="">Mi texto predeterminado</span></span>".</p>

<p>Para definir el contenido de un slot, incluimos una estructura HTML dentro del elemento <code>&lt;my-paragraph&gt;</code> con un atributo {{htmlattrxref("slot")}} cuyo valor es igual al nombre del slot que  queremos rellenar. Al igual que<span class="tlid-translation translation" lang="es"><span title=""> antes, esto puede ser cualquier cosa, por ejemplo:</span></span></p>

<pre class="brush: html">&lt;my-paragraph&gt;
  &lt;span slot="my-text"&gt;<span class="tlid-translation translation" lang="es"><span title="">¡Tengamos un texto diferente!</span></span>&lt;/span&gt;
&lt;/my-paragraph&gt;</pre>

<p>o</p>

<pre class="brush: html">&lt;my-paragraph&gt;
  &lt;ul slot="my-text"&gt;
    &lt;li&gt;<span class="tlid-translation translation" lang="es"><span title="">¡Tengamos un texto diferente!</span></span>&lt;/li&gt;
    &lt;li&gt;¡En una lista!&lt;/li&gt;
  &lt;/ul&gt;
&lt;/my-paragraph&gt;
</pre>

<div class="note">
<p><strong>Nota: </strong>Los elementos que pueden ser insertados en los slots son conocidos como {{domxref("Slotable")}}; cuando un elemento ha sido insertado en un slot, se dice que fue <em>eslotado </em>por su término en inlgés <em>slotted.</em></p>
</div>

<div class="blockIndicator note">
<p><strong>Nota:</strong> Un {{HTMLElement("slot")}} <span class="tlid-translation translation" lang="es"><span title="">sin nombre se rellenará con todos los nodos secundarios de nivel superior del elemento personalizado que no tengan el atributo </span></span> {{htmlattrxref("slot")}}. <span class="tlid-translation translation" lang="es"><span title="">Esto incluye nodos de texto.</span></span></p>
</div>

<p>Y eso es todo nuestro ejemplo sencillo. Si quieres jugar con él un poco más, puedes encontrarlo en <a href="https://github.com/mdn/web-components-examples/tree/master/simple-template">GitHub</a> (también puedes <a href="https://mdn.github.io/web-components-examples/simple-template/">verlo en vivo</a>).</p>

<h2 id="Un_ejemplo_más_completo">Un ejemplo más completo</h2>

<p>Para finalizar el artículo, veamos algo menos trivial.</p>

<p>El siguiente conjunto de fragmentos de código muestra cómo usar {{HTMLElement("slot")}} junto con  {{HTMLElement("template")}} y algo de JavaScript para:</p>

<ul>
 <li>crear un elemento <strong><code>&lt;element-details&gt;</code></strong>  con <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> en su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a></li>
 <li>diseñe el elemento <strong><code>&lt;element-details&gt;</code></strong> de forma que, cuando se use en documentos, sea renderizado desde la composición del contenido del elemento junto con el contenido de su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root,</a> es decir, se utilizan partes del contenido del elemento para rellenar el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> de los <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a></li>
</ul>

<p>Observa que es técnicamente posible usar el elemento {{HTMLElement("slot")}} sin un elemento {{HTMLElement("template")}}, por ejemplo, dentro de un elemento {{HTMLElement("div")}} normal, y aun así tomar ventaja de los indicadores de posición de el elemento {{HTMLElement("slot")}} para el contenido del <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM">Shadow DOM</a>, y al hacerlo puedes evitar el problema de tener que acceder primero a la propiedad <code>content</code> del elemento de la plantilla y clonarlo. Sin embargo, por lo general, es más práctico agregar slots dentro de un elemento {{HTMLElement("template")}}, ya que es poco probable que necesites definir un patrón basado en un elemento ya renderizado.</p>

<p>Además, incluso si no está renderizado, el propósito del contenedor como plantilla debería ser semánticamente más claro cuando se usa el elemento {{HTMLElement("template")}}. Además, el elemento {{HTMLElement("template")}} puede tener elementos agregados directamente a él, como {{HTMLElement("td")}}, que desaparecerían al añadirse a un {{HTMLElement ("div")}}.</p>

<div class="note">
<p><strong>Nota: </strong>Puedes encontrar el ejemplo completo en <a href="https://github.com/mdn/web-components-examples/tree/master/element-details">element-details </a>(también lo puedes<a href="https://github.com/mdn/web-components-examples/tree/master/element-details"> ver en vivo</a>)</p>
</div>

<h3 id="Creando_una_plantilla_con_algunos_elementos_&lt;slot>">Creando una plantilla con algunos elementos &lt;slot&gt;</h3>

<p>En primer lugar, usamos el elemento {{HTMLElement("slot")}} dentro de un elemento {{HTMLElement("template")}} para crear un nuevo <a href="/en-US/docs/Web/API/DocumentFragment">fragmento de documento</a> de tipo "element-details-template" que contiene algunos <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con el atributo name</a>:</p>

<pre class="brush: html">&lt;template id="element-details-template"&gt;
  &lt;style&gt;
  details {font-family: "Open Sans Light",Helvetica,Arial}
  .name {font-weight: bold; color: #217ac0; font-size: 120%}
  h4 { margin: 10px 0 -8px 0; }
  h4 span { background: #217ac0; padding: 2px 6px 2px 6px }
  h4 span { border: 1px solid #cee9f9; border-radius: 4px }
  h4 span { color: white }
  .attributes { margin-left: 22px; font-size: 90% }
  .attributes p { margin-left: 16px; font-style: italic }
  &lt;/style&gt;
  &lt;details&gt;
    &lt;summary&gt;
      &lt;span&gt;
        &lt;code class="name"&gt;&amp;lt;&lt;slot name="element-name"&gt;NECESITA NOMBRE&lt;/slot&gt;&amp;gt;&lt;/code&gt;
        &lt;i class="desc"&gt;&lt;slot name="description"&gt;NECESITA DESCRIPCIÓN&lt;/slot&gt;&lt;/i&gt;
      &lt;/span&gt;
    &lt;/summary&gt;
    &lt;div class="attributes"&gt;
      &lt;h4&gt;&lt;span&gt;Atributos&lt;/span&gt;&lt;/h4&gt;
      &lt;slot name="attributes"&gt;&lt;p&gt;Ninguno&lt;/p&gt;&lt;/slot&gt;
    &lt;/div&gt;
  &lt;/details&gt;
  &lt;hr&gt;
&lt;/template&gt;
</pre>

<p>Ese elemento {{HTMLElement("template")}} tiene varias características.</p>

<ul>
 <li>El {{HTMLElement ("template")}} tiene un elemento {{HTMLElement ("style")}} con un conjunto de estilos CSS ajustados al ámbito del fragmento de documento que {{HTMLElement ("template")}} crea.</li>
 <li>El elemento {{HTMLElement("template")}} usa {{HTMLElement("slot")}} y su atributo {{htmlattrxref("name", "slot")}} para hacer tres <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con el atributo name</a>:
  <ul>
   <li><code>&lt;slot name="element-name"&gt;</code></li>
   <li><code>&lt;slot name="description"&gt;</code></li>
   <li><code>&lt;slot name="attributes"&gt;</code></li>
  </ul>
 </li>
 <li>El elemento {{HTMLElement("template")}} envuelve los <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> dentro de un elemento {{HTMLElement("details")}}.</li>
</ul>

<h3 id="Crear_un_nuevo_elemento_&lt;element-details>_desde_el_elemento_&lt;template>">Crear un nuevo elemento &lt;element-details&gt; desde el elemento &lt;template&gt;</h3>

<p>A continuación, crearemos un nuevo elemento personalizado llamado <strong><code>&lt;element-details&gt;</code></strong> y usaremos {{DOMXref("Element.attachShadow")}} para anclarlo, como su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>, a ese fragmento de documento que creamos anteriormente con nuestro elemento {{HTMLElement("template")}}. Usa exactamente el mismo patrón que vimos antes en el ejemplo sencillo.</p>

<pre class="brush: js">customElements.define('element-details',
  class extends HTMLElement {
    constructor() {
      super();
      var template = document
        .getElementById('element-details-template')
        .content;
      const shadowRoot = this.attachShadow({mode: 'open'})
        .appendChild(template.cloneNode(true));
  }
})
</pre>

<h3 id="Usando_el_elemento_&lt;element-details>_con_slots_con_el_atributo_name">Usando el elemento &lt;element-details&gt; con slots con el atributo name</h3>

<p>Ahora tomaremos el elemento <strong><code>&lt;element-details&gt;</code></strong> para usarlo en nuestro documento.</p>

<pre class="brush: html">&lt;element-details&gt;
  &lt;span slot="element-name"&gt;slot&lt;/span&gt;
  &lt;span slot="description"&gt;Un marcador de posición dentro de un
     componente web que los usuarios pueden rellenar con su propio marcado,
     con el efecto de componer diferentes árboles DOM
     juntos.&lt;/span&gt;
  &lt;dl slot="attributes"&gt;
    &lt;dt&gt;name&lt;/dt&gt;
    &lt;dd&gt;El atributo name del slot.&lt;/dd&gt;
  &lt;/dl&gt;
&lt;/element-details&gt;

&lt;element-details&gt;
  &lt;span slot="element-name"&gt;template&lt;/span&gt;
  &lt;span slot="description"&gt;Un mecanismo para guardar contenido
     en el lado cliente que no se renderiza cuando la página se
     carga sino que posteriormente se puede instanciar en
     tiempo de ejecución usando JavaScript.&lt;/span&gt;
&lt;/element-details&gt;
</pre>

<p><span class="tlid-translation translation" lang="es"><span title="">Observa estos puntos sobre el fragmento anterior</span></span>:</p>

<ul>
 <li>El fragento tiene dos instancias de elementos <strong><code>&lt;element-details&gt;</code></strong> que usan el atributo {{htmlattrxref("slot")}} para referenciar los <a href="https://wiki.developer.mozilla.org/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> <code>"element-name"</code> y <code>"description"</code> que colocamos en el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> del <code>&lt;element-details&gt;</code></li>
 <li>Solo el primero de esos dos elementos <strong><code>&lt;element-details&gt;</code></strong> hace referencia a los <code>"attributes"</code> de <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name. </a>El segundo elemento <code><strong>&lt;element-details</strong>&gt;</code> carece de cualquier referencia a <code>"attributes"</code> de <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a>.</li>
 <li>El primer elemento <code>&lt;<strong>element-details&gt;</strong></code> está referenciando los <code>"attributes"</code>  de <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> usando un elemento {{HTMLElement("dl")}} con {{HTMLElement("dt")}} y {{HTMLElement("dd")}} como hijos.</li>
</ul>

<h3 id="Añadamos_algunos_estilos">Añadamos algunos estilos</h3>

<p>Como toque final, añadiremos algunos estilos CSS a los ellementos {{HTMLElement("dl")}}, {{HTMLElement("dt")}}, y {{HTMLElement("dd")}} en el documento:</p>

<pre class="brush: css">  dl { margin-left: 6px; }
  dt { font-weight: bold; color: #217ac0; font-size: 110% }
  dt { font-family: Consolas, "Liberation Mono", Courier }
  dd { margin-left: 16px }
</pre>

<div class="hidden">
<pre class="brush: css">body { margin-top: 47px }</pre>
</div>

<h3 id="Resultado">Resultado</h3>

<p>Finalmente, juntemos todos los fragmentos y veamos cómo se ve el resultado renderizado.</p>

<p>{{ EmbedLiveSample('full_example', '300','400','https://mdn.mozillademos.org/files/14553/element-details.png','') }}</p>

<p>Observa los siguientes puntos del resultado renderizado:</p>

<ul>
 <li>Aún cuando las instancias del elemento <strong><code>&lt;element-details&gt;</code></strong> en el documento no usan directamente el elemento {{HTMLElement("details")}}, se renderizan usando {{HTMLElement("details")}} porque el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> hace que ellos se rellenen.</li>
 <li>En la salida de {{HTMLElement ("details")}}, el contenido de los elementos <strong><code>&lt;element-details&gt;</code></strong> llena los <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slots con atributo name</a> desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>. En otras palabras, el árbol DOM de los elementos <strong><code>&lt;element-details&gt;</code></strong> se compone junto con el contenido del <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>.</li>
 <li>Para ambos elementos <strong><code>&lt;element-details&gt;</code></strong>, un encabezado de <strong>Attributes</strong> se añade automáticamente desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a> antes de la posición <code>"attributes"</code> del <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a>.</li>
 <li>Ya que el primer elemento <strong><code>&lt;element-details&gt;</code></strong> tiene un elemento {{HTMLElement("dl")}} que hace referencia explicita al <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> <code>"attributes"</code> desde su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>, el contenido de ese {{HTMLElement("dl")}} reemplaza el <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> <code>"attributes"</code> desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a></li>
 <li>Ya que el segundo elemento <strong><code>&lt;element-details&gt;</code></strong> no hace referencia explícita al <a href="/en-US/docs/Web/HTML/Element/slot#named-slot">slot con atributo name</a> <code>"attributes"</code> desde su <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>, su contenido se rellena con el contenido predeterminado desde el <a href="/en-US/docs/Web/API/ShadowRoot">shadow root</a>.</li>
</ul>

<div class="hidden">
<h5 id="full_example">full example</h5>

<pre class="brush: html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;ejemplo de slot&lt;/title&gt;
    &lt;style&gt;

      dl { margin-left: 6px; }
      dt { font-weight: bold; color: #217ac0; font-size: 110% }
      dt { font-family: Consolas, "Liberation Mono", Courier }
      dd { margin-left: 16px }

    &lt;/style&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;template id="element-details-template"&gt;
      &lt;style&gt;
      details {font-family: "Open Sans Light",Helvetica,Arial}
      .name {font-weight: bold; color: #217ac0; font-size: 120%}
      h4 { margin: 10px 0 -8px 0; }
      h4 span { background: #217ac0; padding: 2px 6px 2px 6px }
      h4 span { border: 1px solid #cee9f9; border-radius: 4px }
      h4 span { color: white }
      .attributes { margin-left: 22px; font-size: 90% }
      .attributes p { margin-left: 16px; font-style: italic }
      &lt;/style&gt;
      &lt;details&gt;
        &lt;summary&gt;
          &lt;span&gt;
            &lt;code class="name"&gt;&amp;lt;&lt;slot name="element-name"&gt;NECESITA NOMBRE&lt;/slot&gt;&amp;gt;&lt;/code&gt;
            &lt;i class="desc"&gt;&lt;slot name="description"&gt;NECESITA DESCRIPCIÓN&lt;/slot&gt;&lt;/i&gt;
          &lt;/span&gt;
        &lt;/summary&gt;
        &lt;div class="attributes"&gt;
          &lt;h4&gt;&lt;span&gt;Attributos&lt;/span&gt;&lt;/h4&gt;
          &lt;slot name="attributes"&gt;&lt;p&gt;Ninguno&lt;/p&gt;&lt;/slot&gt;
        &lt;/div&gt;
      &lt;/details&gt;
      &lt;hr&gt;
    &lt;/template&gt;

    &lt;element-details&gt;
      &lt;span slot="element-name"&gt;slot&lt;/span&gt;
      &lt;span slot="description"&gt;Un marcador de posición dentro de un
     componente web que los usuarios pueden rellenar con su propio marcado,
     con el efecto de componer diferentes árboles DOM
     juntos.&lt;/span&gt;
      &lt;dl slot="attributes"&gt;
        &lt;dt&gt;name&lt;/dt&gt;
        &lt;dd&gt;El atributo name del slot.&lt;/dd&gt;
      &lt;/dl&gt;
    &lt;/element-details&gt;

    &lt;element-details&gt;
      &lt;span slot="element-name"&gt;template&lt;/span&gt;
      &lt;span slot="description"&gt;Un mecanismo para guardar contenido
     en el lado cliente que no se renderiza cuando la página se
     carga sino que posteriormente se puede instanciar en
     tiempo de ejecución usando JavaScript.&lt;/span&gt;
    &lt;/element-details&gt;

    &lt;script&gt;
    customElements.define('element-details',
      class extends HTMLElement {
        constructor() {
          super();
          const template = document
            .getElementById('element-details-template')
            .content;
          const shadowRoot = this.attachShadow({mode: 'open'})
            .appendChild(template.cloneNode(true));
        }
      })
    &lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</pre>
</div>