Integrating HTMX with .NET Core MVC and Razor Pages

Introduction

HTMX is a powerful library that allows you to add AJAX, CSS transitions, WebSockets, and Server-Sent Events directly in your HTML using attributes. When combined with .NET Core MVC and Razor Pages, HTMX can significantly enhance the user experience by making your web applications more interactive and responsive without requiring extensive JavaScript coding. In this post, we’ll explore how to integrate HTMX with .NET Core MVC and Razor Pages, focusing on use cases such as tables, forms, pagination, and filtering.

Prerequisites

Before we start, ensure you have the following:

  • .NET Core SDK installed
  • Basic knowledge of .NET Core MVC and Razor Pages
  • Basic knowledge of HTML, CSS, and JavaScript
  • HTMX library (you can include it via CDN in your project)

Setting Up Your .NET Core Project

  1. Create a new .NET Core MVC project:
   dotnet new mvc -n HTMXIntegrationDemo
   cd HTMXIntegrationDemo
  1. Add HTMX to your project:
    Include the HTMX library in your _Layout.cshtml file:
   <!DOCTYPE html>
   <html>
   <head>
       <title>HTMX Integration Demo</title>
       <script src="https://unpkg.com/[email protected]"></script>
   </head>
   <body>
       @RenderBody()
   </body>
   </html>

Using HTMX in Tables

HTMX can dynamically update table rows without refreshing the entire page. Let’s create a table that displays a list of items.

  1. Create a Model:
   public class Item
   {
       public int Id { get; set; }
       public string Name { get; set; }
       public decimal Price { get; set; }
   }
  1. Create a Controller:
   public class ItemsController : Controller
   {
       private static List<Item> Items = new List<Item>
       {
           new Item { Id = 1, Name = "Item 1", Price = 10.0m },
           new Item { Id = 2, Name = "Item 2", Price = 20.0m }
       };

       public IActionResult Index()
       {
           return View(Items);
       }

       public IActionResult AddItem()
       {
           var newItem = new Item { Id = Items.Count + 1, Name = $"Item {Items.Count + 1}", Price = 30.0m };
           Items.Add(newItem);
           return PartialView("_ItemRow", newItem);
       }
   }
  1. Create Views:

Index.cshtml

@model List<Item>

<h1>Items</h1>
<table id="itemsTable" class="table">
    <thead>
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@item.Id</td>
                <td>@item.Name</td>
                <td>@item.Price</td>
            </tr>
        }
    </tbody>
</table>
<button hx-get="/Items/AddItem" hx-target="tbody" hx-swap="beforeend">Add Item</button>

_ItemRow.cshtml

@model Item

<tr>
    <td>@Model.Id</td>
    <td>@Model.Name</td>
    <td>@Model.Price</td>
</tr>

Using HTMX in Forms

HTMX can enhance forms by providing real-time validation and partial form updates.

  1. Modify the Add Item Controller Action for Form Submission:
        public IActionResult AddItem(Item item)
        {
            var newItem = new Item { Id = item.Id + 1, Name = item.Name, Price = item.Price };
            Items.Add(newItem);
            return PartialView("_ItemRow", newItem);
        }
  1. Create Views:

_AddItemForm.cshtml

<h1>Submit Item</h1>
<form hx-post="/Items/AddItem" hx-target="tbody" hx-swap="beforeend" class="form-inline">
    <div class="form-group">
        <label for="Name">Name</label>
        <input type="text" id="Name" name="Name" class="form-control" required />
    </div>
    <div class="form-group">
        <label for="Price">Price</label>
        <input type="number" id="Price" name="Price" class="form-control" required />
    </div>
    <button type="submit" class="btn btn-primary">Add Item</button>
</form>

Using HTMX for Pagination

Implementing pagination with HTMX allows you to load pages dynamically without refreshing the whole page.

  1. Create a Controller Action for Pagination:
   public IActionResult Paginate(int page = 1)
   {
       int pageSize = 10;
       var paginatedItems = Items.Skip((page - 1) * pageSize).Take(pageSize).ToList();
       ViewBag.CurrentPage = page;
       return PartialView("_ItemList", paginatedItems);
   }
  1. Create Views:

Pagination.cshtml

<h1>Paginated Items</h1>
<div id="paginationContainer">
    <div hx-get="/Items/Paginate" hx-trigger="load">
        <!-- Paginated items will be loaded here -->
    </div>
    <button hx-get="/Items/Paginate?page=@(ViewBag.CurrentPage + 1)" hx-target="#paginationContainer" hx-swap="outerHTML">Load More</button>
</div>

_ItemList.cshtml

@model List<Item>

<ul>
    @foreach (var item in Model)
    {
        <li>@item.Name - @item.Price</li>
    }
</ul>

Using HTMX for Filtering

HTMX can dynamically filter content without reloading the page.

  1. Create a Controller Action for Filtering:
   public IActionResult Filter(string searchTerm)
   {
       var filteredItems = Items.Where(i => i.Name.Contains(searchTerm, StringComparison.OrdinalIgnoreCase)).ToList();
       return PartialView("_ItemList", filteredItems);
   }
  1. Create Views:
  • Filter.cshtml: <h1>Filter Items</h1> <input type="text" id="searchTerm" placeholder="Search..." hx-get="/Items/Filter" hx-target="#filterResults" hx-trigger="input changed delay:500ms" /> <div id="filterResults"> <!-- Filtered items will be loaded here --> </div>
  • _ItemList.cshtml: @model List<Item> <ul> @foreach (var item in Model) { <li>@item.Name - @item.Price</li> } </ul>

Filter.cshtml

<h1>Filter Items</h1>
<input type="text" id="searchTerm" placeholder="Search..." hx-get="/Items/Filter" hx-target="#filterResults" hx-trigger="input changed delay:500ms" />
<div id="filterResults">
    <!-- Filtered items will be loaded here -->
</div>

_ItemList.cshtml

@model List<Item>

<ul>
    @foreach (var item in Model)
    {
        <li>@item.Name - @item.Price</li>
    }
</ul>

Conclusion

Integrating HTMX with .NET Core MVC and Razor Pages can greatly enhance the interactivity and responsiveness of your web applications. By leveraging HTMX attributes, you can easily implement dynamic updates for tables, forms, pagination, and filtering without writing extensive JavaScript code. This approach not only improves the user experience but also simplifies your front-end development. Happy coding!