Aller au contenu

Astro : composants et layouts

src/components/Carte.astro :

---
interface Props {
titre: string;
url: string;
tags?: string[];
}
const { titre, url, tags = [] } = Astro.props;
---
<article class="carte">
<h2>
<a href={url}>{titre}</a>
</h2>
{tags.length > 0 && (
<ul>
{tags.map((tag) => (
<li>{tag}</li>
))}
</ul>
)}
<slot />
</article>
<style>
.carte {
border: 1px solid #ccc;
padding: 1rem;
border-radius: 8px;
}
</style>

Utilisation :

---
import Carte from '../components/Carte.astro';
---
<Carte
titre="MD Editor"
url="https://exemple.com"
tags={['markdown', 'éditeur']}
>
<p>Contenu passé dans le slot.</p>
</Carte>
Élément Rôle
Frontmatter --- Code exécuté à la compilation : imports, données, props
Gabarit HTML avec expressions {…}
Astro.props Propriétés reçues
<slot /> Contenu enfant
<style> Styles limités au composant
---
const articles = [
{ id: 1, titre: 'A' },
{ id: 2, titre: 'B' },
];
const connecte = true;
---
<ul>
{articles.map((a) => (
<li key={a.id}>{a.titre}</li>
))}
</ul>
{connecte ? <p>Bonjour</p> : <p>Connexion</p>}
<p class:list={['base', { actif: connecte }]}>Classes conditionnelles</p>
<div set:html={'<strong>HTML brut</strong>'} />
<Fragment>
<span>sans élément parent</span>
</Fragment>
Modale.astro
<div class="modale">
<header>
<slot name="titre">Titre par défaut</slot>
</header>
<slot />
<footer>
<slot name="pied" />
</footer>
</div>
<Modale>
<h2 slot="titre">Confirmer</h2>
<p>Corps de la modale.</p>
<button slot="pied">OK</button>
</Modale>
  • <style> dans un composant est limité à ce composant (Astro ajoute un attribut de portée).
  • <style is:global> ou :global(sélecteur) pour sortir de cette portée.
  • Une feuille globale s’importe dans le layout : import '../styles/global.css';.
  • Variables CSS depuis le frontmatter : <style define:vars={{ couleur }}>.
---
const couleur = 'rebeccapurple';
---
<p class="titre">Texte</p>
<style define:vars={{ couleur }}>
.titre {
color: var(--couleur);
}
</style>

Pour Tailwind : voir Tailwind : installation.

Une balise <script> d’un composant .astro s’exécute dans le navigateur, est regroupée, dédupliquée et peut importer des modules :

<button id="theme">Changer de thème</button>
<script>
document.getElementById('theme')?.addEventListener('click', () => {
const racine = document.documentElement;
racine.dataset.theme = racine.dataset.theme === 'dark' ? 'light' : 'dark';
});
</script>

<script is:inline> conserve le script tel quel, sans traitement (utile pour un petit script exécuté avant l’affichage, comme l’initialisation du thème).

Un layout est un composant qui enveloppe les pages.

src/layouts/Base.astro :

---
import '../styles/global.css';
interface Props {
titre: string;
description?: string;
}
const { titre, description = 'Description par défaut' } = Astro.props;
const canonique = new URL(Astro.url.pathname, Astro.site);
---
<!doctype html>
<html lang="fr">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>{titre}</title>
<meta name="description" content={description} />
<link rel="canonical" href={canonique} />
<slot name="head" />
</head>
<body>
<header>
<a href="/">Accueil</a>
</header>
<main>
<slot />
</main>
<footer>© {new Date().getFullYear()}</footer>
</body>
</html>
---
import Base from '../layouts/Base.astro';
---
<Base titre="À propos" description="Page de présentation">
<h1>À propos</h1>
</Base>

Pour des fichiers Markdown, indiquer le layout dans le frontmatter (layout: ../layouts/Article.astro) ou, avec les collections, l’appeler depuis la page qui affiche le contenu (voir Contenu et collections).

---
import { Image } from 'astro:assets';
import photo from '../assets/photo.jpg';
---
<Image src={photo} alt="Description de la photo" width={800} />

Image produit des formats optimisés (WebP, AVIF), les dimensions et le chargement différé. Les images dans public/ ne sont pas optimisées. Toujours renseigner alt.

Pour une police auto-hébergée, placer les fichiers dans public/fonts/ ou utiliser un paquet @fontsource/... et l’importer dans le layout. Précharger la police principale :

<link
rel="preload"
href="/fonts/police.woff2"
as="font"
type="font/woff2"
crossorigin
/>
Symptôme Piste
Un style de composant ne s’applique pas à un élément enfant Portée locale : :global() ou classe passée en prop
Astro.props vide Propriété non transmise ; vérifier la casse
document is not defined Code navigateur dans le frontmatter : le déplacer dans un <script>
Image : Could not find requested image Chemin d’import incorrect ; fichier absent de src/
Balise <script> exécutée une seule fois Comportement attendu (dédupliquée)
Contenu de <slot /> absent Élément enfant non passé, ou nom de slot incorrect

Ubuntu 24.04 et 26.04 : différences à connaître

Section intitulée « Ubuntu 24.04 et 26.04 : différences à connaître »

Aucune.