Saltar al contenido

Layouts y frontmatter en MDX

Envolver una página MDX autónoma con un layout: la clave layout del frontmatter, la prop frontmatter que el layout recibe con los metadatos del documento, las props que Astro inyecta y las que no comparte con Markdown, y la alternativa de envolver a mano importando el layout como componente.

La clave layout en una página MDX

Una página .mdx situada directamente en src/pages no puede rodear su contenido de un <html> sin repetirlo en cada fichero, así que Astro le ofrece un atajo declarativo: la clave layout del frontmatter, apuntando a la ruta del componente que hará de marco. Con esa sola línea, Astro compila el cuerpo del documento y lo inyecta en el <slot /> del layout indicado.

MDX
---layout: ../../layouts/Articulo.astrotitle: Guía de desplieguefecha: 2026-07-20---# Cómo desplegarEl cuerpo entero de este documento se compila a HTML y aterrizaen el slot del layout, sin escribir una etiqueta de componente.

El mecanismo es idéntico al de una página Markdown: no importas nada ni invocas al layout con JSX; solo lo nombras. Astro hace dos cosas por ti al procesar la página. Primero, renderiza el cuerpo MDX a HTML y lo coloca en el hueco del layout. Segundo, pasa todo el frontmatter al layout para que pueda usar el título, la fecha o cualquier campo que hayas declarado. Una página de contenido obtiene así su marco completo con una línea de configuración.

Un detalle práctico ahorra un desconcierto habitual: la ruta de la clave layout es relativa al fichero .mdx que la escribe, no a la raíz del proyecto. Desde una página en src/pages/blog/, el layout de src/layouts/ se alcanza subiendo dos niveles con ../../layouts/, y equivocar la cuenta de puntos es la causa más común de que Astro no encuentre el marco. Si prefieres evitar el conteo, un alias de ruta configurado en el proyecto vuelve la referencia estable desde cualquier profundidad de carpeta.

La prop frontmatter dentro del layout

Dentro del layout, los metadatos del documento no llegan como props sueltas, sino agrupados bajo una única prop llamada frontmatter. Ese objeto contiene todos los campos que declaraste en la cabecera del .mdx, y desde él el layout lee lo que necesita para armar el documento.

ASTRO
---// src/layouts/Articulo.astroconst { frontmatter } = Astro.props;---<!doctype html><html lang="es">  <head>    <meta charset="utf-8" />    <title>{frontmatter.title}</title>  </head>  <body>    <article>      <h1>{frontmatter.title}</h1>      <time>{frontmatter.fecha}</time>      <slot />    </article>  </body></html>

La razón de que los datos lleguen empaquetados y no dispersos es que su contenido es abierto: Astro no sabe qué campos declararás en tu frontmatter, así que los reúne todos bajo un mismo espacio de nombres en lugar de esparcirlos como props anónimas. El layout accede a cada uno con frontmatter.loquesea, y el <slot /> recibe el cuerpo ya compilado. Datos arriba, contenido en el hueco: el documento queda vestido.

Ese carácter abierto tiene un reverso: frontmatter es, por defecto, un objeto sin garantías, y un campo mal escrito o ausente no se detecta hasta que revienta al renderizar. Un layout robusto se defiende tipando lo que espera con una interface Props que declare la forma de frontmatter y dando valores por defecto al desestructurar. Así, el editor autocompleta los campos, el compilador avisa si el layout pide uno que el documento no trae, y el marco deja de confiar ciegamente en la cabecera del .mdx. Es el mismo salto de la fe a la garantía que ganan las content collections al validar con un esquema, aplicado aquí a mano en la frontera del layout.

Props inyectadas: qué llega y qué no

Junto a frontmatter, Astro entrega al layout de una página MDX un conjunto de props que no tuviste que declarar, útiles para construir cabeceras, índices y enlaces canónicos. Conviene conocerlas, y conviene sobre todo conocer una asimetría con Markdown que sorprende a quien la ignora.

  • frontmatter — el objeto con todos los campos de la cabecera del documento.
  • file — la ruta absoluta del fichero de origen en tu disco.
  • url — la URL pública de la página dentro del sitio.
  • headings — la lista de encabezados del documento, con la que se genera una tabla de contenidos.

De todas ellas, headings es la que más juego da y la que más justifica leer las props inyectadas. Es un array de objetos con la profundidad, el texto y el slug de cada encabezado del documento, extraído por Astro sin que tú analices el texto. Con él, el layout construye un índice navegable —un <nav> con un enlace por sección— que se mantiene solo: si el autor añade un encabezado en el .mdx, aparece en el índice sin tocar el layout. Es un ejemplo perfecto de dato derivado que el marco calcula una vez y muchas piezas consumen.

La asimetría es esta: rawContent() y compiledContent(), las funciones que en un layout de Markdown devuelven el texto crudo y el HTML compilado, no existen en MDX. La razón es de fondo: un .md es una cadena de texto que se puede devolver tal cual, pero un .mdx es un módulo con imports y componentes que no se reduce a una cadena, así que esas funciones no tendrían un valor coherente que devolver. Si escribes un layout pensando servir a los dos formatos, no dependas de ellas.

Envolver a mano importando el layout

La clave layout es cómoda pero limitada: solo pasa el frontmatter, y no te deja calcular props ni elegir a qué hueco va cada cosa. Cuando necesitas ese control, MDX te ofrece la vía explícita, que aprovecha que un documento MDX admite JSX: importas el layout como un componente y envuelves el contenido entre sus etiquetas, pasándole las props que quieras.

MDX
---title: Guía avanzada---import Articulo from '../../layouts/Articulo.astro';export const lecturaMin = 8;<Articulo titulo={title} minutos={lecturaMin}>## ContenidoEl cuerpo va como hijo del layout, en su slot por defecto.</Articulo>

Aquí no usas la clave layout: la omites, porque el marco lo pones tú con la etiqueta <Articulo>. A cambio de escribir un poco más, ganas todo lo que la vía declarativa te negaba: pasar props computadas como minutos, combinar varios valores, o incluso envolver solo una parte del documento. Recuerda el detalle de la lección de componentes —las líneas en blanco alrededor del contenido anidado— para que el Markdown interior se procese como tal.