Let me start by saying that I love the combination of Htmx and ASP.NET Core, and it is a pairing that any .NET developer should consider, whether maintaining an existing application or building a new one. It’s very cool. I was recently talking about revisiting the
hx-trigger
and
HX-Trigger
header technique with ASP.NET Core on Mastodon with Illya Busigin, and they mentioned they use the same method to update the avatar image when a user updates their profile. So, I thought I’d try and see how to implement it myself.
In this post, we’ll see how to use the
HX-Trigger
facility in Htmx to update existing UI elements on a rendered HTML page.
The Moving Parts
When building any new feature in an application, you need to arrange multiple components to work together. Let’s address all the parts you’ll need to make this experience.
- A User Profile store
- Profile Settings endpoints for display and updating
- An endpoint to refresh the avatar element on the page
We’ll be using the capabilities of ASP.NET Core Razor Pages and Razor Views to handle the HTML snippets that Htmx needs for swapping elements. Before we get into HTML and Htmx, let’s deal with our user profile storage service.
Note that you’ll need the NuGet packages of Htmx and, optionally, Htmx.TagHelpers.
The User Service
I created a straightforward class for the demo that will hold the user name and the avatar URL. In a “real application”, you’d likely store this information in a database or third-party auth service. Let’s see what I wrote.
The user can choose from three existing avatars, which are stored in the
wwwroot/img
folder. Fewer options mean less code for the demo and more focus on the Htmx bits that come later.
Next, we’ll register the UserService
as a
Singleton
in our ASP.NET Core setup class to maintain the state between requests. Note: This is only for the demo
and is not recommended in any other scenario.
Cool! Now, we can inject this service where we need it to grab the current state of the user profile, which includes the name and avatar URL.
I inject this service into my Layout.cshtml
and then render the avatar partial.
We’ll examine the partial later in the article, but first, let’s discuss our account endpoints.
Profile Endpoints
In a new Razor page titled Index
, we’ll have three endpoints:
- Show the profile settings form.
- Accept user updates
- Render the
_Avatar
profile image as partial content.
I’ll paste the full class here, and we’ll break it down into one endpoint at a time.
The first method we’ll look at is OnGet
. This method takes the information from the
UserService
and hydrates our property. These properties will be used to bind information to our form.
Next, closer to the bottom of the class, let’s look at a similar method, OnGetAvatar
.
This method returns the partial view of _Avatar
, simply displaying our user information. Now, let’s look at the
OnPost
method, which is the juiciest of the implementations.
Here, we determine if the user input is valid and then update the page. The two most important lines include the
Htmx
references.
If the incoming request was initiated with Htmx, we add a response header to tell Htmx to fire a client-side event of
avatar
. Any element subscribing to this event will then trigger another request. In our case, we’ll be calling the
OnGetAvatar
endpoint. You can add as many events as you need here, but we only want one in our case.
The following reference to Htmx checks if Htmx initiated the request. If it was, we need to send back a partial Html snippet.
That’s it! But what do the Razor views look like?
Htmx and Partial Views
Let’s start with the form since it is the focal point of our user experience. It’s straightforward Razor code with one exception: the Htmx attributes on the
form
tag.
These Htmx attributes allow us to hijack the form submission and route it through an Htmx request, allowing the library to process the header request. Once processed, it fires the event on the
_Avatar
partial. Let’s take a look at that view now.
The essential attribute on this view is the hx-trigger
attribute. Note the exact value.
The from:body
is essential, as the
body
element is what Htmx uses to broadcast the event. That’s it. Let’s see it in action!
Wow! That’s cool!
Conclusion
HX-Trigger
headers can help you decouple UI elements from each other and create a system of elements that can act independently. This can be very powerful, but it should be used in moderation, like all things. Remember, each triggered event results in a request back to the server, which could come at a cost. That said, many existing SPA UI approaches already make expensive calls to the server, so this might not be any worse than a GraphQL call or JSON over an HTTP request.
I’ve uploaded the code for this sample to my GitHub repository so you can try it out.
As always, thanks for reading and hope you give this one a try.