wandres.dev
LAYOUTS · plantillas compartidas

Layouts anidados

Componer un layout de sección dentro de un layout base: un BlogLayout que envuelve su slot en un article y a su vez vive dentro de Base. La cadena de slots, el reparto de responsabilidades y los límites sanos del anidamiento.

⏱ 15 min

Un solo layout raras veces basta para un sitio real. El armazón global —documento, cabecera, pie— lo comparten todas las páginas, pero un artículo del blog quiere además un <article> con su título y su fecha, y una página de documentación quiere una barra lateral. La respuesta no es hinchar el layout base con condicionales, sino anidar: un layout de sección que se especializa y que, por dentro, vive envuelto en el layout base.

🎯 Al terminar esta lección sabrás
  • Entender por qué un único layout no cubre sitios con secciones distintas.
  • Anidar un layout de sección dentro de un layout base reutilizando el marco global.
  • Seguir el recorrido del contenido a través de una cadena de dos <slot />.
  • Repartir las responsabilidades entre el marco global y el marco de sección.

Por qué anidar layouts

El layout base es dueño del documento: el <html>, el <head>, la navegación y el pie. Pero las secciones de un sitio no son iguales entre sí. Un artículo necesita un contenedor <article>, una cabecera con el título y la fecha, y una columna de lectura estrecha. Una página de docs necesita una barra lateral con el índice. Una landing quiere ir a todo el ancho sin cabecera interna. Todo eso es estructura, pero estructura de sección, no de sitio.

Podrías meterlo todo en el layout base con ramas condicionales —“si es un post, envuelve en <article>; si es docs, pinta la barra lateral”—, pero ese camino lleva a un fichero monstruoso que lo sabe todo de todas las secciones y crece sin control. El anidamiento ofrece la alternativa limpia: en lugar de un layout que se ramifica, muchos layouts pequeños que se componen. Cada sección tiene su propio layout, y todos comparten el base envolviéndose en él.

Un layout que usa otro layout

Como un layout es solo un componente, nada impide que un layout importe y use otro layout. Ese es el mecanismo entero del anidamiento: el layout de sección se escribe exactamente como una página que usa un layout, salvo que él mismo expone un <slot /> para su propio contenido.

---
// src/layouts/BlogLayout.astro
import Base from './Base.astro';
const { title, date } = Astro.props;
---
<Base title={title}>
  <article>
    <h1>{title}</h1>
    <time>{date}</time>
    <slot />
  </article>
</Base>

Lee con calma lo que hace BlogLayout. Recibe sus propias props, title y date. Usa Base como envoltorio y le reenvía hacia arriba lo que Base necesita —el title, para el <head>—. Y coloca su propio <slot /> dentro de un <article>, junto al encabezado y la fecha. Es a la vez consumidor de un layout y proveedor de otro: por arriba usa a Base, por abajo sirve a las páginas.

La página del blog, por su parte, usa BlogLayout sin enterarse de que Base existe:

---
// src/pages/blog/primer-post.astro
import BlogLayout from '../../layouts/BlogLayout.astro';
---
<BlogLayout title="Mi primer post" date="2026-07-01">
  <p>El cuerpo del artículo va aquí, y aterriza dentro del article.</p>
</BlogLayout>

La cadena de slots

Lo elegante del anidamiento es cómo viaja el contenido. El párrafo de la página entra en el <slot /> de BlogLayout; ahí queda envuelto en el <article>; y ese <article> entero se convierte, a su vez, en los hijos de Base, que lo colocan en su propio <slot /> dentro del <body>. Es una cadena de proyecciones: el contenido atraviesa dos huecos y sale envuelto en dos capas.

flowchart TD
PAG[contenido de la pagina] --> S1[slot de BlogLayout]
S1 --> ART[envuelto en article]
ART --> S2[slot de Base]
S2 --> BODY[dentro del body]
BODY --> HTML[documento html final]
style S1 fill:#89b4fa,color:#11111b
style S2 fill:#f9e2af,color:#11111b
style HTML fill:#a6e3a1,color:#11111b

