URL tag helper
Hard-coded URLs like hx-get="/products/7" break when routes change. HtmxUrlTagHelper brings ASP.NET Core’s routing to htmx: you give it a page, controller/action, area or named route and it writes the generated URL into the htmx verb attribute you put on the element. It behaves like the built-in anchor tag helper, but for hx-get, hx-post, hx-put, hx-patch and hx-delete.
<button hx-get hxn-page="/UrlHelper" hxn-page-handler="Fragment" hx-target="#url-result-box">Page</button><button hx-get hxn-controller="Demo" hxn-action="Echo" hxn-route-id="7" hx-target="#url-result-box">MVC</button><button hx-get hxn-route="demo-echo" hxn-route-id="42" hxn-route-p="rv" hx-target="#url-result-box">Named route</button><button hx-get hxn-area="Admin" hxn-controller="Admin" hxn-action="Ping" hx-target="#url-result-box">Area</button><button hx-post hxn-page="/UrlHelper" hxn-page-handler="Post" hx-target="#url-result-box">POST</button>Rendered output (example):
<button hx-get="/UrlHelper?handler=Fragment" hx-target="#url-result-box">Page</button><button hx-get="/demo/echo/7" hx-target="#url-result-box">MVC</button>The matching handlers:
public IActionResult OnGetFragment() => Content("page handler Fragment", "text/html");public IActionResult OnPostPost() => Content("page handler Post ok", "text/html");
// DemoController.cs[HttpGet("echo/{id?}", Name = "demo-echo")]public IActionResult Echo(string? id, string? p) => /* ... */;Attributes
Section titled “Attributes”| Attribute | Property | Purpose |
|---|---|---|
hxn-page |
Page |
Razor Page path, e.g. /Products/Index |
hxn-page-handler |
PageHandler |
Page handler name (OnGetFragment -> Fragment) |
hxn-controller |
Controller |
MVC controller name |
hxn-action |
Action |
MVC action name |
hxn-area |
Area |
MVC area (also valid with pages) |
hxn-route |
Route |
Named route |
hxn-route-{key} |
RouteValues |
Route/query values: hxn-route-id="7" -> id=7. Case-insensitive dictionary. |
hxn-host |
Host |
Makes the URL absolute with this host |
hxn-protocol |
Protocol |
Scheme for an absolute URL (https) |
hxn-fragment |
Fragment |
URL #fragment |
Other members: Generator (the injected IHtmlGenerator), ViewContext (injected), Order (-1000, so it runs before other tag helpers) and Process(...). The helper only runs when hxn-page, hxn-action, hxn-controller or hxn-route is present.
- Put exactly one htmx verb on the element. More than one throws
InvalidOperationException. - Pick one link style: route, action/controller, or page/handler. Mixing them throws
InvalidOperationException. - An existing non-empty verb value wins; the helper does nothing.
- Binding attributes with no verb on the element do nothing (there is nowhere to write the URL).
Spellings: :inherited and data-hx-
Section titled “Spellings: :inherited and data-hx-”The helper recognizes hx-get, hx-get:inherited, data-hx-get, data-hx-get:inherited (and likewise for post, put, patch, delete) and writes the URL into whichever spelling is present.
Inheritance in htmx 4
Section titled “Inheritance in htmx 4”htmx 4 turned implicit inheritance off. A child sees a parent’s attribute only when the parent writes it with :inherited (or htmx.config.implicitInheritance is true).
<section hx-target:inherited="#inh-out" hx-headers-X-Demo="from-parent" hx-headers-inherited="true"> <button hx-get="/demo/inherited/echo?p=inh">child uses parent's target and headers</button></section>| Attribute | Inherits with :inherited? |
|---|---|
hx-target, hx-swap, hx-headers, hx-include, … |
Yes |
hx-get, hx-post, hx-put, hx-patch, hx-delete |
No: they do not make descendants send requests |
<section hx-target:inherited="#out" hx-headers-X-Tenant="@tenant" hx-headers-inherited="true"> <button hx-get hxn-controller="Orders" hxn-action="List">Orders</button> <button hx-get hxn-controller="Invoices" hxn-action="List">Invoices</button></section><div id="out"></div>The server can verify what the child inherited through request detection: h.TargetElement reports div#out, and Request.Headers["X-Tenant"] carries the header. See the Headers tag helper.
hx-delete and form values
Section titled “hx-delete and form values”htmx 4 serializes DELETE data into the query string and does not include enclosing form inputs automatically. Add hx-include when you need them:
<form> <input name="id" value="7" /> <button hx-delete hxn-page="/ErrorSwaps" hxn-page-handler="Delete" hx-include="closest form" hx-target="#del-out">Delete</button></form>For antiforgery on DELETE see the Antiforgery guide.
See the live demos: run dotnet run --project samples/Htmx4.Sample and open /UrlHelper (source) and /Inherited (source).
Related: Headers tag helper, Config tag helper, htmx 4 reference: attribute model.
From the blog: HTMX With ASP.NET Core covers the URL tag helpers alongside the rest of the library.