• Stars
    star
    166
  • Rank 226,659 (Top 5 %)
  • Language
    C#
  • License
    MIT License
  • Created about 3 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Adds extensions methods to HttpResponse and HttpRequest to make working with Htmx easier.

Htmx.Net

HTMX Logo

This is a package designed to add server side helper methods for HttpRequest and HttpResponse. This makes working with htmx server-side concepts simpler. You should also consider reading about Hyperscript, an optional companion project for HTMX.

Htmx Extension Methods

Getting Started

Install the Htmx NuGet package to your ASP.NET Core project.

dotnet add package Htmx

HttpRequest

Using the HttpRequest, we can determine if the request was initiated by Htmx on the client.

httpContext.Request.IsHtmx()

This can be used to either return a full page response or a partial page render.

// in a Razor Page
return Request.IsHtmx()
    ? Partial("_Form", this)
    : Page();

We can also retrieve the other header values htmx might set.

Request.IsHtmx(out var values);

Read more about the other header values on the official documentation page.

HttpResponse

We can set Http Response headers using the Htmx extension method, which passes an action and HtmxResponseHeaders object.

Response.Htmx(h => {
    h.PushUrl("/new-url")
     .WithTrigger("cool")
});

Read more about the HTTP response headers at the official documentation site.

Triggering Client-Side Events

You can trigger client side events with HTMX using the HX-Trigger header. Htmx.Net provides a WithTrigger helper method to configure one or more events that you wish to trigger.

Response.Htmx(h => {
    h.WithTrigger("yes")
     .WithTrigger("cool", timing: HtmxTriggerTiming.AfterSettle)
     .WithTrigger("neat", new { valueForFrontEnd= 42, status= "Done!" }, timing: HtmxTriggerTiming.AfterSwap);
});

Htmx.TagHelpers

Getting Started

Install the Htmx.TagHelpers NuGet package to your ASP.NET Core project. Targets .NET Core 3.1+ projects.

dotnet add package Htmx.TagHelpers

Make the Tag Helpers available in your project by adding the following line to your _ViewImports.cshtml:

@addTagHelper *, Htmx.TagHelpers

You'll generally need URL paths pointing back to your ASP.NET Core backend. Luckily, Htmx.TagHelpers mimics the url generation included in ASP.NET Core. This makes linking HTMX with your ASP.NET Core application a seamless experience.

<div hx-target="this">
    <button hx-get
            hx-page="Index"
            hx-page-handler="Snippet"
            hx-swap="outerHtml">
        Click Me (Razor Page w/ Handler)
    </button>
</div>

<div hx-target="this">
    <button hx-get
            hx-controller="Home"
            hx-action="Index"
            hx-route-id="1">
        Click Me (Controller)
    </button>
</div>

<div hx-target="this">
    <button hx-post
            hx-route="named">
        Click Me (Named)
    </button>
</div>

Htmx.Config

An additional htmx-config tag helper is included that can be applied to a meta element in your page's head that makes creating HTMX configuration simpler. For example, below we can set the historyCacheSize, default indicatorClass, and whether to include ASP.NET Core's anti-forgery tokens as an additional element on the HTMX configuration.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="htmx-config" 
          historyCacheSize="20"
          indicatorClass="htmx-indicator"
          includeAspNetAntiforgeryToken="true"
          />
    <!-- additional elements... -->
</head>

The resulting HTML will be.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="htmx-config" content='{"indicatorClass":"htmx-indicator","historyCacheSize":20,"antiForgery":{"formFieldName":"__RequestVerificationToken","headerName":"RequestVerificationToken","requestToken":"<token>"}}' />
    <!-- additional elements... -->
</head>

HTMX and Anti-forgery Tokens

You can set the attribute includeAspNetAntiforgerToken on the htmx-config element. Then you'll need to include this additional JavaScript in your web application. We include the attribute __htmx_antiforgery to track the event listener was added already. This keeps us from accidentally re-registering the event listener.

