import ReadMore from '~/components/ReadMore.astro';

Los componentes de Astro son los elementos básicos de cualquier proyecto de Astro. Son componentes de plantillas HTML sin tiempo de ejecución del lado del cliente y utilizan la extensión de archivo .astro.

:::note Si sabes HTML, ya sabes lo suficiente para escribir tu primer componente de Astro.

Más información en la referencia sintáctica de Astro. :::

Los componentes de Astro son extremadamente flexibles. Un componente de Astro puede ser tan pequeño como un fragmento de HTML, como una colección de etiquetas comunes <meta> que facilitan el trabajo con SEO. Los componentes pueden ser elementos de interfaz de usuario reutilizables, como una cabecera o una tarjeta de perfil. Los componentes de Astro pueden incluso contener un diseño de página completo o, cuando se encuentran en la carpeta especial src/pages/, ser una página completa.

Lo más importante que hay que saber sobre los componentes de Astro es que no se renderizan en el cliente. Se renderizan en HTML en el momento de la compilación o bajo demanda. Puedes incluir código JavaScript dentro del frontmatter de tu componente, y todo será eliminado de la página final enviada a los navegadores de tus usuarios. El resultado es un sitio más rápido, sin ninguna huella de JavaScript añadida por defecto.

Cuando tu componente Astro necesite interactividad en el lado del cliente, puedes añadir etiquetas HTML estándar <script> o componentes UI Framework como "islas cliente".