Lo decisivo es que cada capa solo conoce a su vecina inmediata. BlogLayout no sabe nada del <head> ni de la navegación: eso es asunto de Base. Base no sabe nada del <article> ni de la fecha: eso es asunto de la sección. Ninguna capa necesita entender la cadena completa para hacer su trabajo. Esta ignorancia por niveles es lo que mantiene el sistema comprensible por mucho que crezca: para razonar sobre BlogLayout te basta con saber qué le pide a Base y qué ofrece a las páginas, sin cargar en la cabeza el documento entero.

Especialización por sección

Con esta técnica, un sitio real se organiza como un árbol de composición. Un único Base en la raíz; colgando de él, un layout por cada sección con su estructura propia; y colgando de cada uno, las páginas.

🏛️

Base

El marco global: <html>, <head>, navegación y pie. Lo que comparte absolutamente todo el sitio, escrito una sola vez.

📰

BlogLayout

La estructura del artículo: <article>, título, fecha, columna de lectura. Usa Base y le reenvía el título.

📚

DocsLayout

La estructura de la documentación: barra lateral con el índice y contenido principal. También se apoya en Base.

Las props fluyen hacia arriba por la cadena tanto como el contenido fluye hacia dentro: BlogLayout recibe title de la página y se lo pasa a Base. Comparado con el anti-patrón del layout único lleno de condicionales, este reparto es más fácil de leer, de probar y de extender: añadir una sección nueva es escribir un layout nuevo que use Base, sin tocar nada de lo existente.

⚠️
Un solo documento y anidamiento con mesura

Solo el layout de la raíz —Base— debe renderizar el <html>, el <head> y el <!doctype html>. Los layouts de sección nunca los repiten: si BlogLayout abriera su propio <html>, obtendrías documentos anidados e inválidos. En cuanto a la profundidad, dos o tres niveles son sanos y expresivos; encadenar cinco o seis layouts vuelve difícil seguir de dónde sale cada etiqueta. Si la cadena se alarga demasiado, suele ser señal de que alguna capa debería ser un componente normal, no un layout.

Los layouts se componen como funciones, y el documento es su resultado

El anidamiento de layouts revela que un layout no es una plantilla estática sino, en esencia, una función que toma contenido y devuelve contenido envuelto. Base es una función que recibe unos hijos y los rodea de documento; BlogLayout es otra que recibe unos hijos y los rodea de artículo, y que además llama a Base con su resultado. Anidar layouts es, ni más ni menos, componer funciones: la salida de una se convierte en la entrada de la otra, y el documento final es lo que emerge al aplicar la cadena entera. Esta lente lo explica todo de golpe. Explica por qué el orden importa —article dentro de body, no al revés—, porque componer funciones no es conmutativo. Explica por qué cada capa solo conoce a su vecina, porque en una composición cada función solo ve su argumento y su valor de retorno, jamás el interior de las demás. Y explica por qué el patrón escala sin volverse frágil: puedes insertar una capa nueva en medio de la cadena —un layout que añada, digamos, un aviso de cookies— sin reescribir las de arriba ni las de abajo, exactamente como intercalas una función en una tubería de transformaciones. Cuando dejas de ver los layouts como cajas que contienen cajas y empiezas a verlos como transformaciones que se encadenan, ganas el modelo mental que usan los buenos ingenieros para razonar sobre sistemas enteros: no como jerarquías de cosas, sino como composiciones de funciones, donde la complejidad se domina partiéndola en pasos pequeños que se combinan. El documento HTML que llega al navegador no es un objeto que alguien construyó de una vez, sino el punto final de una tubería de envoltorios, y verlo así es empezar a pensar en composición.

⚔️ Construye una cadena de dos capas
  1. Parte de tu Base.astro y crea BlogLayout.astro que lo importe, reciba title y date, y envuelva su <slot /> en un <article> con encabezado y fecha.
  2. Escribe una página en src/pages/blog/ que use BlogLayout y comprueba en el HTML generado que tu contenido queda dentro del <article> y este dentro del <body> de Base.
  3. Verifica que solo Base emite el <html> y el <head>: confirma que no hay etiquetas de documento duplicadas.
  4. Añade un DocsLayout que también se apoye en Base con una estructura distinta y razona cómo las props suben por la cadena hasta el <head> compartido.