# Un tour de Whistle-stop des extensions HTMX et l'utilisation d'HTMX avec ASP.NET Core

<datetime class="hidden">2025-05-02T20:30</datetime>

<!--category-- Javascript, HTMX, ASP.NET Core -->
# Introduction

HTMX est une puissante bibliothèque JavaScript qui vous permet de créer des applications web dynamiques avec un minimum de JavaScript. Il vous permet d’effectuer des demandes AJAXM SK1 échanger du contenu HTML , et traiter les événements directement dans vos attributs HTML. J’utilise HT MX depuis environ deux ans à ce moment-là. Avec chaque projet, j’apprente de plus en plus sur ses capacitésMNK5 et surtout sa limitationMRK6

Toutefois, je ne prétend pas avoir de connaissances spécialisées sur ce sujet. Je voulais simplement faire part des choses que j’ai apprises tout au long du chemin.

> **Article conjoint:** Cet article met l’accent sur le système d’événements HTMX', les extensions de , et la customization avancée de ,. [HTMX avec ASP.Partiaux de base du NET:Le serveurM SK2Renaissance côtière](/blog/htmx-aspnetcore-partials).

[TOC]

# Événements

## Préparation de la demande

La phase de préparation de la demande est celle où HTMX configure la requête avant qu'elle ne soit envoyée au serveur. Cela inclut le réglage des titres de l'en-têteM SK1 l'ajout de paramètres, et la manipulation des entrées d'utilisateurs . Les événements suivants sont déclenchés durant cette phaseMSC4

```mermaid
flowchart LR

        A[htmx:configRequest] --> B[htmx:confirm] --> C[htmx:prompt] --> D[htmx:abort]

```

## Demande de cycle de vie

La phase du cycle de vie de la demande est celle où HTMX envoie la requête au serveur et gère la réponse. Les événements suivants sont déclenchés durant cette phase:

```mermaid
flowchart LR
 E[htmx:beforeRequest] --> F[htmx:request] --> G[htmx:afterRequest]
```

## Gestion de la réponse

La phase de traitement des réponses est celle où HTMX traite la réponse du serveur et met à jour le DOM. Les événements suivants sont déclenchés durant cette phase:

```mermaid
flowchart LR
        H[htmx:beforeOnLoad] --> I[htmx:onLoad]
        I --> J[htmx:beforeSwap] --> K[htmx:swap] --> L[htmx:afterSwap]
        L --> M[htmx:afterSettle] --> N[htmx:afterOnLoad]

```

## Gestion de l'histoire

La phase de gestion des antécédents est celle où HTMX met à jour l’historique du navigateur et le URL. Les événements suivants sont déclenchés durant cette phase:

```mermaid
flowchart LR
 A[htmx:historyRestoreRequest]
 A --> B[htmx:historyPopped]
 B --> C[htmx:historyRestorePage]
```

Comme vous pouvez le voir, HTMX fournit un certain nombre d'événements auxquels vous pouvez s'accouplir pour modifier la demande ou la réponse.

# Extensions

L'un des aspects les plus puissants de HTMX est la capacité [créer des extensions](https://v2-0v2-0.htmx.org/extensions/) pour étendre ses capacités. Dans mon cas, je me connecte habituellement à `htmx:configRequest` pour ajouter des paramètres supplémentaires à la demande. C'est utile lorsque vous voulez transmettre des données additionnelles au serveur sans avoir à modifier le code HTML ou JavaScript .

Autres extensions pourraient s'accouplir `htmx:beforeRequest` pour modifier la demande avant qu’elle ne soit envoyée; mais **après** la plupart des autres extensions qui attachent `configRequest`; comme dans `beforeRequest` des choses telles que `HX-Vals` et `HX-Include`s sont déjà attachés à la chaîne de demande ( soit dans la charge de paye \
Vous pouvez même attirer `htmx:afterSwap` pour effectuer des actions après que le contenu a été remplacé. Combiné avec les bibliothèques de templation du côté client comme [Alpine.js](https://alpinejs.dev/) ou [Lith](https://lit.dev/) vous pouvez créer des applications dynamiques puissantes avec un code minimal.

HTMX fournit quelques extensions built-in comme `hx-boost` et `hx-swap-oob` qui vous permettront d’améliorer la fonctionnalité de HTMX sans écrire un code personnalisé. Cependant , il y a des moments où vous devez créer vos propres extensions pour répondre à des exigences spécifiques.

