# Een Whistle-stop Tour van HTMX Extensions en het gebruik van HTMX met ASP.NET Core

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

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

HTMX is een krachtige JavaScript-bibliotheek waarmee u dynamische webapplicaties kunt maken met minimale JavaScript. Hiermee kunt u AJAX-verzoeken indienen, HTML-inhoud uitwisselen en gebeurtenissen direct verwerken in uw HTML-attributen. Ik gebruik HTMX al ongeveer twee jaar op dit moment en bij elk project leer ik meer en meer over zijn mogelijkheden; en nog belangrijker is dat het beperkingen heeft.

Maar ik zeg nog steeds niet dat ik er deskundige kennis van heb. Ik wilde alleen wat dingen delen die ik onderweg geleerd heb.

> **Metgezel-artikel:** Dit artikel richt zich op HTMX's event systeem, extensies en geavanceerde maatwerk. Voor ASP.NET Core integratie patronen met gedeeltelijke views, HTMX.NET, en paginatie, zie mijn metgezel artikel: [HTMX met ASP.NET Core Partials: De Server-Side Renaissance](/blog/htmx-aspnetcore-partials).

[TOC]

# Gebeurtenissen

## Voorbereiding van het verzoek

De voorbereidingsfase van het verzoek is waar het HTMX het verzoek configureert voordat het naar de server wordt verzonden. Dit omvat het instellen van headers, het toevoegen van parameters en het verwerken van gebruikersinvoer. De volgende gebeurtenissen worden geactiveerd tijdens deze fase:

```mermaid
flowchart LR

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

```

## Request Lifecycle

De levenscyclusfase van het verzoek is waar het HTMX het verzoek naar de server stuurt en het antwoord behandelt. De volgende gebeurtenissen worden geactiveerd tijdens deze fase:

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

## Response Handling

De response handling fase is waar HTMX de reactie van de server verwerkt en de DOM bijwerkt. De volgende gebeurtenissen worden geactiveerd tijdens deze fase:

```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]

```

## Geschiedenisbeheer

De history management fase is waar HTMX de browsergeschiedenis en URL update. De volgende gebeurtenissen worden geactiveerd tijdens deze fase:

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

Zoals u kunt zien HTMX biedt een aantal gebeurtenissen die u kunt haak in om het verzoek of antwoord te wijzigen, of zelfs geschiedenis; HTMX doet een LOT voor het zijn van een dergelijk compact systeem. Met behulp van elk van deze kunt u wijzigen hoe HTMX interactie met de server / de client op vrij uitgebreide manieren.

# Uitbreidingen

Een van de meest krachtige aspecten van HTMX is de mogelijkheid om [extensies aanmaken](https://v2-0v2-0.htmx.org/extensions/) In mijn geval, ik meestal haak in `htmx:configRequest` om extra parameters toe te voegen aan het verzoek. Dit is handig wanneer u extra gegevens wilt doorgeven aan de server zonder de HTML- of JavaScript-code te hoeven wijzigen.

Andere extensies kunnen haak `htmx:beforeRequest` het verzoek te wijzigen voordat het wordt verzonden; maar **na** de meeste andere uitbreidingen die haak `configRequest`; als in `beforeRequest` dingen zoals `HX-Vals` en `HX-Include`s zijn al aangesloten op de reuest (of in de payload \ querystring).
Je kunt zelfs haak `htmx:afterSwap` om acties uit te voeren nadat de inhoud is geruild. In combinatie met client-side-templating-bibliotheken zoals [Alpine.jsunit synonyms for matching user input](https://alpinejs.dev/) of [Lit](https://lit.dev/) U kunt krachtige dynamische toepassingen maken met minimale code.

HTMX biedt enkele ingebouwde extensies zoals `hx-boost` en `hx-swap-oob` die u in staat stellen om de functionaliteit van HTMX te verbeteren zonder het schrijven van een aangepaste code. Echter, er zijn momenten dat u nodig hebt om uw eigen extensies te maken om te voldoen aan specifieke eisen.

U kunt bijvoorbeeld aangepaste headers toevoegen aan uw verzoeken, de payload van uw verzoek wijzigen of specifieke gebeurtenissen op een unieke manier behandelen.

Om dit te bereiken HTMX biedt u een aantal handige integratie punten:

```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 biedt een aantal vooraf gebouwde extensies die u kunt [lees hier over](https://htmx.org/extensions/).

Bijvoorbeeld een handige [ingebouwde uitbreiding](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/json-enc/README.md) `json-encode` Hiermee kunt u JSON-gegevens verzenden in plaats van URL-gecodeerde formuliergegevens. Dit is handig wanneer u complexe datastructuren of arrays naar de server wilt sturen.
U kunt zien dat deze haken in 3 gebeurtenissen

- `init` - om de uitbreiding in te stellen en een verwijzing naar de HTMX API op te slaan
- `onEvent` - het instellen van de `Content-Type` koptekst naar `application/json` wanneer het verzoek wordt geconfigureerd
- `encodeParameters` - om de standaard URL-gecodeerde vormcodering te omzeilen en de parameters als JSON te serialiseren. Het geeft ook een tekenreeks terug om te voorkomen dat HTMX de standaard URL-gecodeerde vormcodering gebruikt.

```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))
    }
  })
})()
```

Of zelfs de eenvoudigere maar nog meer handige `hx-debug` extensie die een `HX-Debug` header naar het verzoek. Dit is handig voor het debuggen en loggen, omdat het u toelaat om de raw-verzoek- en responsgegevens in de dev-console te zien.

```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')
      }
    }
  })
})()

