La tabla de contenidos puede mejorar mucho la experiencia de usuario de muchos sitios web, por ejemplo los de documentación o enciclopedias en línea como Wikipedia. Una tabla de contenidos bien diseñada ofrece una visión general de la página y ayuda a los usuarios a navegar rápidamente a la sección que les interesa.
Tradicionalmente, se pueden crear tablas de contenido (TOC, Table of Contents) en HTML o con JavaScript, pero las últimamente estandarizadas slots HTML ofrecen una vía intermedia entre ambas. HTML Slot es un estándar web que permite añadir marcadores de posición a una página web y rellenarlos posteriormente con contenido de forma dinámica.
Cuándo Utilizar la Etiqueta <slot>
Puedes colocar etiquetas <slot>
en la tabla de contenidos dentro de tu archivo HTML, de modo que los slots puedan rellenarse posteriormente con los encabezados y subencabezados pertinentes. Cuando se cambian los títulos, éstos se actualizan automáticamente.
Con esta técnica, es necesario crear manualmente el código fuente HTML de la tabla de contenido. JavaScript sólo genera automáticamente el contenido de texto de la tabla de contenido, basándose en los títulos o subtítulos de la página.
Nota
Crear el HTML
El código fuente HTML para la TOC (tabla de contenidos) estará dentro de una etiqueta <template>
. El código dentro de <template> no se renderiza hasta que se añade al documento mediante JavaScript. Nuestra TOC tendrá marcadores de posición, contenidos en etiquetas <slot>
, para todos los encabezados y subencabezados que se encuentran en el documento.
El atributo name
de cada <slot>
tendrá el mismo valor que el atributo slot de sus correspondientes encabezados y subencabezados en el documento.
A continuación, puedes ver un ejemplo de HTML <article>
con algunos encabezados y subencabezados. El <div>
del principio es donde insertaremos la TOC autocompletada.
<div id='toc'></div>
<article>
<p>Velociraptor (que significa "asaltante rápido" en latín) es …</p>
<h2 slot='h-1'>Descripción</h2>
<p>El Velociraptor era un dromeosáurido de tamaño mediano, con …</p>
<h3 slot='sh-1-1'>Plumas</h3>
<p>Se sabe que los fósiles de dromeosáuridos más primitivos que …</p >
<h2 slot='h-2'>Historia del descubrimiento</h2>
<p>Durante una expedición del Museo Americano de Historia Natural al …</p>
<h2 slot='h-3'>Clasificación</h2>
<p>Velociraptor es miembro del grupo Eudromaeosauria, un subgrupo derivado …</p>
<h2 slot='h-4'>Paleobiología</h2>
<p>El espécimen de los "Dinosaurios en Combate", encontrado en 1971, …</p>
<h3 slot='sh-4-1'>Comportamiento de carroñero</h3>
<p>En 2010, Hone y sus colegas publicaron un artículo sobre …</p>
<h3 slot='sh-4-2'>Metabolismo</h3>
<p>VEl Velociraptor era de sangre caliente hasta cierto grado, ya que …</p>
<h3 slot='sh-4-3'>Patología</h3>
<p>Un cráneo de Velociraptor mongoliensis presenta dos filas …</p>
</article>
Como puedes ver, a cada encabezado se le da un valor de slot único.
Y, aquí está el código HTML de la TOC, dentro de una etiqueta <template>
.
<template>
<ul>
<li>
<slot name='h-1'></slot>
<ul>
<li><slot name='sh-1-1'></slot></li>
</ul>
</li>
<li><slot name='h-2'></slot></li>
<li><slot name='h-3'></slot></li>
<li>
<slot name='h-4'></slot>
<ul>
<li><slot name='sh-4-1'></slot></li>
<li><slot name='sh-4-2'></slot></li>
<li><slot name='sh-4-3'></slot></li>
</ul>
</li>
</ul>
<style>
ul {
list-style: none;
}
/* … */
</style>
</template>
En los dos fragmentos de código anteriores, observa la coincidencia de los atributos slot y name dentro de los encabezados y las etiquetas <slot>
.
Numerar los Encabezados
Antes de ver el código JavaScript que añadirá la TOC del <template>
al documento, vamos a añadir números de serie para los encabezados, usando contadores CSS.
article {
counter-reset: heading;
}
article h2::before {
counter-increment: heading;
content: '0'counter(heading)': ';
}
Asegúrate de que la regla counter-reset pertenece al elemento que es el padre inmediato de todos los títulos que llevan el atributo slot (que es el elemento <article>
en nuestro código).
Insertar la tabla de contenido en el documento
Ahora, añadimos el script que inserta el TOC encima de la etiqueta <article>
, dentro del contenedor <div id='toc'></div>
templateContent = document.querySelector('template').content;
article = document.querySelector('article').cloneNode(true);
article.attachShadow({ mode: 'closed' }).appendChild(templateContent.cloneNode(true));
document.querySelector('#toc').appendChild(article);
El fragmento de código anterior crea una copia de <article>
y le adjunta un Shadow DOM Tree (árbol del DOM sombreado). También añadimos una copia del contenido de <template> a este Shadow DOM tree.
A continuación, el <article>
clonado se inserta en el elemento <div id='toc'>
. El elemento <article>
ahora también está presente en la TOC, sin embargo sólo son visibles sus encabezados y subencabezados que encontraron un marcador de posición dentro de la TOC.
Si hubiéramos reiniciado el contador CSS en el elemento body o html
en lugar de article
, el contador habría contado también la lista de encabezados dentro de la TOC. Es por eso que debes restablecer los contadores en el padre inmediato de los encabezados.
Aquí está la captura de pantalla de la salida:
Añadir Hipervínculos
Si deseas vincular los títulos de la TOC a sus respectivos encabezados y subencabezados añadiendo id a los encabezados y anclando su correspondiente texto de la TOC tendrás que eliminar los valores id repetitivos del artículo clonado.
<div id='toc'></div>
<article>
<p>Velociraptor (que significa "asaltante rápido" en latín) es …</p>
<h2 id='h-1' slot='h-1'>Descripción</h2>
<p>El Velociraptor era un dromeosáurido de tamaño mediano, con …</p>
<h3 id='sh-1-1' slot='sh-1-1'>Plumas</h3>
<p>Se sabe que los fósiles de dromeosáuridos más primitivos que …</p >
<!-- ... -->
</article>
Como puedes ver arriba, el atributo id
se añade a todos los títulos y subtítulos del artículo.
Y, los títulos dentro de la tabla de contenidos están anclados:
<template>
<ul>
<li>
<a href='#h-1'><slot name='h-1'></slot></a>
<ul>
<a href='#sh-1-1'><li><slot name='sh-1-1'></slot></li></a>
</ul>
</li>
<!-- ... -->
</ul>
</template>
En la línea adicional anterior, se eliminan todos los atributos id
del article
clonado antes de adjuntarle el Shadow DOM tree.
templateContent = document.querySelector('template').content;
article = document.querySelector('article').cloneNode(true);
article.querySelectorAll('*[id]').forEach((ele)=>{ele.removeAttribute('id')})
article.attachShadow({ mode: 'closed' }).appendChild(templateContent.cloneNode(true));
document.querySelector('#toc').appendChild(article);
Véase a continuación la captura de pantalla de la tabla de contenidos enlazada: