Entendiendo la sintaxis de los archivos .astro: frontmatter, HTML y expresiones JS

DUGLAS MORENODUGLAS MORENO 👁 21

Introducción

Astro es un framework moderno para construir sitios web rápidos y enfocados en el contenido. Su gran ventaja es que permite escribir componentes usando una sintaxis muy parecida a HTML, pero con la potencia de JavaScript y la posibilidad de incluir datos mediante frontmatter. En este artículo vamos a explorar en detalle cómo se estructuran los archivos .astro, qué es el frontmatter, cómo se escribe HTML dentro de ellos y cómo usar expresiones de JavaScript para generar contenido dinámico. Cada concepto se acompañará de ejemplos con su salida esperada, de modo que podás copiar y pegar el código y ver el resultado inmediatamente.

Este tutorial está pensado para desarrolladores que ya conocen HTML, CSS y JavaScript básico y quieren aprender a aprovechar Astro sin tener que leer documentación extensa. Al final, vas a ser capaz de crear páginas y componentes .astro con confianza, sabiendo cuándo usar cada característica y evitando los errores más comunes.


¿Qué es un archivo .astro y por qué usarlo?

Un archivo con la extensión .astro es el bloque de construcción fundamental de un proyecto Astro. En esencia, es un archivo que mezcla tres capas:

  1. Frontmatter (opcional): bloque de datos en formato YAML, JSON o JavaScript que se ejecuta en tiempo de compilación y pone a disposición variables para el template.
  2. HTML: la estructura de la página o componente, escrita como HTML estándar.
  3. Expresiones de JavaScript: fragmentos de código entre llaves {} que se evalúan y cuyo resultado se inserta en el HTML.

Esta combinación permite escribir prácticamente cualquier UI sin necesidad de aprender un DSL complejo, y al mismo tiempo obtener los beneficios de la generación estática (SSG) o de renderizado bajo demanda (SSR) que ofrece Astro.


Estructura básica de un archivo .astro

Un archivo .astro típico tiene esta forma:

---
// Frontmatter (opcional)
const title = 'Mi primera página'
const items = ['Astro', 'React', 'Svelte']
---