```

Er zijn er nog veel meer, waaronder een zeer krachtig [extensie van client-side-templating](https://github.com/bigskysoftware/htmx-extensions/tree/main/src/client-side-templates) waarmee u templatingsbibliotheken aan de clientzijde kunt gebruiken om geretourneerde JSON-gegevens om te zetten in HTML. Dit is handig voor het aanmaken van dynamische UI's zonder dat u hoeft te vertrouwen op server-side rendering.

# Enkele aangepaste extensies

## Dynamische rij-ID's

Bijvoorbeeld in een recent project heb ik HTMX OOB swaps gebruikt om een aantal rijen in een tabel bij te werken.
Om dit te doen wilde ik weten welke rijen momenteel in de tabel worden weergegeven, dus ik heb alleen de rijen die zichtbaar waren bijgewerkt.

### De uitbreiding

```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
    }
}
```

### Gebruik ervan

Om het te gebruiken moeten we de uitbreiding toevoegen aan onze HTMX configuratie.
Dus in je invoerpunt js bestand (als je modules gebruikt; yoy zou moeten zijn) kun je iets als dit doen:

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

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

Dan op welk element u het wilt gebruiken op kunt u de `hx-ext` attribuut met de waarde `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>

```

## Paramen behouden

Dit is een andere eenvoudige HTMX extensie, deze keer aangesloten op `htmx:configRequest` als we de URL aanpassen voordat het verzoek verzonden wordt. Deze extensie is handig als u gebruik maakt van querystring-gebaseerde filtering etc. en u wilt dat sommige verzoeken bestaande filters behouden terwijl andere dat niet doen (bijv. 'name' en 'startdate' maar niet 'page' of 'sort').

Dit is SIMILAR naar maar niet precies hetzelfde als de bestaande HTMX extensie [pushparams](https://github.com/bigskysoftware/htmx-extensions/blob/main/src/path-params/README.md)

### De uitbreiding

Je kunt zien dat we elkaar aanraken. `onEvent` om te luisteren voor de `htmx:configRequest` event.

Dan gaan we:

- Krijg het element dat de gebeurtenis activeerde
- Haal de `preserve-params-exclude` attribuut van het element (als het bestaat) en split het in een reeks sleutels om uit te sluiten (dus we voegen ze niet toe aan het verzoek)
- De huidige URL-parameters ophalen uit de locatie van het venster
- Krijg de nieuwe parameters van de aanvraag-URL
- Loop door de huidige parameters en controleer of ze niet in de lijst met uitsluitingen staan en nog niet in de nieuwe parameters
- Als ze dat niet zijn, voegen we ze toe aan de nieuwe parameters
- Tot slot hebben we de nieuwe parameters op de aanvraag URL en terug te keren waar om door te gaan met het verzoek.

```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;
    }
};
```

Hier gebruik ik de essentiële [HTMX.Net](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main) voor zijn tag helpers. `hx-controller` en `hx-action` zijn tag helpers die de juiste HTMX attributen voor u genereren. `hx-route-<x>` Dit is echt handig omdat het je toelaat om C#-code te gebruiken om de juiste waarden voor de attributen te genereren in plaats van ze te hardcoderen in je HTML.

### Gebruik ervan

Als extensie is het heel eenvoudig te gebruiken:

Eerst moeten we de uitbreiding toevoegen aan onze HTMX configuratie.

```javascript

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

