Anidar frameworks distintos y pasar slots
Dentro de su propio JSX o plantilla, un componente de framework solo puede renderizar componentes del mismo framework; para mezclar React con Svelte o Vue con Solid, el terreno neutral es la plantilla .astro, que renderiza una isla y le pasa otra como slot. La regla dura que lo hace posible: las directivas client solo existen en ficheros .astro, nunca dentro del JSX de un framework, de modo que un componente anidado por importación comparte la hidratación de su padre, mientras que uno pasado como slot desde Astro conserva su propia directiva e hidrata por separado.
Cada framework solo renderiza a los suyos
Dentro del JSX o la plantilla de un componente, cada framework habita su propio mundo. Un componente de React puede importar y colocar otro componente de React en su árbol; ese es el modelo de composición normal del framework y funciona sin intervención de Astro. Lo que no puede es colocar un componente de Svelte o de Vue en su JSX, porque React no sabe renderizar nada que no sea React: su reconciliador espera elementos de React, no un componente compilado por otro motor.
// Panel.jsx de Reactimport Fila from './Fila.jsx'; // OK: React dentro de React// import Grafico from './G.svelte'; // no tiene sentido: React no renderiza Svelteexport default function Panel({ children }) { return ( <div class="panel"> <Fila /> {children} </div> );}Esta frontera es lógica, no arbitraria. Cada framework tiene su propio formato de elemento interno y su propio ciclo de vida; mezclarlos en un mismo árbol exigiría que uno supiera hablar el idioma del otro, cosa que ninguno hace. Por eso la composición entre frameworks distintos no ocurre dentro de un componente, sino un nivel por encima, en el único lugar que los conoce a todos.
Conviene subrayar que esta no es una restricción que Astro imponga, sino una que hereda. En una aplicación pura de cualquiera de estos frameworks ocurriría exactamente lo mismo: React nunca ha sabido montar un componente de Vue en su árbol, ni Svelte hospedar uno de Solid. Lo que Astro añade no es la barrera —que ya existía—, sino la salida: un terreno por encima de los frameworks donde la barrera deja de importar.
Componer frameworks distintos desde Astro
Ese lugar es la plantilla .astro. Un fichero de Astro puede renderizar una isla de cualquier framework y pasarle, como contenido anidado, una isla de otro framework. Astro renderiza el hijo por su cuenta y lo entrega al padre como HTML, que este coloca en su {children} o en el slot correspondiente.
---import Marco from '../components/Marco.jsx'; // Reactimport Grafico from '../components/Grafico.svelte'; // Svelte---<Marco client:load> <Grafico client:visible /></Marco>Aquí un marco de React envuelve un gráfico de Svelte, algo imposible dentro del JSX de Marco, pero trivial desde la plantilla. Astro renderiza Grafico a HTML, se lo pasa a Marco como children, y Marco lo sitúa donde su código indique. La plantilla .astro actúa de adaptador universal: al hablar el contrato común de renderers, puede encajar piezas de motores que jamás se entenderían entre sí directamente. Recuerda, eso sí, la ley de la lección anterior: para Marco, ese children es HTML ya impreso e inerte; no puede regenerarlo con su propio estado.
El mismo puente sirve para los slots con nombre. Si el componente de framework declara varios huecos, diriges contenido de Astro a cada uno con el atributo slot sobre el elemento anidado, exactamente como harías hacia un .astro. Astro renderiza cada fragmento por separado y lo entrega al hueco que le corresponde, sea ese fragmento texto, otro componente .astro o incluso otra isla.
---import Ficha from '../components/Ficha.jsx'; // React con props titulo y pieimport Sello from '../components/Sello.astro'; // .astro estatico---<Ficha client:load> <Sello slot="titulo" /> <p>Cuerpo en el slot por defecto.</p> <small slot="pie">Actualizado hoy</small></Ficha>Como viste en la segunda lección, un slot="titulo" de Astro aterriza en la isla de React como una prop titulo, el slot="pie" como una prop pie, y el resto del contenido como children. El framework no percibe que ese marcado nació en una plantilla de Astro ni que uno de los fragmentos era a su vez un componente .astro: solo ve HTML llegando a sus huecos. Esa opacidad es justo lo que vuelve universal al puente, porque le da igual de qué motor —o de ninguno— procede lo que recibe.
La directiva client: solo existe en .astro
Aquí está el detalle que lo gobierna todo y que conviene grabar: las directivas client: son una característica de la plantilla de Astro, no del JSX de ningún framework. Solo puedes escribir client:load, client:visible y compañía sobre un componente colocado en un fichero .astro. Dentro del JSX de React o de la plantilla de Vue, esa sintaxis no existe y no tendría a quién dirigirse.
La consecuencia es doble y precisa. Un componente que anidas por importación dentro del JSX de otro —como Fila dentro de Panel— no puede llevar directiva propia: forma parte del árbol del padre y se hidrata con él, como una sola isla indivisible. Un componente que pasas como slot desde una plantilla .astro —como Grafico dentro de Marco— conserva su propia directiva client: y se hidrata por su cuenta, como una isla independiente que resulta estar visualmente dentro de otra.
De ahí sale una prueba mental rápida: pregúntate por dónde entró el componente. Si lo escribiste en el JSX o la plantilla de otro framework, es parte de esa isla y no negocia su hidratación. Si lo colocaste en un fichero .astro, es una isla por derecho propio, con su directiva y su momento. El fichero donde vive la etiqueta, no su posición visual en la página, decide su destino.
Islas dentro de islas: quién hidrata a quién
Reunir las dos ideas resuelve casi cualquier duda sobre anidamiento. Cuando un framework contiene a otro por importación —solo posible dentro del mismo framework—, hay una sola isla: una directiva, un momento de hidratación, un bundle. Cuando la composición ocurre por slot desde Astro, hay tantas islas como componentes con directiva, cada una hidratándose en su propio momento, aunque el HTML de una quede anidado dentro del de otra.
---import Tabs from '../components/Tabs.jsx'; // React, la isla contenedoraimport Mapa from '../components/Mapa.svelte'; // Svelte, isla independienteimport Aviso from '../components/Aviso.astro'; // solo servidor, cero JS---<Tabs client:load> <Aviso slot="cabecera" /> <Mapa client:visible slot="cuerpo" /></Tabs>En esta escena conviven tres regímenes a la vez: Tabs es una isla de React que se hidrata al cargar; Mapa es una isla de Svelte que se hidrata al entrar en pantalla, independiente de Tabs aunque viva en su slot cuerpo; y Aviso es un .astro estático que nunca envía JavaScript. Tres piezas, tres destinos de ejecución distintos, coordinadas por una plantilla que no pertenece a ningún framework. Ese es el patrón que te deja construir interfaces mixtas sin renunciar al control fino de cuánto JavaScript paga cada región.
Y nada impide encadenar más niveles: la isla contenedora puede recibir por slot otra isla que a su vez envuelva a una tercera, cada una con su directiva y su framework. Mientras cada salto de composición suba a una plantilla .astro, la profundidad no tiene tope y cada capa conserva su destino de hidratación propio. La regla que resume todo el asunto es breve —la importación fija la pertenencia a un árbol y funde la hidratación; el slot preserva la independencia y la separa— y con ella decides, en cada anidamiento, si dos piezas son una isla o dos.