Skip to content

Getting started

htmx.NET gives ASP.NET Core two packages for htmx 4. This page takes you from an empty project to a working htmx interaction with antiforgery protection.

Package Purpose
Htmx Request detection (IsHtmx(), HtmxRequestHeaders) and response header helpers (Response.Htmx(...)).
Htmx.TagHelpers Razor tag helpers (htmx-config meta, URL generation, hx-headers-*) and the antiforgery script.

While 2.x is in preview, add --prerelease (NuGet skips pre-release versions otherwise):

Terminal window
dotnet add package Htmx --prerelease
dotnet add package Htmx.TagHelpers --prerelease

Both target net8.0 and net10.0. Htmx works in any ASP.NET Core app (minimal APIs, MVC, Razor Pages); Htmx.TagHelpers needs Razor (MVC views or Razor Pages).

Vendor the file (recommended; the sample keeps it in wwwroot/lib/htmx/htmx.min.js) or use a CDN:

<script src="https://unpkg.com/htmx.org@4.0.0/dist/htmx.min.js" defer></script>

From samples/Htmx4.Sample/Program.cs:

using Htmx.TagHelpers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllers();
builder.Services.AddAntiforgery();
var app = builder.Build();
app.UseStaticFiles();
app.UseRouting();
app.UseAntiforgery();
// serves /_htmx/antiforgery.js
app.MapHtmxAntiforgeryScript();
app.MapRazorPages();
app.MapControllers();
app.Run();

Pages/_ViewImports.cshtml (or Views/_ViewImports.cshtml):

@using Htmx
@addTagHelper *, Htmx.TagHelpers
@using Htmx.TagHelpers
<meta name="htmx-config" includeAspNetAntiforgeryToken="true" />
<script src="~/lib/htmx/htmx.min.js" defer></script>
<script src="@HtmxAntiforgeryScriptEndpoints.Path" defer></script>
  • The htmx-config meta is rendered by the config tag helper. includeAspNetAntiforgeryToken embeds the antiforgery token so htmx requests can send it. Keep it before the htmx script.
  • The script served by MapHtmxAntiforgeryScript() attaches that token to POST/PUT/PATCH/DELETE requests. See Antiforgery.

A button that loads a server-rendered fragment, plus a form that saves and fires a client event.

Pages/Products.cshtml:

@page
@model ProductsModel
<h1>Products</h1>
<!-- GET: the URL comes from the page handler via the tag helper -->
<button hx-get hxn-page="/Products" hxn-page-handler="List" hx-target="#list">Load</button>
<ul id="list"></ul>
<!-- POST: antiforgery token is attached automatically -->
<form hx-post hxn-page="/Products" hxn-page-handler="Add" hx-target="#list" hx-swap="beforeend"
hx-on:product-added="this.reset()">
<input name="name" required />
<button>Add</button>
</form>

Pages/Products.cshtml.cs:

using Htmx;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
public class ProductsModel : PageModel
{
private static readonly List<string> Items = ["Chai", "Chang"];
// the full page
public void OnGet() { }
public IActionResult OnGetList()
{
// direct visits get the full page
if (!Request.IsHtmx()) return RedirectToPage();
// cache-safe: Vary: HX-Request
Response.Htmx(h => h.WithVary());
return Content(string.Concat(Items.Select(i => $"<li>{i}</li>")), "text/html");
}
public IActionResult OnPostAdd(string name)
{
Items.Add(name);
// HX-Trigger -> reset the form
Response.Htmx(h => h.WithTrigger("product-added"));
return Content($"<li>{System.Net.WebUtility.HtmlEncode(name)}</li>", "text/html");
}
}

What happens: clicking Load sends GET /Products?handler=List with HX-Request: true; the <li> fragment replaces the list contents. Submitting the form sends POST with the antiforgery token, appends the new <li> (beforeend) and the product-added event resets the form.

I want to… Read
Detect htmx, boosted, partial vs full Request detection
Steer htmx from the server Response headers
Fire client events Triggering events
Change htmx settings Config tag helper
Generate URLs from routes URL tag helper
Send custom headers Headers tag helper
Protect POST/PUT/PATCH/DELETE Antiforgery
Multi-target and morph swaps Partials and morph
Cache correctly Caching
Browse working demos Samples

Run the full sample with dotnet run --project samples/Htmx4.Sample.

From the blog: HTMX With ASP.NET Core walks through the library and NuGet packages end to end.