Par exemple, vous voudriez peut-être ajouter des titres personnalisés à vos requêtes , modifier la charge de paye de la demande , ou traiter des événements spécifiques d'une manière unique

Pour ce faire, HTMX vous offre quelques points d’intégration pratiques:

```javascript

{
  /**
   * init(api)
   * Called once when the extension is initialized.
   * Use it to set up internal state, store references, or access HTMX utility functions via the api parameter.
   */
  init: function(api) {
    return null;
  },

  /**
   * getSelectors()
   * Returns additional CSS selectors that HTMX should monitor.
   * Useful if your extension needs to handle custom elements or dynamic behavior.
   */
  getSelectors: function() {
    return null;
  },

  /**
   * onEvent(name, evt)
   * Called on every HTMX event (e.g., htmx:beforeRequest, htmx:afterSwap).
   * Return false to cancel the event or stop propagation.
   */
  onEvent: function(name, evt) {
    return true;
  },

  /**
   * transformResponse(text, xhr, elt)
   * Modify the raw response text before it is parsed and swapped into the DOM.
   * Use this to sanitize or preprocess HTML.
   */
  transformResponse: function(text, xhr, elt) {
    return text;
  },

  /**
   * isInlineSwap(swapStyle)
   * Return true if your extension will handle this swap style manually.
   * This tells HTMX to skip default behavior.
   */
  isInlineSwap: function(swapStyle) {
    return false;
  },

  /**
   * handleSwap(swapStyle, target, fragment, settleInfo)
   * Perform custom DOM manipulation if you implement a custom swap style.
   * Return true to prevent HTMX's default swap.
   */
  handleSwap: function(swapStyle, target, fragment, settleInfo) {
    return false;
  },

  /**
   * encodeParameters(xhr, parameters, elt)
   * Modify or serialize request parameters before sending.
   * Return null to use default URL/form encoding.
   * Return a string to override with a custom payload (e.g., JSON).
   */
  encodeParameters: function(xhr, parameters, elt) {
    return null;
  }
}
```

HTMX fournit un certain nombre d'extensions pré- construites que vous pouvez [lire ici](https://htmx.org/extensions/).

Par exemple, un [extension built-in](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/json-enc/README.md) `json-encode` permet d'envoyer des données JSON dans le corps de la demande au lieu d'URL-données encodées sur les formulaires. C'est utile lorsque vous voulez envoyer à un serveur des structures ou des tableaux de données complexes.
Vous pouvez voir que cela s'inscrit dans les 3 événements

- `init` - pour configurer l'extension et stocker une référence à la API HTMX
- `onEvent` - pour établir le `Content-Type` à l'en-tête `application/json` lorsque la demande est configurée
- `encodeParameters` - pour surrider l'URL par défaut -encodé de forme et serialiser les paramètres comme JSON. Il retourne également une chaîne pour empêcher HTMX d'utiliser l'url par défaut

```javascript
(function() {
  let api
  htmx.defineExtension('json-enc', {
    init: function(apiRef) {
      api = apiRef
    },

    onEvent: function(name, evt) {
      if (name === 'htmx:configRequest') {
        evt.detail.headers['Content-Type'] = 'application/json'
      }
    },

    encodeParameters: function(xhr, parameters, elt) {
      xhr.overrideMimeType('text/json')

      const object = {}
      parameters.forEach(function(value, key) {
        if (Object.hasOwn(object, key)) {
          if (!Array.isArray(object[key])) {
            object[key] = [object[key]]
          }
          object[key].push(value)
        } else {
          object[key] = value
        }
      })

      const vals = api.getExpressionVars(elt)
      Object.keys(object).forEach(function(key) {
        // FormData encodes values as strings, restore hx-vals/hx-vars with their initial types
        object[key] = Object.hasOwn(vals, key) ? vals[key] : object[key]
      })

      return (JSON.stringify(object))
    }
  })
})()
```

Ou encore plus simple, mais encore plus RAPIDE `hx-debug` extension qui ajoute un `HX-Debug` header à la requête. Cette fonction est utile pour le débugging et l'enregistrement de l'information.