OPMERKING: U zult merken dat de standaard HTMX extensies de 'autoload' methode gebruiken om de extensie te laden.

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

Dit is een goede manier om het te doen als je gebruik maakt van HTMX in een niet-module omgeving. Echter, als je gebruik maakt van modules (die je zou moeten zijn) is het beter om de `import` verklaring om de extensie te laden dan expliciet registreren tegen uw `htmx` instance. Hiermee kunt u profiteren van boomschudden en alleen de extensies laden die u nodig hebt.

Dan kunt u op uw element de `hx-ext` attribuut met de waarde `preserve-params` en de `preserve-params-exclude` attribuut met een komma gescheiden lijst van parameters om uit te sluiten van het verzoek.

```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>
```

In dit geval wegens de `event.detail.path` met de nieuwe `myparam` waarde ingesteld in het zal die vervangen door onze nieuwe waarde, maar behoud alle anderen (behalve `page` en `sort`Zo kunnen we alle filters die we in de URL hebben ingesteld op de server blijven doorgeven zonder dat we ons zorgen hoeven te maken dat ze verloren gaan wanneer we een nieuw verzoek doen.

# ASP.NET-kern

Een van de leuke dingen over HTMX is dat een groot deel van de interactie met de server gebeurt via HTTP headers. Deze headers bieden de server een rijke context over wat het verzoek activeerde, zodat u adequaat kunt reageren vanuit uw ASP.NET Core endpoints of Razor views.

Wederom een belangrijk onderdeel hiervan is de [HTMX.Net](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main). Onder veel van de items die het biedt zijn netjes `Request` uitbreidingen om HTMX-verzoeken op te sporen. Dit is handig om te bepalen of HTMX een verzoek heeft ingediend of niet, en om het dienovereenkomstig te behandelen.

Het heeft ook zijn eigen mechanisme om triggers te sturen

```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 deed een geweldige job van het creëren van een set van extensies om het gemakkelijk te maken om te werken met HTMX in ASP.NET Core.

Het is een belangrijk hulpmiddel in mijn gereedschapskist bij het werken met HTMX en ASP.NET Core. [**Moet je zien.**](https://github.com/khalidabuhakmeh/Htmx.Net/tree/main)

## Common HTMX Request Headers

Hieronder vindt u een overzicht van de meest nuttige headers die HTMX met elk verzoek verzendt:

Beschrijving van de header
|----------------------------|------------------------------------------------------------------------------------------------------------------|
HX-Request Altijd ingesteld op waar voor elke HTMX-geïnitieerde aanvraag. Geweldig voor het detecteren van HTMX-gesprekken in middleware of controllers.
HX-Target De id van het doelelement in de DOM waarin de respons zal worden geruild.
HX-Trigger De id van het element dat het verzoek activeerde (bijv. een knop).
HX-Trigger-Name De naam van het triggerende element (gebruikelijk voor formulieren).
HX-Prompt bevat gebruikersinvoer van hx-prompt.
HX-Current-URL De browser-URL wanneer het verzoek werd gestart. Nuttig voor logging en context.
HX-Geschiedenis-Restore-Request Verzonden als waar als het verzoek deel uitmaakt van een geschiedenisherstel na navigatie (bijv., terugknop).

## Verzoek extensies

Ik gebruik deze vrij uitgebreid in mijn ASP.NET Core apps. In combinatie met de HTMX.Net degenen zoals `Request.IsHtmx()` , `Request.IsHtmxBoosted()` en `Request.IsHtmxNonBoosted()` u kunt gemakkelijk HTMX-verzoeken detecteren en daarop reageren.

Bijvoorbeeld, ik heb een heel eenvoudige extensie aan Request die laat me detecteren als een verzoek is gericht op mijn belangrijkste `#page-content` Div. Als het is dan weet ik dat ik een gedeeltelijke terug moet sturen.
OPMERKING: Velen realiseren zich niet dat je een 'volledige pagina' als een gedeeltelijke kunt opgeven, het slaat dan gewoon de lay-out over.

```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;
    }
    }

```

## Response extensions

Naast verzoeken extensies, kunt u ook Response extensies aanmaken om gebeurtenissen terug te sturen naar de klant. Dit is handig voor het activeren van client side events.

### SweetAlert-voorbeeld

Bijvoorbeeld [in mijn SweetAlert2-integratie](https://www.mostlylucid.net/blog/usingsweetalertforhxindicators) Ik activeer het sluiten van het dialoogvenster met behulp van een trigger die is ingesteld vanaf de server.

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

```

Dit wordt geactiveerd vanaf de server als een HTMX trigger event.

```csharp

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

    }
```

Dit zal leiden tot de `sweetalert:close` event aan de clientzijde, waarmee u het dialoogvenster kunt sluiten. U kunt ook gegevens teruggeven aan de client met behulp van de `HX-Trigger` header. Dit is handig voor het doorgeven van gegevens van de server aan de client zonder de HTML- of JavaScript-code te hoeven wijzigen.

Zoals je ziet is het makkelijk om voor deze gebeurtenissen te luisteren door gewoon een event luisteraar aan het lichaam toe te voegen. Ik gebruik JSON voornamelijk zoals het altijd goed codeert.

### Toast tonen

Ik schreef over mijn toast methode eerder [Hier.](https://www.mostlylucid.net/blog/showingtoastandswappingwithhtmx), maar het is het vermelden waard hier ook. Om heel eenvoudig de server in staat te stellen om een toast notificatie aan de client kant te activeren. Ik heb de trigger ingesteld in deze Response extensie.

```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
            }
        }));

    }