if (!document.body.attributes.__htmx_antiforgery) {
    document.addEventListener("htmx:configRequest", evt => {
        let httpVerb = evt.detail.verb.toUpperCase();
        if (httpVerb === 'GET') return;
        let antiForgery = htmx.config.antiForgery;
        if (antiForgery) {
            // already specified on form, short circuit
            if (evt.detail.parameters[antiForgery.formFieldName])
                return;

            if (antiForgery.headerName) {
                evt.detail.headers[antiForgery.headerName]
                    = antiForgery.requestToken;
            } else {
                evt.detail.parameters[antiForgery.formFieldName]
                    = antiForgery.requestToken;
            }
        }
    });
    document.addEventListener("htmx:afterOnLoad", evt => {
        if (evt.detail.boosted) {
            const parser = new DOMParser();
            const html = parser.parseFromString(evt.detail.xhr.responseText, 'text/html');
            const selector = 'meta[name=htmx-config]';
            const config = html.querySelector(selector);
            if (config) {
                const current = document.querySelector(selector);
                // only change the anti-forgery token
                const key = 'antiForgery';
                htmx.config[key] = JSON.parse(config.attributes['content'].value)[key];
                // update DOM, probably not necessary, but for sanity's sake
                current.replaceWith(config);
            }
        }
    });
    document.body.attributes.__htmx_antiforgery = true;
}

You can access the snippet in two ways. The first is to use the HtmxSnippet static class in your views.

<script>
@Html.Raw(HtmxSnippets.AntiforgeryJavaScript)
</script>

A simpler way is to use the HtmlExtensions class that extends IHtmlHelper.

@Html.HtmxAntiforgeryScript()

This html helper will result in a <script> tag along with the previously mentioned JavaScript. Note: You can still register multiple event handlers for htmx:configRequest, so having more than one is ok.

Note that if the hx-[get|post|put] attribute is on a <form ..> tag, the ASP.NET Tag Helpers will add the Anti-forgery Token as an input element and you do not need to further configure your requests as above. You could also use hx-include pointing to a form, but this all comes down to a matter of preference.

Additionally, and the recommended approach is to use the HtmxAntiforgeryScriptEndpoint, which will let you map the JavaScript file to a specific endpoint, and by default it will be _htmx/antiforgery.js.

app.UseAuthorization();
// registered here
app.MapHtmxAntiforgeryScript();
app.MapRazorPages();
app.MapControllers();

You can now configure this endpoint with caching, authentication, etc. More importantly, you can use the script in your head tag now by applying the defer tag, which is preferred to having JavaScript at the end of a body element.

<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta
        name="htmx-config"
        historyCacheSize="20"
        indicatorClass="htmx-indicator"
        includeAspNetAntiforgeryToken="true"/>
    <title>@ViewData["Title"] - Htmx.Sample</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css"/>
    <link rel="stylesheet" href="~/css/site.css" asp-append-version="true"/>
    <script src="~/lib/jquery/dist/jquery.min.js" defer></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js" defer></script>
    <script src="https://unpkg.com/htmx.org@@1.9.2" defer></script>
    <!-- this uses the static value in a script tag -->
    <script src="@HtmxAntiforgeryScriptEndpoints.Path" defer></script>
</head>

License

Copyright Β© 2022 Khalid Abuhakmeh

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the β€œSoftware”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED β€œAS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

More Repositories

1

ConsoleTables

Print out a nicely formatted table in a console application C#
C#
840
star
2

StonksWatcher

C#
105
star
3

htmx-aspnetcore

HTMX & ASP.NET Core Samples
HTML
63
star
4

EntityFrameworkCoreMultiTenancy

EF Core and Minimal API sample for multi-tenancy example using global filters
C#
60
star
5

SimplestAuthMvc5

The simplest authentication you can do with OWIN and ASP.NET MVC 5
JavaScript
40
star
6

HtmxTables

ASP.NET Core with Htmx Editable Table
C#
39
star
7

Branchy

Nested Route Registration for ASP.NET Core Minimal APIs
C#
38
star
8

codez

A library designed to help generating codes / confirmation strings
C#
36
star
9

TailwindAspNetCore

Install Tailwind CSS with ASP.NET Core
CSS
30
star
10

turbolinks.net

C#
27
star
11

MvcFlash

Flash Messages inspired by Rails
C#
25
star
12

aspnet-core-elasticsearch-demo