```javascript
(function() {
  htmx.defineExtension('debug', {
    onEvent: function(name, evt) {
      if (console.debug) {
        console.debug(name, evt)
      } else if (console) {
        console.log('DEBUG:', name, evt)
      } else {
        throw new Error('NO CONSOLE SUPPORTED')
      }
    }
  })
})()

```

Il y a beaucoup plus de ', dont un très puissant [extension de templetage du côté client](https://github.com/bigskysoftware/htmx-extensions/tree/main/src/client-side-templates) ce qui vous permet d’utiliser les bibliothèques de templage de la partie client- pour transformer les données JSON retournées en HTML. C’est utile pour créer des interfaces dynamiques sans avoir à s’appuyer sur le serveur

# Certaines extensions personnalisées

## IDs de rangée dynamique

Par exemple, dans un projet récent, j’ai utilisé les swaps HTMX OOB pour mettre à jour un certain nombre de lignes dans une table.
Pour ce faire, j’ai voulu savoir quelles lignes sont actuellement affichées dans la table, et je n’ai donc mis à jour que les lignes qui étaient visibles.

### L'extension

```javascript
export default {
    encodeParameters: function (xhr, parameters, elt) {
        const ext = elt.getAttribute('hx-ext') || '';
        if (!ext.split(',').map(e => e.trim()).includes('dynamic-rowids')) {
            return null; // Use default behavior
        }

        const id = elt.dataset.id;
        const approve = elt.dataset.approve === 'true';
        const minimal = elt.dataset.minimal === 'true';
        const single = elt.dataset.single === 'true';

        const target = elt.dataset.target;
        const payload = { id, approve, minimal, single };

        if (approve && target) {
            const table = document.querySelector(target);
            if (table) {
                const rowIds = Array.from(table.querySelectorAll('tr[id^="row-"]'))
                    .map(row => row.id.replace('row-', ''));
                payload.rowIds = rowIds;
            }
        }

        // Merge payload into the parameters object
        Object.assign(parameters, payload);
        return null; // Return null to continue with default URL-encoded form encoding
    }
}
```

### Utilisation

Pour l'utiliser, nous devons ajouter la extension à notre configuration HTMX.
Par conséquent, dans votre fichier js de point d'entrée ( supposant que vous utilisez des modules' ; y aurait à êtreM SK3 vous pouvez faire quelque chose comme ceci

```javascript
import dynamicRowIds from "./dynamicRowIds"; // Load the file

htmx.defineExtension("dynamic-rowids", dynamicRowIds); // Register the extension
```

Ensuite, sur n'importe quel élément que vous voulez utiliser, vous pouvez ajouter le `hx-ext` attribut avec la valeur `dynamic-rowids`.

```html
                <button
                    hx-ext="dynamic-rowids"
                    data-target="#my-table"
                    data-id="@Model.Id"
                    data-param1="true"
                    data-param2="false"
                    data-param3="@Model.Whatever"
                    hx-post
                    hx-controller="Contoller"
                    hx-action="Action"
                >
                    <i class='bx bx-check text-xl text-white'></i>
                </button>

```

## Préserver les paramètres

Il s’agit d’une autre extension HTMX simple, cette fois fixée à `htmx:configRequest` comme nous modifions l’URL avant que la demande ne soit envoyée. Cette extension est pratique si vous utilisez des filtres fondés sur les chaînes de recherche, etc.

Ceci est SIMILAR à, mais pas exactement le même que l'extension HTMX existante [push-params](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/path-params/README.md)

### L'extension

Vous pouvez voir que nous `onEvent` pour écouter les `htmx:configRequest` événement.

Puis nous:

- Obtenir l'élément qui a déclenché l'événement
- Obtenir le `preserve-params-exclude` l'attribut de l'élément ( s'il existe) et le diviser en un ensemble de clés pour exclure ( donc nous ne les ajoutons pas à la demande
- Obtenir les paramètres de l'URL actuel à partir du lieu de la fenêtre
- Obtenir les nouveaux paramètres de l'URL de la demande
- Suivez les paramètres actuels et vérifiez s'ils ne figurent pas dans la liste d'exclusion et si ceux-ci n'y sont pas déjà.
- Si elles ne sont pas, nous les ajoutons aux nouveaux paramètres
- Enfin, nous avons fixé les nouveaux paramètres à l'URL de la demande et retourné true pour poursuivre avec la demande.

```javascript
export default {
    onEvent: function (name, evt) {
        if (name !== 'htmx:configRequest') return;
        const el = evt.detail.elt;
        const excludeStr = el.getAttribute('preserve-params-exclude') || '';
        const exclude = excludeStr.split(',').map(s => s.trim());

        const currentParams = new URLSearchParams(window.location.search);
        const newParams = new URLSearchParams(evt.detail.path.split('?')[1] || '');

        currentParams.forEach((value, key) => {
            if (!exclude.includes(key) && !newParams.has(key)) {
                newParams.set(key, value);
            }
        });

        evt.detail.path = evt.detail.path.split('?')[0] + '?' + newParams.toString();

        return true;
    }
};
```

Ici, j'utilise l'essentiel [HTMX.Net](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main) pour ses aides à l'étiquetage. Les likes de `hx-controller` et `hx-action` sont des aides-étiquettes qui génèrent les attributs HTMX corrects pour vous. ainsi que `hx-route-<x>` pour les valeurs à passer dans la route. C'est vraiment utile puisqu'il vous permet d'utiliser le code C# pour générer les justes valeurs des attributs au lieu de devoir les hardcoder dans votre HTML .

### Utilisation

En tant qu’extension, elle est vraiment simple à utiliser.

Premièrement, nous devons ajouter l'extension à notre configuration HTMX.

```javascript

import preserveParams from './preserveParams.js';
htmx.defineExtension('preserve-params', preserveParams);
```

REMARQUE: Vous' remarquerez que les extensions HTMX par défaut utilisent la méthode de chargement automatique 'autoloadM SK3 pour charger l'extension

```javascript
// Autoloading the extension and registering it
(function() {
  htmx.defineExtension('debug', {
}
```

Il s’agit là d’une bonne façon de le faire si vous utilisez HTMX dans un environnement non modulaire. Toutefois, , si vous utilisez des modules (qui devraient être les suivants : `import` la déclaration de charger l'extension puis l'inscrire explicitement contre votre `htmx` instance. Cela vous permet de tirer parti de la mise en forme d'arbres-shaking et de ne charger que les extensions dont vous avez besoinM SK2

Ensuite, sur votre élément vous pouvez ajouter le `hx-ext` attribut avec la valeur `preserve-params` et le `preserve-params-exclude` attribut avec une liste de paramètres séparée par comma à exclure de la demande.

```html

<a class="btn-outline-icon"
   hx-controller="MyController"
   hx-action="MyAction"
   hx-route-myparam="@MyParam"
   hx-push-url="true"
   hx-ext="preserve-params"
   preserve-params-exclude="page,sort"
   hx-target="#page-content"
   hx-swap="innerHTML show:top"
   hx-indicator>
    <i class="bx bx-search"></i>
</a>
```

Dans ce cas, en raison du `event.detail.path` d’avoir le nouveau `myparam` La valeur qui y est inscrite ' remplacera celle-ci par notre nouvelle valeur mais préservera toutes les autres (à l'exception `page` et `sort`). Ainsi, nous pouvons continuer à transmettre tous les filtres que nous avons définis dans l’URL au serveur sans avoir à craindre qu’ils ne soient perdus lorsque nous faisons une nouvelle requête.

# ASP.NET Core

L’un des points saillants de HTMX est que la majeure partie de son interaction avec le serveur se fait par l’intermédiaire d’entêtes HTTP. Ces entêtes fournissent au serveur un contexte riche sur ce qui a déclenché la demande, vous permettant de répondre adéquatement à partir de votre ASPM SK2NET Core endpoints ou vues Razor .

Une autre composante clé de ce programme est la [HTMX.Net](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main). Parmi les nombreux articles qu’il fournit, il y a des articles propres `Request` extensions pour détecter les demandes HTMX. Il est utile de déterminer si une requête a été faite par l’HTMX ou non , et de traiter celle-ci en conséquence.

Il a également son propre mécanisme pour envoyer des déclencheurs.

```csharp

Response.Htmx(h => {
    h.WithTrigger("yes")
     .WithTrigger("cool", timing: HtmxTriggerTiming.AfterSettle)
     .WithTrigger("neat", new { valueForFrontEnd= 42, status= "Done!" }, timing: HtmxTriggerTiming.AfterSwap);
});
```

Push Urls etc...etc...
Khalid a fait un grand travail en créant une série d'extensions pour faciliter le travail avec HTMX dans ASP.NET Core.

Il est un outil clé dans ma boîte à outils lorsque je travaille avec HTMX et ASP. [**Vérifiez-le!**](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main)

## Headers de demande HTMX communs

Voici une ventilation des titres les plus utiles que HTMX envoie avec chaque demande:

| Intitulé | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------|
| HXM SK1Requête | Établir toujours la valeur exacte pour n'importe quel HTMX-requête initiéeMSC4 Très bon pour détecter les appels HT MX dans le logiciel de middleware ou dans les contrôleurs
| HXM SK1Target | L'ID de l'élément cible dans le DOM pour lequel la réponse sera remplacée par. |
| HXM SK1Trigger | L'ID de l'élément qui a déclenché la demande e.gMNK5 un boutonMRK6 M|
| HXM SK1Trigger-Nom | Nom de l'élément déclencheur (utilisable pour les formulairesMNK5 SNK6
| HXM SK1Prompt | Contient l'entrée de l'utilisateur à partir d'hx-prompt
| HXM SK1Current-URL | URL du navigateur au moment de l'initiation de la demande
| HXM SK1History-RestoreMSC3Request | Envoyé comme vrai si la demande fait partie d'une restauration de l'historique après la navigation.

## Demande d'extensions

Je les utilise assez largement dans mes applications ASP.NET Core. Combinées avec celles de HTMXM SK2Net comme `Request.IsHtmx()` , `Request.IsHtmxBoosted()` et `Request.IsHtmxNonBoosted()` vous pouvez facilement détecter les demandes HTMX et répondre en conséquence.

Par exemple, J’ai une extension très simple à Request qui me permet de détecter si une demande vise mon principal `#page-content` div. Si c'est le cas, je sais que je dois envoyer un partiel
REMARQUE: Beaucoup de gens ne savent pas que vous pouvez spécifier une page entière '' en tant qu’élément partiel

```csharp
        if (Request.PageContentTarget())
        {   
            Response.PushUrl(Request);
            return PartialView("List", vm);
        }
        return View("List", vm);
        
        public static class RequestExtensions
{
        
        public static bool PageContentTarget(this HttpRequest request)
    {
        bool isPageContentTarget = request.Headers.TryGetValue("hx-target", out var pageContentHeader) 
                                   && pageContentHeader == "page-content";
        
        return isPageContentTarget;
    }
    }

```

## Extensions de réponse

Outre les extensions Request,, vous pouvez aussi créer des extensions Response pour envoyer les événements de retour au client. Ce qui est utile pour déclencher les évènements du côté client .

### Exemple SweetAlert

Par exemple, [dans mon intégration SweetAlert2](https://www.mostlylucid.net/blog/usingsweetalertforhxindicators) Je permets de fermer le dialogue en utilisant un déclencheur qui est établi du serveur.

```javascript
    document.body.addEventListener('sweetalert:close', closeSweetAlertLoader);

```

Cela est déclenché par le serveur comme un événement de déclenchement HTMX.

```csharp

    public static void CloseSweetAlert(this HttpResponse response)
    {
        response.Headers.Append("HX-Trigger" , JsonSerializer.Serialize(new
        {
            sweetalert = "close"
        }));

    }
```

Il s’agit de l’un des `sweetalert:close` événement du côté client, permettant de fermer le dialogue. Vous pouvez également transmettre les données au client en utilisant `HX-Trigger` header. C'est utile pour transmettre les données du serveur au client sans avoir à modifier le code HTML ou JavaScript.

Comme vous le voyez, ' est facile à écouter pour ces événements en ajoutant un auditeur d'événement au corps.

### Présenter le toast

J'ai déjà écrit sur ma méthode de toast. [ici](https://www.mostlylucid.net/blog/showingtoastandswappingwithhtmx), mais il vaut la peine de mentionner ici aussiM SK1 . Pour permettre très simplement au serveur de déclencher une notification de toast sur le côté client. J’ai mis le déclencheur dans cette extension RéponseMSC4

```csharp
    public static void ShowToast(this HttpResponse response, string message, bool success = true)
    {
        response.Headers.Append("HX-Trigger", JsonSerializer.Serialize(new
        {
            showToast = new
            {
                toast = message,
                issuccess =success
            }
        }));

    }
```

Puis je me connecte au côté client de l’événement et j’appelle mon `showToast` fonction.

```javascript
import { showToast, showHTMXToast } from './toast';

window.showHTMXToast = showHTMXToast;

document.body.addEventListener("showToast", showHTMXToast);
```

C'est alors que j'ai `showToast` fonction et puits, montre un toastM SK1 voir de nouveau plus à ce sujet [dans l'article ](https://www.mostlylucid.net/blog/showingtoastandswappingwithhtmx).

```javascript


export function showHTMXToast(event) {
    const xhr = event?.detail?.xhr;
    let type = 'success';
    let message = xhr?.responseText || 'Done!';

    try {
        const data = xhr ? JSON.parse(xhr.responseText) : event.detail;

        if (data.toast) message = data.toast;
        if ('issuccess' in data) {
            type = data.issuccess === false ? 'error' : 'success';
        } else if (xhr?.status >= 400) {
            type = 'error';
        } else if (xhr?.status >= 300) {
            type = 'warning';
        }

    } catch {
        if (xhr?.status >= 400) type = 'error';
        else if (xhr?.status >= 300) type = 'warning';
    }

    showToast(message, 3000, type);
}
```

## En conclusion

Bon, c’est ce qu’il est' , une tournée d’hélicoptères de HTMX et ASP. Core NETM SK3 J’espère que vous l’avez trouvé utile et instructifMSC4 Si vous avez des questions ou des commentaires, n’hésitez pas à les formuler ci-dessous

## Articles connexes sur ce blog

### Article de compagne

Cet article fait partie d’une série de deux parties sur HTMX avec ASP

1. **[HTMX avec les parties centrales ASP.NET](/blog/htmx-aspnetcore-partials)** - Concentration sur l'ASP.Intégration du noyau NET , vues partiellesM SK3 HTMXMST4NETMSC5 et pagination
2. **Cet article** - Immersion profonde dans les événements de l'HTMX , cycle de vie

### Autres articles HTMX

- [Ajouter le messagerie avec HTMX](/blog/addpagingwithhtmx) - Mise en œuvre de la pagination avec HTMX
- [ASP.Net Caching Core avec HTMX](/blog/aspnetcachingwithhtmx) - Stratégies de cache pour les demandes HTMX
- [Auto-refresh avec Alpine et HTMX](/blog/autorefreshwithalpineandhtmx) - Combiner Alpine.js avec HTMX pour les composants réactifs
- [Faire votre site plus SPA-comme avec HTMX](/blog/htmxtomakeyoursitemorespalike) - SPA- navigation similaire sans cadres JavaScript
- [Utilisation de SweetAlert pour les indicateurs HX](/blog/usingsweetalertforhxindicators) - Pièces indicateurs de chargement avec HTMX
- [Afficher Toast et Swapping avec HTMX](/blog/showingtoastandswappingwithhtmx) - Server-notifications de toast trigées

## Autres lectures

**Documentation officielle HTMX:**

- [Documentation HTMX](https://htmx.org/docs/) - La documentation officielle de l'HTMX
- [HTMX Référence sur les événements](https://htmx.org/events/) - Liste complète des événements HTMX
- [Extensions HTMX](https://htmx.org/extensions/) - Extensions officielles de l'HTMX
- [Exemples HTMX](https://htmx.org/examples/) - Exemples pratiques de modèles HTMX
- [HTMX Essays](https://htmx.org/essays/) - Articles réfléchis sur la philosophie de l'HTMX

**Bibliothèques & Outils:**

- [HTMX.NET GitHub](https://github.com/khalidabuhakmeh/Htmx.Net) - Code source de la bibliothèque HTMX.NET
- [NuGet HTMX](https://www.nuget.org/packages/Htmx/) - HTMX.NET sur NuGet
- [Site Web de Khalid Abuhakmeh](https://khalidabuhakmeh.com/) - Créateur de HTMX.NET
- [Alpine.js Documentation](https://alpinejs.dev/) - Docs officiels de l’AlpineM SK1js

**Ressources communautaires:**

- [HTMX Discord](https://htmx.org/discord) - Soutien communautaire actif
- [Hypermedia Systems Book](https://hypermedia.systems/) - Livre en ligne gratuit sur la construction d'applications hypermédia