This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Friday, 02 May 2025
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.
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:
flowchart LR
A[htmx:configRequest] --> B[htmx:confirm] --> C[htmx:prompt] --> D[htmx:abort]
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:
flowchart LR E[htmx:beforeRequest] --> F[htmx:request] --> G[htmx:afterRequest]
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:
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]
De history management fase is waar HTMX de browsergeschiedenis en URL update. De volgende gebeurtenissen worden geactiveerd tijdens deze fase:
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.
Een van de meest krachtige aspecten van HTMX is de mogelijkheid om extensies aanmaken 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-Includes 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 of Lit 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:
{
/**
* 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.
Bijvoorbeeld een handige ingebouwde uitbreiding 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 slaanonEvent - het instellen van de Content-Type koptekst naar application/json wanneer het verzoek wordt geconfigureerdencodeParameters - 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.(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.
(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 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.
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.
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
}
}
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:
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.
<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>
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
Je kunt zien dat we elkaar aanraken. onEvent om te luisteren voor de htmx:configRequest event.
Dan gaan we:
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)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 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.
Als extensie is het heel eenvoudig te gebruiken:
Eerst moeten we de uitbreiding toevoegen aan onze HTMX configuratie.
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.
// 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.
<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 sortZo 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.
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. 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
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.
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).
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.
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;
}
}
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.
Bijvoorbeeld in mijn SweetAlert2-integratie Ik activeer het sluiten van het dialoogvenster met behulp van een trigger die is ingesteld vanaf de server.
document.body.addEventListener('sweetalert:close', closeSweetAlertLoader);
Dit wordt geactiveerd vanaf de server als een HTMX trigger event.
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.
Ik schreef over mijn toast methode eerder Hier., 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.
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.
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 .
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);
}
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.
Dit artikel maakt deel uit van een tweedelige serie op HTMX met ASP.NET Core:
Officiële HTMX-documentatie:
Bibliotheken & hulpprogramma's:
Communautaire middelen:
© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.