Para los componentes que necesitan mostrar contenido personalizado o dinámico, puede aplazar su presentación en el servidor añadiendo una [directiva de servidor] (/es/reference/directives-reference/#directivas-del-servidor). Estas "islas de servidor" renderizarán su contenido cuando esté disponible, sin retrasar la carga completa de la página.

Estructura de un componente

Un componente de Astro se compone de dos partes principales: el script del componente y el maquetado del componente. Cada parte cumple una función diferente, pero juntas proveen un marco de trabajo más fácil de utilizar y lo suficientemente expresivo para manejar cualquier cosa que desees construir.

astro
---// Script del componente (JavaScript)---<!-- Maquetado del componente (HTML + Expresiones JS) -->

Script de un componente

Astro utiliza una valla de código (---) para identificar el script del componente Astro. Si has escrito Markdown anteriormente deberías estar familiarizado con un concepto similar llamado frontmatter. El script del componente de Astro fue inspirado por este concepto.

Puedes utilizar el script del componente para escribir cualquier código de JavaScript que necesites para renderizar el maquetado. Esto puede incluir:

  • Importar otros componentes Astro
  • Importar componentes de otros frameworks, como React
  • Importar datos, como un archivo JSON
  • Consultar contenido de una API o base de datos
  • Crear variables que luego puedes referenciar en tu maquetado
astro
---import UnComponenteAstro from '../components/UnComponenteAstro.astro';import UnComponenteReact from '../components/UnComponenteReact.jsx';import algunosDatos from '../data/pokemon.json';// Acceder a props recibidas, por ejemplo `<X title="Hola Mundo" />`const { title } = Astro.props;// Consultar datos externos, de una API privada o base de datosconst datos = await fetch('API_URL_SECRETA/users').then(r => r.json());---<!-- ¡Tu maquetado va aquí! -->

La valla de código está diseñada para garantizar que el código JavaScript que escribes adentro se encuentre "encapsulado". Este código no se filtrará a tu aplicación, o llegará al usuario final. Puedes escribir código que sea costoso o sensible (como una llamada a la base de datos) sin preocuparte por que estos datos sensibles lleguen al navegador del usuario.

:::note El script del componente de Astro es TypeScript, que permite añadir sintaxis adicional a JavaScript para herramientas de edición y comprobación de errores.

Más información sobre el soporte integrado de TypeScript de Astro. :::

Maquetado del componente

El maquetado del componente se encuentra debajo de la valla de código y determina la salida HTML de tu componente.

Si escribes solo HTML en esta sección, el componente va a renderizar este HTML en cualquier página Astro donde sea importado o utilizado.

Sin embargo, el maquetado de componentes de Astro también soporta expresiones de JavaScript, etiquetas <style> y <script> de Astro, componentes importados, y directivas especiales de Astro. Los datos y valores definidos en el script del componente pueden ser usados en el maquetado del componente para producir HTML creado dinámicamente.

astro
---// El script de tu componente va aquí!import Banner from '../components/Banner.astro';import Avatar from '../components/Avatar.astro';import ReactPokemonComponent from '../components/ReactPokemonComponent.jsx';const misPokemonesFavoritos = [/* ... */];const  { title } = Astro.props;---<!-- ¡Soporta comentarios HTML! -->{/* La sintaxis de comentario de JS es también válida */}<h1>¡Hola mundo!</h1><!-- Utiliza props y otras variables definidas en el script del componente: --><p>{title}</p><!-- Retrasa el renderizado del componente y proporciona contenido de carga alternativo: --><Avatar server:defer>  <svg slot="alternativo" class="avatar-genérico" transition:name="avatar">...</svg></Avatar><!-- Incluye otros componentes UI con la directiva de hidratación `client:`: --><ReactPokemonComponent client:visible /><!-- Puedes mezclar HTML con expresiones de JavaScript, similar a JSX: --><ul>  {misPokemonesFavoritos.map((data) => <li>{data.name}</li>)}</ul><!-- ¡Usa una directiva de maquetado para crear nombres de clase a partir de múltiples strings o incluso objetos! --><p class:list={["agregar", "dinámico", { classNames: true }]} />

Diseño basado en componentes

Los componentes son diseñados para ser reusables y componibles. Puedes usar componentes dentro de otros componentes para construir UI más y más avanzada. Por ejemplo, un componente Button podría ser usado para crear un componente ButtonGroup:

astro
---import Button from './Button.astro';---<div>  <Button title="Botón 1" />  <Button title="Botón 2" />  <Button title="Botón 3" /></div>

Props de componentes

Un componente de Astro puede definir y aceptar props. Estas props estarán disponibles para ser utilizadas en el renderizado del maquetado HTML y además estarán disponibles en el script del componente de manera global dentro del objeto Astro.props.

Aquí vemos un ejemplo de un componente que recibe una prop saludo y otra nombre. Fíjate que las props a recibir están desestructuradas del objeto global Astro.props.

astro
---// src/components/GreetingHeadline.astro// Utilización: <GreetingHeadline saludo="Qué tal" nombre="Amiga" />const { saludo, nombre } = Astro.props---<h2>{saludo}, {nombre}!</h2>

Este componente, cuando se importa y renderiza en otros componentes, layouts o páginas de Astro, puede pasar estas props como atributos:

astro
---// src/components/GreetingCard.astroimport GreetingHeadline from './GreetingHeadline.astro';const name = 'Astro';---<h1>Tarjeta de saludos</h1><GreetingHeadline greeting="Hola" name={name} /><p>¡Espero que tenga un día maravilloso!</p>

También puedes definir props con TypeScript usando una interfaz de tipo Props. Astro recogerá automáticamente la interfaz Props en el frontmatter y dará advertencias/errores de tipo para tu proyecto. A estas propiedades también se les puede dar valores predeterminados cuando se desestructuran desde Astro.props.

astro
---// src/components/GreetingHeadline.astrointerface Props {  nombre: string;  saludo?: string;}const { saludo = "Hola", nombre } = Astro.props;---<h2>{saludo}, {nombre}!</h2>

A los props de componentes se les pueden dar valores predeterminados para usar cuando no se proporciona ninguno.

astro
---// src/components/GreetingHeadline.astroconst { greeting = "Hola", name = "Astronauta" } = Astro.props;---<h2>¡{greeting}, {name}!</h2>

Slots

El elemento <slot /> es un espacio reservado para contenido HTML externo, permitiéndote inyectar (o ingresar en la "ranura") elementos hijos provenientes de otros archivos en el maquetado de tu componente.

Por defecto, todos los elementos hijos que le sean enviados a un componente serán renderizados en su <slot />.

:::note Diferente a props, que son atributos enviados a un componente Astro y disponibles para utilizar con Astro.props, los slots renderizan elementos HTML hijos donde se lo indique. :::

astro
---// src/components/Wrapper.astroimport Header from './Header.astro';import Logo from './Logo.astro';import Footer from './Footer.astro';const { titulo } = Astro.props;---<div id="content-wrapper">  <Header />  <Logo />  <h1>{titulo}</h1>  <slot />  <!-- aquí van los hijos -->  <Footer /></div>
astro
---// src/pages/fred.astroimport Wrapper from '../components/Wrapper.astro';---<Wrapper titulo="Página de Fred">  <h2>Todo sobre Fred</h2>  <p>Aquí veremos cosas sobre Fred.</p></Wrapper>

Este patrón es la base de un maquetado de componente Astro: todo el contenido HTML de una página puede ser “envuelto” con etiquetas <SomeLayoutComponent></SomeLayoutComponent> y enviadas al componente para que se renderice dentro de elementos comunes de página definidos allí.

{/* TODO: add link to Astro.slots (/es/reference/astro-syntax/#astroslots) */} Consulta sobre funciones de utilidad Astro.slots para más formas de acceder y renderizar contenido de slots.

Slots con nombre

Un componente de Astro también puede tener slots con nombre. Esto te permite compartir elementos HTML únicamente con el nombre correspondiente al slot.

Los slots se nombran usando el atributo name:

astro
---// src/components/Wrapper.astroimport Header from './Header.astro';import Logo from './Logo.astro';import Footer from './Footer.astro';const { titulo } = Astro.props;---<div id="content-wrapper">  <Header />  <!--  hijos con el atributo `slot="after-header"` van aquí -->  <slot name="after-header" />  <Logo />  <h1>{titulo}</h1>  <!--  hijos sin `slot`, o con el atributo `slot="default"` van aquí -->  <slot />  <Footer />  <!--  hijos con el atributo `slot="after-footer"` van aquí -->  <slot name="after-footer" /></div>

Para inyectar contenido HTML en un slot particular, usa el atributo slot en cualquier elemento hijo para especificar el nombre del slot. Todos los demás elementos hijos del componente serán inyectados en el slot por defecto (sin nombre) <slot />.

astro
---// src/pages/fred.astroimport Wrapper from '../components/Wrapper.astro';---<Wrapper titulo="Página de Fred">  <img src="https://my.photo/fred.jpg" slot="after-header" />  <h2>Todo sobre Fred</h2>  <p>Aquí veremos cosas sobre Fred.</p>  <p slot="after-footer">Copyright 2022</p></Wrapper>

:::tip Utiliza un atributo slot="mi-slot" en el elemento hijo que quieras enviar junto con su <slot name="mi-slot" /> emparejado en tu componente. :::

Para pasar múltiples elementos HTML dentro del placeholder <slot/> de un componente sin un <div> envolvente, usa el atributo slot="" en el componente <Fragment/> de Astro:

astro
---// Crea una tabla personalizada con placeholders de slots con nombre para el contenido del header y el body---<table class="bg-white">  <thead class="sticky top-0 bg-white"><slot name="header" /></thead>  <tbody class="[&_tr:nth-child(odd)]:bg-gray-100"><slot name="body" /></tbody></table>

Inyecta múltiples filas y columnas de contenido HTML usando el atributo slot="" para especificar el contenido "header" y "body". Los elementos HTML individuales también pueden ser estilizados:

astro
---import CustomTable from './CustomTable.astro';---<CustomTable>  <Fragment slot="header"> <!-- agrega un encabezado para la tabla -->    <tr><th>Nombre del producto</th><th>Unidades disponibles</th></tr>  </Fragment>  <Fragment slot="body"> <!-- pasar el cuerpo de la tabla -->    <tr><td>Chanclas</td><td>64</td></tr>    <tr><td>Botas</td><td>32</td></tr>    <tr><td>Tenis</td><td class="text-red-500">0</td></tr>  </Fragment></CustomTable>

Ten en cuenta que los slots con nombre deben ser hijos inmediatos del componente. No puedes pasar slots con nombre a través de elementos anidados.

:::tip Los slots con nombre también se pueden pasar a componentes de framework en archivos Astro. :::

:::note No es posible generar dinámicamente un nombre de slot de Astro, tal como dentro de una función map. Si esta característica es necesaria dentro de un componente de framework UI, podría ser mejor generar estos slots dinámicos dentro del framework mismo. :::

Contenido alternativo para slots

Los slots también pueden renderizar contenido alternativo en el caso que no reciban datos con <slot /> para emparejar, sea slot con nombre o no.

astro
---// src/components/Wrapper.astroimport Header from './Header.astro';import Logo from './Logo.astro';import Footer from './Footer.astro';const { titulo } = Astro.props;---<div id="content-wrapper">  <Header />  <Logo />  <h1>{titulo}</h1>  <slot>    <p>Este es mi contenido alternativo, si no hay ningún elemento pasado al slot</p>  </slot>  <Footer /></div>

El contenido de reserva solo se mostrará cuando no se pasen elementos coincidentes con el atributo slot="nombre" a un slot con nombre.

Astro pasará un slot vacío cuando un elemento slot exista pero no tenga contenido para pasar. El contenido de reserva no puede ser usado como un valor predeterminado cuando se pasa un slot vacío. El contenido de reserva solo se mostrará cuando no se pueda encontrar un elemento slot.

Transferir slots

Los slots pueden ser transferidos a otros componentes. Por ejemplo, cuando se crean plantillas anidadas:

astro
------<html lang="en">	<head>		<meta charset="utf-8" />		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />		<meta name="viewport" content="width=device-width" />		<meta name="generator" content={Astro.generator} />    <slot name="head" />	</head>	<body>		<slot />	</body></html>
astro
// src/layouts/HomeLayout.astro---import BaseLayout from './BaseLayout.astro';---<BaseLayout>  <slot name="head" slot="head" />  <slot /></BaseLayout>

:::note Los slots con nombre pueden ser transferidos a otro componente usando los atributos name y slot en una etiqueta <slot />. :::

Ahora, los slots por defecto y head pasados a HomeLayout serán transferidos al componente padre BaseLayout.

astro
// src/pages/index.astro---import HomeLayout from '../layouts/HomeLayout.astro';---<HomeLayout>	<title slot="head">Astro</title>	<h1>Astro</h1></HomeLayout>

Componentes HTML

Astro soporta importar y usar archivos .html como componentes o colocarlos dentro del subdirectorio src/pages/. Es posible que quieras usar componentes HTML si estás reusando código de un sitio existente construido sin usar frameworks, o si quieres asegurarte que tu componente no tiene características dinámicas.

Los componentes HTML solo deben contener HTML válido, y por lo tanto le faltarán características claves de los componentes de Astro.

  • Ellos no soportan el frontmatter, importaciones del lado del servidor, o expresiones dinámicas.
  • Cualquier etiqueta <script> quedan sin agrupar, son tratados como si tuvieran una directiva in:inline
  • Ellos solo pueden referenciar recursos que están en la carpeta public/.

:::note Un elemento <slot/> dentro de un componente HTML trabajar como lo haría en un componente de Astro. En cambio, para poder usar el elemento Componente Web HTML Slot añade is:inline al elemento slot. :::

Próximos Pasos

Aprende sobre el uso de componentes de frameworks UI en tu proyecto Astro.