C#
22
star
13

SvelteAspNetCore

Adding Svelte To ASP.NET Core Projects
JavaScript
21
star
14

YarpReverseProxyFlowThroughAuth

Using YARP to flow through credentials from IdentityServer to other apps.
C#
21
star
15

marten-bank-sample

A sample of a simple bank using Marten's Event Store
C#
20
star
16

aspnetcore_localization_sample

C#
19
star
17

FreezeFrame

F# .NET global tool to grap the first frame of a GIF as a PNG
F#
18
star
18

AspNetCoreSignalRCharts

Using ASP.NET Core, SignalR, and ChartJs to create real-time updating charts
JavaScript
17
star
19

ef-core-entertainment

C#
17
star
20

Frankenblog

A Frankenblog template for folks coming from a .NET background who want to blog using Jekyll
C#
16
star
21

SoStreamy

KnockoutJs, SignalR, and RavenDB Changes Api
JavaScript
16
star
22

MvcFlash2

Successor to the Original MvcFlash
C#
16
star
23

MoonPhaseConsole

C#
15
star
24

SocialCards

Social Cards with ASP.NET Core, FeatherHTTP, and Playwright
HTML
15
star
25

Ducksboard

Ducksboard object implemented for use in your .NET projects
C#
13
star
26

Compressing

Use compression streams with .NET
C#
13
star
27

CsharpTenFeatures

C# 10 Features in one console application
Dockerfile
13
star
28

Image-Gallery

ASP.NET Core image gallery with Marten, ImageSharp, and HTMX
JavaScript
12
star
29

GameOfLifeMvvm

Conway's Game of Life with Avalonia UI and the MVVM pattern
C#
12
star
30

MassTransit.ScaleOut

Show how competing consumers work with MassTransit and RabbitMq
C#
12
star
31

blacksmith

IronMQ client that has some sensible assumptions of how .NET developers would want to use IronMQ.
C#
11
star
32

TiredDoctorManhattan

A Twitter Bot that responds with "I AM TIRED OF..."
C#
11
star
33

AspNetCoreLitWebComponents

Using Lit Web Components in an ASP.NET Core Web Project
TypeScript
11
star
34

GameOfLife

C#
11
star
35

ef-core-multiple-providers

EF Core 7 Multiple Database Providers Example (SQLite and Postgres)
C#
11
star
36

Blazortron

HTML
11
star
37

aspnetcore-vuecomponents

C#
10
star
38

FastEndpointsSample

Unit testing a FastEndpoints aspnet.core application
C#
10
star
39

HelloDotnetWasm

Building #dotnet code to target WASM in the browser
JavaScript
10
star
40

resource-permissions

Resource based permissions based on HTTP Action method intentions
C#
10
star
41

DotnetDramaMeter

dotnet Drama Meter with MAUI
C#
10
star
42

GrpcDemo

GrpcDemo for ASP.NET Core JetBrains Post
C#
10
star
43

record-equality-source-generator

Source Generator to modify record equality with attributes
C#
10
star
44

jekyll-aspnet-core

Running Jekyll On Top Of ASP.NET Core
CSS
9
star
45

StaticSiteTool

Generate HTML from ASP.NET Core MVC app
HTML
9
star
46

FluentTranslation

Using Fluent Project to do localization in .NET
C#
9
star
47

AspNetCoreLocalizationSample

ASP.NET Core Localization Sample (.NET 7+)
HTML
9
star
48

AvaloniaClock

Avalonia UI desktop clock app using NXUI
C#
9
star
49

AspNetCorePlaceholderImages

Using ImageSharp.Web you can create a local placeholder image service
HTML
8
star
50

Searching

Use Lunr to save and load a search index using .NET 5
C#
8
star
51

RobotsTxt

An ASP.NET Core Robots.txt Middleware
C#
8
star
52

monorepo_build

An example of building a mono repo based on files changes
8
star
53

AnimatedGifConsole

Using ImageSharp and Spectre.Console to animate gifs to the terminal
C#
8
star
54

EventSourcingDungeonCrawler

Using event sourcing to manage player state in a dungeon crawl
C#
8
star
55

DatabaseIntegrationTesting

