Crear Tabla de Contenidos en Astro de forma simple
Como ya comentamos en nuestro último post, Astro se está convirtiendo en el favorito de muchos desarrolladores. Por ello queremos elaborar contenido que os ayuden a integraros y desarrollar vuestros nuevos proyectos en este framework. Una de las características que más nos gusta de Astro es que soporta de forma nativa Markdown y MDX (Markdown + JSX). Esto ayuda enormemente a tener una buena base de desarrollo a las personas que se centran en proyectos tipo blog o centrado mayormente en contenido estático. Así que en este post os mostraremos cómo crear una tabla de contenidos en Astro sin hacer uso de plugins como remark-toc.
Obtener información de los encabezados
En el ejemplo que vamos a usar para implementar la tabla de contenidos usamos las Astro Content Collections, que según Astro es “la mejor manera de administrar y crear contenido en cualquier proyecto de Astro”. Básicamente te ayuda a organizar el contenido markdown siguiendo una estructura de carpetas dentro de src/content.
---import { type CollectionEntry, getCollection } from 'astro:content';import BlogPost from '../../layouts/BlogPost.astro';import type { MarkdownHeading } from 'astro';
export async function getStaticPaths() { const posts = await getCollection('blog');
const headings = await Promise.all( posts.map(async (post) => { const data = await post.render(); return data.headings; }) );
return posts.map((post, index) => ({ params: { slug: post.slug }, props: {post, headings: headings[index]}, }));}
type Props = { post: CollectionEntry<'blog'>; headings: MarkdownHeading[];};const { post, headings } = Astro.props;const { Content } = await post.render();---
<BlogPost headings={headings} {...post.data} > <Content /></BlogPost>Este archivo es el [...slug].astro que muestra los post según las rutas dinámicas definidas en la función de Astro getStaticPaths. Hay mucho que explicar aquí, pero centrémonos en los encabezados. Dentro de la función extraemos los headings, una lista de objetos que representan los encabezados y nos aportan información útil como la profundidad (si es h1, h2, etc.), el slug (para crear los enlaces de la tabla de contenidos) y el texto (simplemente el texto literal del encabezado respetando el formato).
Como getStaticPaths se ejecuta, por así decirlo, previamente a la renderización del componente, devolvemos las props en las cuales incluimos los headings y podemos obtener está información en el mismo componente mediante Astro.props. Ya en la plantilla del componente pasamos estos headings al layout BlogPost que engloba al contenido.
Mostrar la tabla de contenidos
Ahora tenemos que renderizar la tabla de contenidos en el post, por lo que creamos el componente src/components/TableOfContents.astro.
---import type { MarkdownHeading } from 'astro';
interface Props { headings: MarkdownHeading[];}
const { headings } = Astro.props;
const filteredHeadings = headings.filter((heading) => heading.depth <= 2);---
<nav> <ul> { filteredHeadings.map((heading) => ( <li> <a href={`#${heading.slug}`}>{heading.text}</a> </li> )) } </ul></nav>Este componente recibirá los encabezados desde el layout. Seguidamente, le realizamos un filtrado a estos encabezados para quedarnos solo con los de profundidad 2 o menor, es decir, tomar todos los h1 y h2. Para no complicarnos mucho creamos una lista html básica a partir de la lista de encabezados en la que el href toma el heading.slug para crear el hiperenlace interno en la misma página.
Por último, debemos renderizar TableOfContents.astro dentro del post en un lugar a nuestra elección. Obtenemos los headings como props y renderizamos la tabla de contenidos pasándoselos como props. Además, validamos para que solo se muestre la tabla de contenidos si existe algún encabezado.
---// Resto de js/tstype Props = CollectionEntry<'blog'>['data'] & { headings: MarkdownHeading[] }const { title, description, pubDate, updatedDate, heroImage, labels, headings } = Astro.props---<!-- Resto de la plantilla -->{headings && <TableOfContents headings={headings} />}<!-- Resto de la plantilla -->Cómo se vería la tabla de contenidos
Finalmente, ya podemos ver el resultado y así quedaría nuestra tabla de contenidos (el ejemplo es de este mismo artículo):
Posts Relacionados
Cómo Configurar tu Astro robots.txt Sin Errores (Estático vs. Integración)
¿Dudas con tu astro robots txt? Aprende a configurarlo: método estático en /public o la integración "astro-robots-txt". Optimiza tu crawl budget. ¡Entra ya!
Cómo Integrar y Personalizar Tailwind CSS en Proyectos con Astro Framework
Aprende a integrar Tailwind en Astro paso a paso. Cubrimos la instalación, configuración de "tailwind.config" y cómo solucionar errores comunes. Entra ya.
Cómo Crear y Configurar un Sitemap en Astro para Mejorar tu SEO
¿Problemas con tu sitemap de Astro? Te enseñamos a configurarlo correctamente, filtrar páginas y evitar errores comunes. ¡Optimiza tu SEO ahora!
Guía Práctica de Accesibilidad Web WCAG: Implementación y Testing para Desarrolladores en 2025
Domina la accesibilidad web en 2025. Te explicamos los 4 principios WCAG, los niveles (A, AA, AAA) y cómo auditar e implementar todo con ejemplos de código.
Mejores prácticas para mejorar la Optimización de tu Página Web
Descubre cómo se realiza una optimización de páginas web, analizar el rendimiento del sitio y mejorar el SEO y la experiencia de los usuarios.