<!DOCTYPE html>
<html lang='es'>
  <head>
    <meta charset='utf-8' />
    <title>{title}</title>
  </head>
  <body>
    <h1>{title}</h1>
    <ul>
      {#each items as item}
        <li>{item}</li>
      {/each}
    </ul>
  </body>
</html>

En el ejemplo anterior vemos claramente las tres partes: el bloque entre --- es el frontmatter, luego viene el HTML y dentro de él usamos expresiones {} y la directiva {#each} para iterar.


Frontmatter: definición y uso

El frontmatter es la sección que está delimitada por tres guiones (---) al inicio y al final del archivo. Todo lo que está dentro se trata como código JavaScript que se ejecuta una sola vez durante la fase de compilación. Por eso es ideal para definir datos estáticos, cargar archivos externos, o realizar cualquier lógica que no necesite correr en el cliente.

Sintaxis soportada

Astro acepta tres formatos para el frontmatter:

  • YAML (el más común)
  • JSON
  • JavaScript/TypeScript (bloque sin etiquetas)

A continuación, mostramos cada uno con el mismo conjunto de datos.

Ejemplo en YAML

---
title: 'Blog de Astro'
author:
  name: 'Lucía'
  site: 'https://lucia.dev'
tags: ['astro', 'frontend', 'tutorial']
---

<h1>{title}</h1>
<p>Autor: {author.name}</p>

Salida esperada

<h1>Blog de Astro</h1>
<p>Autor: Lucía</p>

Ejemplo en JSON

---
{
  "title": "Blog de Astro",
  "author": {
    "name": "Lucía",
    "site": "https://lucia.dev"
  },
  "tags": ["astro", "frontend", "tutorial
  ]
}
---

<h1>{title}</h1>
<p>Autor: {author.name}</p>

Salida esperada

<h1>Blog de Astro</h1>
<p>Autor: Lucía</p>

Ejemplo en JavaScript puro

---
export const title = 'Blog de Astro'
export const author = { name: 'Lucía', site: 'https://lucia.dev' }
export const tags = ['astro', 'frontend', 'tutorial']
---

<h1>{title}</h1>
<p>Autor: {author.name}</p>

Salida esperada

<h1>Blog de Astro</h1>
<p>Autor: Lucía</p>

Nota: En la sintaxis de JavaScript/TypeScript se debe usar export (o const con export) para que las variables queden expuestas al template. Si omites export, las variables no estarán disponibles fuera del frontmatter.


HTML dentro de .astro

Después del cierre del frontmatter (la segunda línea ---) comienza el HTML. Astro no impone restricciones: podés escribir cualquier etiqueta válida, incluidos componentes personalizados, SVG, o incluso fragmentos de plantillas de otros frameworks (aunque esos deberán ser hidratados por separado).

HTML estático

Un fragmento de HTML sin expresiones se renderiza tal cual. Por ejemplo:

---
---
<section>
  <h2>Bienvenido</h2>
  <p>Este es un párrafo estático.</p>
</section>

Salida esperada

<section>
  <h2>Bienvenido</h2>
  <p>Este es un párrafo estático.</p>
</section>

HTML con atributos dinámicos

Podés usar expresiones dentro de los atributos de una etiqueta. Astro interpreta el contenido de {} y lo inserta como valor del atributo.

---
const url = 'https://example.com'
const titulo = 'Visita Example'
---

<a href={url} title={titulo}>Cliqueá aquí</a>

Salida esperada

<a href="https://example.com" title="Visita Example">Cliqueá aquí</a>

Tip: Si el valor de la expresión resulta undefined o null, Astro elimina el atributo completo del nodo resultante. Esto es útil para atributos opcionales como disabled o required.


Expresiones de JavaScript: {}

Las llaves son la puerta de entrada al poder de JavaScript dentro del template. Cualquier expresión válida que produzca un valor puede ir dentro de {} y su resultado se colocará en el punto donde aparece.

Variables y constantes del frontmatter

Cualquier variable exportada en el frontmatter puede usarse directamente.

---
export const saludo = 'Hola, mundo!'
---

<p>{saludo}</p>

Salida esperada

<p>Hola, mundo!</p>

Operaciones y llamadas a funciones

Podés realizar operaciones aritméticas, llamar a funciones, usar operadores ternarios, etc.

---
export const precio = 19.99
---

<p>El precio con IVA es: {precio * 1.21}</p>

{/* Operador ternario */}
<p>{precio > 10 ? 'Caro' : 'Barato'}</p>

Salida esperada

<p>El precio con IVA es: 24.187999999999998</p>
<p>Caro</p>

Renderizado de arreglos y objetos

Si la expresión devuelve un arreglo o un objeto, Astro lo convierte a su representación de cadena (lo cual rara vez es útil). Por eso, para iterar o acceder a propiedades usamos directivas especiales (ver más abajo) o desestructuramos previamente.

---
export const frutas = ['manzana', 'banana', 'cereza']
---

<ul>
  {#each frutas as fruta}
    <li>{fruta<li>{fruta}</li>{/each}
</ul>

Salida esperada

<ul>
  <li>manzana</li>
  <li>banana</li>
  <li>cereza</li>
</ul>

Nota: La sintaxis {#each}...{/each} es una de las directivas de Astro que veremos en la siguiente sección.


Directivas de Astro

Astro incluye un conjunto de directivas que permiten controlar el renderizado de forma declarativa, similar a lo que hacen frameworks como Svelte o Vue, pero sin enviar JavaScript al cliente (a menos que lo hidrates explícitamente). Las directivas más usadas son:

  • class: para aplicar clases condicionalmente
  • style: para establecer estilos en línea
  • if: para renderizado condicional
  • for: o {#each}...{/each} para iterar
  • set:html para insertar HTML sin escapar
  • set:text para insertar texto sin escapar (valor predeterminado)

class: y style:

---
export const activo = true
export const color = 'tomato'
---

<button class:activo={activo} style:color={color}>
  Botón dinámico
</button>

Salida esperada

<button class="activo" style="color: tomato;
">Botón dinámico</button>

Cuando la expresión de class: resulta falsa, la clase no se incluye en el nodo.

if: (renderizado condicional)

---
export const mostrar = false
---

{if:mostrar}
  <p>Este párrafo solo se ve si mostrar es true.</p>
{:else}
  <p>Mostrando el mensaje alternativo.</p>
{/if}

Salida esperada

<p>Mostrando el mensaje alternativo.</p>

for: y {#each}...{/each}

Para iterar sobre un arreglo o un objeto iterable, Astro ofrece la directiva for: (atributo) o la sintaxis de bloque {#each}. Ambas son equivalentes; la de bloque suele ser más legible para estructuras anidadas.

Usando el atributo for:

---
export const números = [1, 2, 3, 4]
---

<ul for:número={números}>
  <li>{número}</li>
</ul>

Salida esperada

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>

Usando el bloque {#each}

---
export const usuarios = [
  { nombre: 'Ana', edad: 28 },
  { nombre: 'Luis', edad: 34 },
]
---

<ul>
  {#each usuarios as usuario}
    <li>{usuario.nombre} ({usuario.edad} años)</li>
  {/each}
</ul>

Salida esperada

<ul>
  <li>Ana (28 años)</li>
  <li>Luis (34 años)</li>
</ul>

set:html (insertar HTML sin escapar)

Por defecto, Astro escapa cualquier contenido que se interpola con {} para evitar XSS. Si necesitás insertar HTML confiable (por ejemplo, proveniente de un CMS), usás set:html.

---
export const alerta = "<strong>¡Atención!</strong> Este es un mensaje importante." 
---

<div set:html={alerta}></div>

Salida esperada

<div><strong>¡Atención!</strong> Este es un mensaje importante.</div>

Advertencia: Nunca uses set:html con datos que provengan directamente del usuario sin sanitizarlos previamente.


Importar y usar otros componentes .astro

Astro permite crear componentes reutilizables y luego importarlos en cualquier otro archivo .astro o en páginas de Markdown. La sintaxis de import es la misma que en ES modules.

Creando un componente de tarjeta

src/components/Card.astro

---
export const { title, contenido } = Astro.props
---

<div class='card'>
  <h2>{title}</h2>
  <p>{contenido}</p>
</div>

Usando el componente en una página

src/pages/index.astro

---
import Card from '../components/Card.astro'
---

<Card title='Bienvenido' contenido='Esta es una tarjeta de ejemplo.' />
<Card title='Otra tarjeta' contenido='Podés pasar cualquier prop que necesites.' />

Salida esperada

<div class='card'>
  <h2>Bienvenido</h2>
  <p>Esta es una tarjeta de ejemplo.</p>
</div>
<div class='card'>
  <h2>Otra tarjeta</h2>
  <p>Podés pasar cualquier prop que necesites.</p>
</div>

Tip: Los componentes reciben sus propiedades a través del objeto Astro.props. Podés destructurar directamente en el export del frontmatter como se mostró arriba.


Buenas prácticas y errores comunes

Buenas prácticas

  1. Manté el frontmatter limpio y tipado: si usas TypeScript, agrega export interface o export type para definir la forma de tus datos. Esto ayuda a capturar errores en tiempo de compilación.
  2. Preferí expresiones cortas en las llaves: si la lógica se vuelve compleja, extraela a una función o a un helper y exportalo desde el frontmatter.
  3. Usá directivas para lógica de presentación: class:, style:, if: y for: hacen que el template sea más legible que mezclando mucho JavaScript dentro de {}.
  4. Escapé por defecto: confié en el escaping automático de {} para evitar inyecciones. Solo recurras a set:html cuando estés absolutamente seguro del origen.
  5. Importá componentes con rutas relativas claras: evita importaciones absolutas que rompan al mover el proyecto; usa alias configurados en tsconfig.json si los necesitás.

Errores comunes

  • Olvidar export en el frontmatter: las variables no estarán disponibles en el template, provocando que {nombre} se renderice como texto literal nombre.
  • Usar doble llave {{}} por hábito de otros frameworks: en Astro eso se trata como texto literal y no se evalúa.
  • Insertar datos de usuario sin sanitizar en set:html: abre una vulnerabilidad XSS.
  • Confundir for: como atributo con {#each}: ambos funcionan, pero mezclarlos en el mismo elemento puede generar comportamientos inesperados.
  • Dejar etiquetas HTML sin cerrar: aunque Astro es permisivo, el HTML resultante puede romper el DOM del navegador.

Conclusión

Los archivos .astro son una forma poderosa y sencilla de combinar datos, lógica y marcado en una sola unidad de compilación. Hemos visto cómo el frontmatter nos brinda un lugar seguro para definir variables y ejecutar código de tiempo de compilación, cómo el HTML estándar forma la base de nuestra UI y cómo las expresiones de JavaScript y las directivas nos permiten crear contenido dinámico sin enviar JavaScript innecesario al navegador.

Con los ejemplos provistos, ya podés:

  • Escribir frontmatter en YAML, JSON o JavaScript.
  • Usar {} para interpolar valores y ejecutar operaciones.
  • Aplicar clases y estilos condicionalmente con class: y style:.
  • Renderizar listas y condicionales con for:/{#each} y if:.
  • Insertar HTML confiable mediante set:html.
  • Crear y reutilizar componentes .astro mediante importación y props.

Recordá siempre seguir las buenas prácticas: mantener el frontmatter tipado, preferir directivas para la presentación, escapar por defecto y validar cualquier dato externo antes de usar set:html.

Si querés seguir profundizando, la documentación oficial de Astro muestra cómo combinar estos archivos con frameworks de UI (React, Svelte, Vue) para islas de interactividad, cómo optimizar imágenes y cómo desplegar en diversos proveedores de alojamiento. Pero con lo aprendido acá ya estás listo para construir sitios estáticos rápidos, mantenibles y libres de bloat.

¡Manos a la obra y empezá a crear con Astro hoy mismo!

Comentarios (0)

Sé el primero en comentar.

Dejá tu comentario