C#
8
star
56

Farm

Blazor Farm Soundboard
HTML
8
star
57

Blazor-Weather-App-Sample

Example of a Blazor app calling a Weather API for forecasts
HTML
8
star
58

TimescaleAndEntityFrameworkCore

Timescale with Entity Framework Core 7
C#
8
star
59

OpenTokApi

OpenTok Api for .NET
C#
7
star
60

restful-routing-aspnetcore

Ported version of Restful Routing for ASP.NET Core
C#
7
star
61

HttpApi

Super Basic HTTP API with ASP.NET Core
C#
7
star
62

VerifyingFiles

C#
7
star
63

SuperMarioConsoleSong

Play The Super Mario Theme Using C#
C#
7
star
64

dotnet-dramameter

.NET Drama Meter web service
C#
7
star
65

EleventyCore

Combining 11ty and ASP.NET Core
JavaScript
7
star
66

Khalid.Fibonacci

NuGet Package Steps Needed to Go From Project to NuGet
C#
7
star
67

StyleTransfer

Using ONNX to StyleTransfer
C#
7
star
68

NoRepositories

Use the ORM you are using and dump the nasty Repository pattern.
C#
7
star
69

Idempotent-AspNetCore

Idempotency techniques for ASP.NET Core
C#
7
star
70

BlogPromoter

C#
7
star
71

MachineLearningDotnet7

Machine Learning with ML.NET and .NET 7
C#
7
star
72

Blazor-United

Blazor United for .NET 8 with all the possible paradigms in one solution
HTML
6
star
73

LinksExample

C#
6
star
74

GroupsAndFilters

Endpoints Filters for .NET 7
C#
6
star
75

BlazorCustomElementsSample

".NET 7 Blazor Custom Elements Sample hosted in ASP.NET Core Razor Pages"
HTML
6
star
76

MudBlazorInRazor

Using MudBlazor UI components in Razor Pages
HTML
6
star
77

Sorting

C#
6
star
78

SocialLogins

Social Login sample with .NET 5.0 and GitHub
C#
6
star
79

dotnet-six-todoapp

TodoApp Using EF Core 6 and .NET 6 Minimal Hosting
CSS
6
star
80

EntityFrameworkCoreRelationships

Entity Framework Core Relationships
C#
6
star
81

Xaml-For-Blazor-Sample

Xaml For Blazor (from OpenSilver) bringing XAML controls to Blazor
JavaScript
5
star
82

conversions

C#
5
star
83

signalr-postgresql-notifications

Sample showing realtime notifications from postgresql database connection
JavaScript
5
star
84

blazor-javascript-modules

HTML
5
star
85

YouTubeThumbnailGenerator

C#
5
star
86

GuidGenie

GuidGenie Twitter response bot
C#
5
star
87

HtmxCollections

Using Htmx, ASP.NET Core, and Marten (postgres document db) to sort list
JavaScript
5
star
88

MoonPhaseApp

C#
5
star
89

SideBySiteUnitTesting

Host tests side-by-side with code under test
C#
5
star
90

OpenTelemetryAspnet

Sample ASP.NET Core project using OpenTelemetry and Jaeger
C#
5
star
91

Mongo-Sample

MongoDB Sample project using Minimal APIs
C#
5
star
92

DatabaseHelpersExample

Create a LocalDB Sql Server database in process, attach, run tests, then clean up
C#
5
star
93

HttpQuery

Using experimental HTTP Method Query with ASPNET Core minimal API
C#
5
star
94

FluentSitemap

Let's you create a Sitemap using Asp.Net MVC
C#
5
star
95

PagedTableAspNetMvc

http://khalidabuhakmeh.com/building-a-robust-paged-table-in-asp-net-mvc
C#
5
star
96

khalidabuhakmeh

Khalid Abuhakmeh Profile Repository
4
star
97

aspnetcore-cursor-paging

C#
4
star
98

RidingTheGraph

GraphQL sample using Hot Chocolate and ASP.NET Core minimal hosting
C#
4
star
99

ExtismPlayground

Playing around with Extism as a plugin creator and consumer
C#
4
star
100

EFCoreDatabaseFunctions

C#
4
star