Astro
Astro es dueño de la estructura estática: páginas, diseños y regiones puramente presentacionales.
SolidJS o React son dueños de toda la interactividad: cada componente que maneja entrada del usuario,
administra estado o responde a eventos es una isla de framework, no un archivo .astro.
Los Módulos CSS se utilizan para todos los estilos de componentes, siempre en un archivo separado
styles.module.css, nunca en línea ni dentro del bloque <style> de Astro.
Cuándo Usar Esta Habilidad
- Estructurar un nuevo proyecto Astro o agregar páginas y áreas de diseño
- Construir páginas
.astro, diseños o regiones presentacionales estáticas - Decidir si algo pertenece a Astro o a una isla de SolidJS/React
- Elegir qué directiva de hidratación usar para una isla
- Aplicar estilos con Módulos CSS dentro de archivos
.astroo islas de framework - Trabajar con colecciones de contenido (
src/content/,src/content.config.ts) - Conectar datos de la capa de servicios en páginas Astro renderizadas en servidor
- Usar islas de servidor (
server:defer) para regiones personalizadas diferidas - Configurar renderizado bajo demanda (SSR) con adaptadores y middleware
- Definir y llamar Acciones de Astro para mutaciones seguras de servidor
Astro vs Islas — La Decisión Arquitectónica Central
Esta es la decisión más importante en cualquier proyecto Astro.
| Qué hace | Usa |
|---|---|
| Renderiza HTML estático a partir de datos — sin interacción del usuario | .astro |
| Esqueleto de página, envoltorio de diseño, estructura de navegación | .astro |
| Secciones de contenido, publicaciones de blog, regiones de marketing | .astro |
Cualquier componente con onClick, onChange, estado de formulario o datos reactivos | Isla SolidJS o React |
| Componentes de UI fundamentales (Button, Input, Modal, Alert, etc.) | Isla SolidJS o React |
| Cualquier componente que lea o escriba en un store o hook de servicio | Isla SolidJS o React |
La regla en términos simples:
- Astro renderiza estructura y contenido. No maneja interacción del usuario.
- SolidJS o React maneja toda la interactividad, todo el estado de formularios y todos los primitivos de UI interactivos fundamentales, incluso un simple botón que dispara un evento.
- No construyas UI interactiva en archivos
.astro. Astro no tiene reactividad. Intentar agregar interactividad a un archivo.astroproduce código frágil y no comprobable.
¿Qué framework — SolidJS o React?
El proyecto usa uno de manera consistente. Revisa astro.config.mjs para la integración
configurada (@astrojs/solid-js o @astrojs/react) y usa ese framework para todas
las islas del proyecto. No mezcles ambos frameworks en el mismo proyecto.
Lee ./references/islands-and-hydration.md para la guía de decisión completa y la
referencia de directivas de hidratación.
Reglas de Estilo — Módulos CSS en Archivos Separados
Esta es la regla más crítica de esta habilidad.
Cada componente, página y diseño de Astro usa Módulos CSS para estilos con ámbito.
El CSS vive en un archivo separado, nunca dentro de la etiqueta <style> de Astro.
ComponentName/
├── index.astro ← lógica del componente y marcado
└── styles.module.css ← TODOS los estilos para este componente, siempre un archivo separado
- Siempre crea
styles.module.cssjunto aindex.astro. - Nunca pongas estilos dentro del bloque
<style>de Astro. - Nunca uses atributos
styleen línea. - Importa el módulo al principio de la valla de frontmatter:
import styles from './styles.module.css' - Aplica clases usando la directiva
class:listo enlace directo de clase:<div class={styles.container}><div class:list={[styles.container, isActive && styles.active]}>
- Usa nombres de clase semánticos. Sin apilamiento de clases utilitarias.
- Usa propiedades personalizadas CSS para todos los tokens de diseño (colores, espaciado, tipografía).
- Sin
!important. Sin selectores profundos. Sin selectores de ID para estilos.
Lee ./references/styling-and-css-modules.md para la estrategia de tokens, variables
de tema, reglas responsivas y guía de animaciones.
Lee ./examples/button-component/ para un ejemplo completo de Button con archivo
CSS Module separado.
Estructura del Proyecto
src/
├── components/
│ ├── foundation/ # Primitivos de UI interactivos — SolidJS o React, NO .astro
│ │ ├── Button/
│ │ │ ├── index.tsx ← SolidJS (.tsx) o React (.tsx)
│ │ │ └── styles.module.css
│ │ └── Input/
│ │ ├── index.tsx
│ │ └── styles.module.css
│ ├── layout/ # Estructura de diseño estático — .astro
│ │ ├── Header/
│ │ │ ├── index.astro
│ │ │ └── styles.module.css
│ │ └── Footer/
│ │ ├── index.astro
│ │ └── styles.module.css
│ └── features/ # Áreas de características interactivas — SolidJS o React
│ └── SomeFeature/
│ ├── index.tsx ← componente isla
│ └── styles.module.css
├── layouts/
│ └── BaseLayout/
│ ├── index.astro ← el esqueleto del diseño siempre es .astro
│ └── styles.module.css
├── pages/
│ ├── index/
│ │ ├── index.astro ← la página siempre es .astro
│ │ └── styles.module.css
│ └── [dynamic]/
│ ├── index.astro
│ └── styles.module.css
├── content/
│ ├── blog/
│ └── [collection-name]/
├── content.config.ts ← Esquemas y cargadores de colecciones de Astro 5
├── store/
│ ├── repository/
│ ├── service/
│ └── config.ts
├── styles/
│ ├── tokens/
│ │ ├── _colors.css
│ │ ├── _spacing.css
│ │ └── _typography.css
│ ├── global.css
│ └── themes/
│ ├── light.css
│ └── dark.css
└── utils/
Convenciones de nomenclatura:
- Páginas y diseños
.astro: carpetaPascalCase/conindex.astro - Componentes de isla de framework: carpeta
PascalCase/conindex.tsx - Páginas: carpeta
kebab-case/conindex.astroo[dynamic]/conindex.astro - Archivos CSS Module: siempre
styles.module.css— uno por directorio de componente - Utilidades:
kebab-case.ts
Lee ./references/project-structure.md para un desglose completo de las
responsabilidades de los directorios y las convenciones de nomenclatura.
Forma del Componente Astro
Los archivos .astro son solo para estructura estática. Renderizan HTML a partir de props y
datos — no manejan eventos ni administran estado.
- Usa props tipificadas mediante
interface Propsen la valla de frontmatter. - Accede a props con
Astro.props. - Mantén los componentes pequeños y de un solo propósito.
- Prefiere composición sobre perforación de props.
- Mantén las expresiones simples; mueve la lógica compleja a variables de frontmatter.
- Usa elementos HTML semánticos —
<section>,<article>,<nav>,<main>,<header>— en lugar de envoltorios<div>genéricos cuando el elemento tenga significado semántico.
---
import styles from './styles.module.css'
interface Props {
title: string
subtitle?: string
}
const { title, subtitle } = Astro.props
---
<section class={styles.hero} aria-label={title}>
<h1 class={styles.title}>{title}</h1>
{subtitle && <p class={styles.subtitle}>{subtitle}</p>}
<slot />
</section>
Lee ./references/component-patterns.md para convenciones de frontmatter, uso de slots
y referencia de la API de Astro.
Componentes Fundamentales — SolidJS o React, No Astro
Los primitivos de UI fundamentales (Button, Input, Alert, Modal, Select, Toggle, etc.)
siempre se construyen como componentes SolidJS o React. Nunca son archivos .astro.
Por qué: Los componentes fundamentales manejan eventos del usuario, administran el foco,
exponen callbacks onClick y onChange, y a veces tienen estado interno. Nada de esto es
posible en un archivo .astro. Construir un "botón" como .astro produce HTML estático
que no puede responder a clics de manera tipificada y reutilizable.
La regla de decisión:
- El primitivo existe — úsalo.
- El primitivo está cerca pero le falta una prop — extiende el primitivo existente.
- El primitivo no existe — créalo como un componente SolidJS o React en
components/foundation/antes de usarlo. Nunca coloques elementos interactivos únicos en componentes de página o característica.
Todos los componentes fundamentales deben ser consistentes, accesibles y fuertemente tipificados.
Consulta la habilidad solid.js o react para las convenciones de implementación que
se aplican dentro de los componentes isla.
Islas e Hidratación
Cada componente interactivo es una isla. Monta islas desde páginas y diseños .astro
usando una directiva client:*. Elige la directiva mínima que satisfaga el
requisito de interacción.
| Directiva | Cuándo usarla |
|---|---|
client:load | Debe ser interactivo inmediatamente al cargar la página |
client:idle | Puede esperar hasta que el navegador esté inactivo |
client:visible | Solo necesita hidratarse cuando entra en el viewport |
client:media="(query)" | Solo es interactivo en un tamaño de viewport específico |
client:only="solid-js" o client:only="react" | Requiere APIs del navegador en el renderizado; omite SSR |
Por defecto, usa client:visible o client:idle. Usa client:load solo para UI con la que
el usuario interactuará inmediatamente — formularios principales, desplegables de navegación, páginas de autenticación.
Los componentes isla siempre tienen su propio styles.module.css:
components/features/ContactForm/
├── index.tsx ← Isla SolidJS o React
└── styles.module.css ← CSS Module separado, misma regla que en todos lados
Montar una isla desde una página Astro:
---
import styles from './styles.module.css'
import ContactForm from '../../components/features/ContactForm/index.tsx'
const { prefillEmail } = Astro.props
---
<section class={styles.section}>
<h2 class={styles.heading}>Contáctanos</h2>
<ContactForm client:visible prefillEmail={prefillEmail} />
</section>
Lee ./references/islands-and-hydration.md para la guía de decisión completa,
notas específicas del framework y reglas de paso de datos.
Colecciones de Contenido
Las colecciones de contenido son la forma canónica de gestionar archivos Markdown, MDX y datos estructurados con seguridad de tipos TypeScript completa.
Cambios clave en Astro 5:
- La configuración está en
src/content.config.ts(nosrc/content/config.ts) - Las colecciones usan un
loader—glob()ofile()desdeastro/loaders render(entry)es una función importada deastro:content(noentry.render())- Importa
zdeastro:content, no directamente dezod
// src/content.config.ts
import { defineCollection, z, reference } from 'astro:content'
import { glob } from 'astro/loaders'
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.coerce.date(),
draft: z.boolean().default(false),
}),
})
export const collections = { blog }
Renderizar en una página:
---
import { getEntry, render } from 'astro:content'
const post = await getEntry('blog', Astro.params.slug)
const { Content } = await render(post)
---
<Content />
Lee ./references/content-collections.md para la API completa: cargadores, referencias
entre colecciones, cargadores personalizados, colecciones en tiempo de ejecución y patrones de ruta dinámica.
Islas de Servidor, SSR y Acciones
Islas de Servidor (server:defer)
Difiere un componente .astro personalizado o dinámico mientras se sirve el esqueleto de la página
inmediatamente. Requiere un adaptador.
<Observa que no se traduce la prop server:defer ya que es código>
<UserCart server:defer>
<span slot="fallback">···</span>
</UserCart>
El componente diferido se ejecuta del lado del servidor y se transmite. Úsalo para UI específica del usuario (contadores de carrito, notificaciones, saludos personalizados) que de otro modo bloquearían la entrega de la página estática.
Renderizado Bajo Demanda (SSR)
Opta por páginas en renderizado de servidor con export const prerender = false (modo híbrido)
o configura output: 'server' globalmente.
Las páginas SSR tienen acceso a Astro.cookies, Astro.request, Astro.redirect()
y Astro.locals (poblado por middleware).
Middleware
Define lógica de interceptación de solicitudes en src/middleware.ts:
import { defineMiddleware } from 'astro:middleware'
export const onRequest = defineMiddleware(async (context, next) => {
context.locals.user = await getUser(context.cookies.get('session')?.value)
return next()
})
Acciones de Astro
Funciones de servidor seguras de tipos definidas en src/actions/index.ts, invocables desde
islas o formularios HTML:
// src/actions/index.ts
import { defineAction, ActionError } from 'astro:actions'
import { z } from 'astro:content'
export const server = {
newsletter: {
subscribe: defineAction({
input: z.object({ email: z.string().email() }),
handler: async ({ email }) => {
await addSubscriber(email)
return { success: true }
},
}),
},
}
Llamar desde una isla:
import { actions } from 'astro:actions'
const { data, error } = await actions.newsletter.subscribe({ email })
Usa isInputError(error) para distinguir errores de validación Zod de errores del handler.
Lee ./references/server-rendering.md para cobertura completa: modos de renderizado,
configuración de adaptador, middleware, islas de servidor, APIs bajo demanda, acciones con formularios,
códigos de error, variables de entorno tipificadas (astro:env) y transiciones de vista.
Referencia de la API de Astro
Astro.props— props tipificadas del componenteAstro.params— parámetros de ruta dinámica ([slug],[...path])Astro.request— objeto de solicitud del lado del servidor (encabezados, cookies, URL)Astro.url— URL de la página actualgetStaticPaths()— enumera rutas para la generación de sitios estáticosgetEntry()/getCollection()— consultas de colecciones de contenido
Flujo de Datos de la Capa de Servicios
Las páginas y diseños de Astro son el lugar correcto para llamar funciones de servicio o repositorio en la valla de frontmatter. Los componentes deben recibir datos como props.
- Obtén datos en el frontmatter de la página, no dentro de los componentes.
- Pasa datos hacia abajo como props tipificadas.
- Los componentes no deben llamar repositorios o APIs externas directamente.
- Mantén la validación y la lógica de negocio en la capa de servicios.
Accesibilidad
- Usa elementos HTML semánticos donde el elemento tenga significado.
- Agrega atributos ARIA donde agreguen información semántica real.
- Asegúrate de que todos los elementos interactivos tengan nombres accesibles.
- Mantén estados de foco visibles.
- Mantén un tamaño mínimo de objetivo táctil de 44px para elementos interactivos.
- Respeta
prefers-reduced-motion. - Estructura los encabezados de manera lógica (
h1→h2→h3) dentro del contenido de la página.
Lee ./references/accessibility-patterns.md para patrones ARIA, etiquetas de formularios
y guía de jerarquía de encabezados.
Archivos de Soporte
./references/styling-and-css-modules.md— Reglas de Módulos CSS, tokens, variables de tema./references/islands-and-hydration.md— Guía de decisión de hidratación, notas específicas del framework./references/server-rendering.md— SSR, middleware, islas de servidor, acciones, transiciones de vista./references/component-patterns.md— Convenciones de frontmatter, slots, API de Astro./references/project-structure.md— Desglose de directorios, nomenclatura./references/content-collections.md— API de colecciones, cargadores, esquemas./references/accessibility-patterns.md— ARIA, formularios, jerarquía de encabezados./examples/button-component/— Ejemplo completo de Button con CSS Module
Archivos de Configuración
astro.config.mjs— Configuración principal del proyecto (integraciones, output, adaptador, etc.)src/content.config.ts— Esquemas y cargadores de colecciones de contenidosrc/actions/index.ts— Acciones de servidor tipificadassrc/middleware.ts— Lógica de middleware
Puntos Clave a Recordar
- Astro para estructura estática; SolidJS/React para interactividad. No hay excepciones.
- Módulos CSS siempre en archivos separados. Nunca estilos dentro de
<style>o en línea. - Directiva de hidratación mínima. Empieza con
client:visibleoclient:idle. - Componentes fundamentales siempre son islas. Nunca archivos
.astro. - Una carpeta por componente. Archivo principal (
index.astrooindex.tsx) másstyles.module.css. - Datos desde páginas hacia abajo. Consultas en frontmatter de página, props en componentes.
- HTML semántico y accesible. Sin divs genéricos cuando hay un elemento semántico disponible.