Astro a fondo 1, componentes, props, slots y layouts
En Instalación y primer proyecto creaste un proyecto.
Un .astro tiene código de construcción entre --- y una plantilla HTML con {expresiones}.
Las props llevan datos al componente (interface Props y Astro.props); los slots, HTML.
Un layout es el documento común; cada página lo usa y llena su <slot />.
Los <style> de un componente tienen ámbito; lo global va en un CSS importado en el layout.
- En Instalación y primer proyecto creaste un proyecto. En estas cuatro páginas montas un portafolio completo, el de Lucía Prieto: una portada con los proyectos, una página por proyecto generada a partir de ficheros Markdown, imágenes optimizadas, transiciones entre páginas y publicación en GitHub Pages. Todo el código está probado con Astro 7.4 (así en noviembre de 2026; puede haber cambiado).
- Astro 7 necesita Node.js 22.23.4 o superior; las versiones impares (23, 25) no valen. Con la LTS (Node.js 26) no hay problema.
- npm create astro@latest portafolio cd portafolio npm run dev
- El asistente pregunta qué plantilla usar (elige la mínima, minimal), si instala las dependencias y si crea un repositorio de Git. La web queda en http://localhost:4321 y se recarga al guardar.
- portafolio/ ├── public/ ← se copia tal cual: favicon, robots.txt, CNAME ├── src/ │ ├── assets/ ← imágenes que Astro optimiza │ ├── components/ ← piezas: cabecera, tarjeta… │ ├── content/ ← los textos (Markdown) de los proyectos │ ├── layouts/ ← la plantilla común de las páginas │ ├── pages/ ← cada fichero es una página │ ├── styles/ ← CSS global │ └── content.config.ts ├── astro.config.mjs └── package.json
Introducción
En Instalación y primer proyecto creaste un proyecto. En estas cuatro páginas montas un portafolio completo, el de Lucía Prieto: una portada con los proyectos, una página por proyecto generada a partir de ficheros Markdown, imágenes optimizadas, transiciones entre páginas y publicación en GitHub Pages. Todo el código está probado con Astro 7.4 (así en noviembre de 2026; puede haber cambiado).
Crear el proyecto
Astro 7 necesita Node.js 22.23.4 o superior; las versiones impares (23, 25) no valen. Con la LTS (Node.js 26) no hay problema.
npm create astro@latest portafolio cd portafolio npm run dev
El asistente pregunta qué plantilla usar (elige la mínima, minimal), si instala las dependencias y si crea un repositorio de Git. La web queda en http://localhost:4321 y se recarga al guardar.
Las carpetas
portafolio/ ├── public/ ← se copia tal cual: favicon, robots.txt, CNAME ├── src/ │ ├── assets/ ← imágenes que Astro optimiza │ ├── components/ ← piezas: cabecera, tarjeta… │ ├── content/ ← los textos (Markdown) de los proyectos │ ├── layouts/ ← la plantilla común de las páginas │ ├── pages/ ← cada fichero es una página │ ├── styles/ ← CSS global │ └── content.config.ts ├── astro.config.mjs └── package.json
La única carpeta obligatoria es src/pages/. El resto son costumbre, pero conviene seguirla: es la que vas a encontrar en cualquier proyecto.
Un componente por dentro
Un fichero .astro tiene dos partes. Entre las dos líneas --- va el código que se ejecuta al construir la web (en tu ordenador o en el servidor, nunca en el navegador). Debajo, la plantilla: HTML con expresiones entre llaves.
--- // src/components/Cabecera.astro const enlaces = [ { texto: 'Proyectos', href: '/' }, { texto: 'Sobre mí', href: '/sobre-mi' }, ]; const actual = Astro.url.pathname; --- <header> <a class="logo" href="/">Lucía Prieto</a> <nav aria-label="Principal"> <ul> {enlaces.map(({ texto, href }) => ( <li> <a href={href} aria-current={actual === href ? 'page' : undefined}>{texto}</a> </li> ))} </ul> </nav> </header>
{enlaces.map(...)} repite el <li> por cada elemento de la lista. Un atributo con valor undefined no se escribe: el enlace de la página actual lleva aria-current="page" y los demás, nada. Astro.url.pathname es la ruta de la página que se está generando.
Para mostrar algo solo si se cumple una condición, &&:
Props: datos que recibe el componente
Una tarjeta de proyecto recibe el título y la imagen desde fuera. En el componente se declaran con una interfaz Props (así el editor te avisa si te falta alguno) y se leen de Astro.props:
--- // src/components/Tarjeta.astro interface Props { titulo: string; enlace: string; etiqueta?: string; // el ? la hace opcional } const { titulo, enlace, etiqueta = 'Proyecto' } = Astro.props; --- <article class="tarjeta"> <p class="etiqueta">{etiqueta}</p> <h2><a href={enlace}>{titulo}</a></h2> </article>
Y se usa como una etiqueta HTML, después de importarla:
--- import Tarjeta from '../components/Tarjeta.astro'; --- <Tarjeta titulo="Cartel para un festival de jazz" enlace="/proyectos/cartel-festival-jazz" /> <Tarjeta titulo="Identidad de una cafetería" enlace="/proyectos/marca-cafeteria" etiqueta="Marca" />
Slots: el hueco para el contenido
Las props son datos sueltos; un slot es un hueco donde va el HTML que escribes entre la etiqueta de apertura y la de cierre. Un componente puede tener uno sin nombre y otros con nombre, y cada uno puede traer un contenido por defecto:
--- // src/components/Aviso.astro --- <aside class="aviso"> <slot name="titulo"><strong>Aviso</strong></slot> <slot /> </aside>
<Aviso> <strong slot="titulo">Disponible para encargos</strong> <p>Desde enero de 2027.</p> </Aviso>
La plantilla común (layout)
Un layout es un componente con el documento entero: <html>, <head>, la cabecera y el pie. Cada página lo usa y pone su contenido en el slot.
--- // src/layouts/Base.astro import Cabecera from '../components/Cabecera.astro'; import '../styles/global.css'; interface Props { titulo: string; descripcion?: string; } const { titulo, descripcion = 'Portafolio de Lucía Prieto, diseñadora gráfica' } = Astro.props; --- <!doctype html> <html lang="es"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="description" content={descripcion} /> <title>{titulo} · Lucía Prieto</title> </head> <body> <Cabecera /> <main> <slot /> </main> <footer> <slot name="pie">© 2026 Lucía Prieto</slot> </footer> </body> </html>
--- // src/pages/sobre-mi.astro import Base from '../layouts/Base.astro'; --- <Base titulo="Sobre mí"> <h1>Sobre mí</h1> <p>Diseño carteles, marcas y webs desde Sevilla.</p> <p slot="pie">Escríbeme: hola@ejemplo.es</p> </Base>
Estilos con ámbito
Un <style> dentro de un componente solo afecta a ese componente: Astro añade un atributo propio (data-astro-cid-…) a sus etiquetas y a sus selectores. Si escribes h2 { … } en la tarjeta, los h2 del resto de la web no cambian.
<style> .tarjeta { border: 1px solid #ddd; border-radius: 0.5rem; } h2 { font-size: 1.25rem; } </style>
ParaEscribe Estilos de todo el sitio (variables, body, tipografía)Un CSS en src/styles/ importado en el layout Un <style> sin ámbito<style is:global> Llegar a lo que viene de fuera (el HTML de un Markdown, un slot)article :global(h2) { … }
Practica
Crea el proyecto con la plantilla mínima y arranca npm run dev. Haz el layout Base.astro y úsalo en index.astro y en una página nueva sobre-mi.astro. Crea Cabecera.astro con el menú y la marca de la página actual. Crea Tarjeta.astro con props y pon tres tarjetas en la portada. Dale estilo a la tarjeta con un <style> en el componente y comprueba en las DevTools el atributo data-astro-cid-….
Errores frecuentes
Usar document o window entre los ---: ese código no se ejecuta en el navegador. Llamar tarjeta.astro al componente y usarlo como <tarjeta>: tiene que empezar por mayúscula. Dejar una etiqueta sin cerrar, como un <p> sin su </p>. Desde Astro 7 es un error al construir, no algo que se arregla solo. Escribir el CSS de todo el sitio en el <style> de un componente: solo se aplica dentro de él.