```

Ik dan haak in de gebeurtenis client kant en bel mijn `showToast` functie.

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

window.showHTMXToast = showHTMXToast;

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

Dit roept dan mijn `showToast` functie en goed, toont een toast; weer zie er meer over [in het artikel ](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);
}
```

## Conclusie

Nou dat is het, een wervelwind tour van HTMX en ASP.NET Core. Ik hoop dat u vond het nuttig en informatief. Als u vragen of opmerkingen hebt voel je vrij om hieronder te reageren.

## Gerelateerde artikelen op dit blog

### Metgezel-artikel

Dit artikel maakt deel uit van een tweedelige serie op HTMX met ASP.NET Core:

1. **[HTMX met ASP.NET kernonderdelen](/blog/htmx-aspnetcore-partials)** - Focuss op ASP.NET Kernintegratie, gedeeltelijke weergaven, HTMX.NET, en paginatie
2. **Dit artikel** - Diepe duik in HTMX evenementen, levenscyclus, uitbreiding architectuur, en aangepaste extensies

### Meer HTMX artikelen

- [Pagina's toevoegen met HTMX](/blog/addpagingwithhtmx) - Het uitvoeren van paginatie met HTMX
- [ASP.NET Core Caching met HTMX](/blog/aspnetcachingwithhtmx) - Caching strategieën voor HTMX-verzoeken
- [Automatisch vernieuwen met Alpine en HTMX](/blog/autorefreshwithalpineandhtmx) - Alpine.js combineren met HTMX voor reactieve componenten
- [Het maken van uw site meer SPA-achtig met HTMX](/blog/htmxtomakeyoursitemorespalike) - SPA-achtige navigatie zonder JavaScript-kaders
- [Gebruik van SweetAlert voor HX-indicatoren](/blog/usingsweetalertforhxindicators) - Mooie laadindicatoren met HTMX
- [Toast en Swapping tonen met HTMX](/blog/showingtoastandswappingwithhtmx) - Server-getriggerde toastmeldingen

## Meer lezen

**Officiële HTMX-documentatie:**

- [HTMX-documentatie](https://htmx.org/docs/) - De officiële HTMX documentatie
- [HTMX-gebeurtenissenreferentie](https://htmx.org/events/) - Volledige lijst van HTMX-evenementen
- [HTMX-extensies](https://htmx.org/extensions/) - Officiële HTMX uitbreidingen
- [HTMX Voorbeelden](https://htmx.org/examples/) - Praktische voorbeelden van HTMX patronen
- [HTMX Essays](https://htmx.org/essays/) - Nadenkende artikelen over HTMX filosofie

**Bibliotheken & hulpprogramma's:**

- [HTMX.NET GitHub](https://github.com/khalidabuhakmeh/Htmx.Net) - De broncode van de HTMX.NET-bibliotheek
- [HTMX.NET NuGet](https://www.nuget.org/packages/Htmx/) - HTMX.NET op NuGet
- [Website van Khalid Abuhakmeh](https://khalidabuhakmeh.com/) - Maker van HTMX.NET
- [Alpine.js Documentatie](https://alpinejs.dev/) - Officiële documenten van Alpine.js

**Communautaire middelen:**

- [HTMX Discord](https://htmx.org/discord) - Actieve ondersteuning van de gemeenschap
- [Hypermedia Systems Book](https://hypermedia.systems/) - Gratis online boek over het bouwen van hypermedia toepassingen