{"id":29027319,"url":"https://github.com/rameel/ramstack.htmxtoolkit","last_synced_at":"2025-06-26T06:05:25.105Z","repository":{"id":221761779,"uuid":"754825051","full_name":"rameel/ramstack.htmxtoolkit","owner":"rameel","description":"Enables seamless integration of HTMX with ASP.NET Core (https://htmx.org).","archived":false,"fork":false,"pushed_at":"2025-06-14T20:27:53.000Z","size":130,"stargazers_count":12,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-14T20:54:53.243Z","etag":null,"topics":["aspnetcore","htmx"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rameel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-08T20:44:49.000Z","updated_at":"2025-06-14T20:24:14.000Z","dependencies_parsed_at":"2024-02-23T21:27:02.312Z","dependency_job_id":"35556c0f-61f2-44ef-91a1-052ccb9a5664","html_url":"https://github.com/rameel/ramstack.htmxtoolkit","commit_stats":null,"previous_names":["rameel/ramstack.htmxtoolkit"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/rameel/ramstack.htmxtoolkit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.htmxtoolkit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.htmxtoolkit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.htmxtoolkit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.htmxtoolkit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rameel","download_url":"https://codeload.github.com/rameel/ramstack.htmxtoolkit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.htmxtoolkit/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262010868,"owners_count":23244414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aspnetcore","htmx"],"created_at":"2025-06-26T06:05:24.576Z","updated_at":"2025-06-26T06:05:25.087Z","avatar_url":"https://github.com/rameel.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HtmxToolkit\n[![NuGet](https://img.shields.io/nuget/v/Ramstack.HtmxToolkit.svg)](https://nuget.org/packages/Ramstack.HtmxToolkit)\n[![MIT](https://img.shields.io/github/license/rameel/ramstack.htmxtoolkit)](https://github.com/rameel/ramstack.htmxtoolkit/blob/main/LICENSE)\n\nProvides HTMX integration for ASP.NET Core applications.\n\n\u003c!-- TOC --\u003e\n  * [Getting Started](#getting-started)\n  * [HttpRequest](#httprequest)\n    * [HtmxRequestAttribute](#htmxrequestattribute)\n  * [HttpResponse](#httpresponse)\n    * [The declarative way of setting response headers](#the-declarative-way-of-setting-response-headers)\n  * [TagHelpers](#taghelpers)\n    * [HtmxUrlTagHelper](#htmxurltaghelper)\n    * [HtmxHeaderTagHelper](#htmxheadertaghelper)\n    * [HtmxConfigTagHelper](#htmxconfigtaghelper)\n  * [Antiforgery Token](#antiforgery-token)\n  * [Supported Versions](#supported-versions)\n  * [Contributions](#contributions)\n  * [Changelog](#changelog)\n    * [1.2.2](#122)\n    * [1.2.1](#121)\n    * [1.2.0](#120)\n    * [1.1.0](#110)\n  * [License](#license)\n\u003c!-- TOC --\u003e\n\n## Getting Started\n\nInstall `Ramstack.HtmxToolkit` [NuGet package](https://www.nuget.org/packages/Ramstack.HtmxToolkit/) to your project,\nuse the following command\n\n```console\ndotnet add package Ramstack.HtmxToolkit\n```\n\n## HttpRequest\n\nThe library provides a set of classes for working with `HttpRequest`.\nFirst off, there's the `HttpRequestExtensions` class.\n\n```csharp\n/// \u003csummary\u003e\n/// Provides extension methods for the \u003csee cref=\"HttpRequest\"/\u003e class.\n/// \u003c/summary\u003e\npublic static class HttpRequestExtensions\n{\n    /// \u003csummary\u003e\n    /// Determines whether the specified HTTP request is htmx request.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"request\"\u003eThe HTTP request.\u003c/param\u003e\n    /// \u003creturns\u003e\n    /// \u003cc\u003etrue\u003c/c\u003e if the specified HTTP request is htmx request; otherwise, \u003cc\u003efalse\u003c/c\u003e.\n    /// \u003c/returns\u003e\n    public static bool IsHtmxRequest(this HttpRequest request);\n\n    /// \u003csummary\u003e\n    /// Determines whether the specified HTTP request is htmx request.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"request\"\u003eThe HTTP request.\u003c/param\u003e\n    /// \u003cparam name=\"headers\"\u003eWhen this methods returns, contains the \u003csee cref=\"HtmxRequestHeaders\"/\u003e\n    /// that provides well-known htmx headers.\u003c/param\u003e\n    /// \u003creturns\u003e\n    /// \u003cc\u003etrue\u003c/c\u003e if the specified HTTP request is htmx request; otherwise, \u003cc\u003efalse\u003c/c\u003e.\n    /// \u003c/returns\u003e\n    public static bool IsHtmxRequest(this HttpRequest request, out HtmxRequestHeaders headers);\n\n    /// \u003csummary\u003e\n    /// Determines whether the specified HTTP request was made using AJAX\n    /// instead of a normal navigation.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"request\"\u003eThe HTTP request.\u003c/param\u003e\n    /// \u003creturns\u003e\n    /// \u003cc\u003etrue\u003c/c\u003e if the specified HTTP request is boosted; otherwise, \u003cc\u003efalse\u003c/c\u003e.\n    /// \u003c/returns\u003e\n    public static bool IsHtmxBoosted(this HttpRequest request);\n\n    /// \u003csummary\u003e\n    /// Determines whether the specified HTTP request was made using AJAX\n    /// instead of a normal navigation.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"request\"\u003eThe HTTP request.\u003c/param\u003e\n    /// \u003cparam name=\"headers\"\u003eWhen this methods returns, contains the \u003csee cref=\"HtmxRequestHeaders\"/\u003e\n    /// that provides well-known htmx headers.\u003c/param\u003e\n    /// \u003creturns\u003e\n    /// \u003cc\u003etrue\u003c/c\u003e if the specified HTTP request is boosted; otherwise, \u003cc\u003efalse\u003c/c\u003e.\n    /// \u003c/returns\u003e\n    public static bool IsHtmxBoosted(this HttpRequest request, out HtmxRequestHeaders headers);\n\n    /// \u003csummary\u003e\n    /// Returns the \u003csee cref=\"HtmxRequestHeaders\"/\u003e that provides well-known htmx headers.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"request\"\u003eThe HTTP request.\u003c/param\u003e\n    /// \u003creturns\u003e\n    /// The \u003csee cref=\"HtmxRequestHeaders\"/\u003e.\n    /// \u003c/returns\u003e\n    public static HtmxRequestHeaders GetHtmxHeaders(this HttpRequest request);\n}\n```\n\nThe `IsHtmxRequest` method allows you to determine whether the current request is initiated by HTMX.\n\n```csharp\nHttpContext.Request.IsHtmxRequest()\n```\n\nAnd thus, you can define different scenarios depending on the result, for example:\n\n```csharp\nif (Request.IsHtmxRequest())\n    return PartialView();\n\nreturn View();\n```\n\nThe overloads of these methods provide access to strongly typed headers set by HTMX:\n\n```csharp\nif (Request.IsHtmxRequest(out var headers))\n{\n    if (headers.HistoryRestoreRequest)\n    {\n        ...\n    }\n}\n```\n\nIn addition, access to strongly typed headers can be obtained by calling `GetHtmxHeaders`:\n\n```csharp\nvar headers = Request.GetHtmxHeaders();\n```\n\nThe full list of headers is presented below:\n\n```csharp\n/// \u003csummary\u003e\n/// Represents strongly typed HTMX request headers.\n/// \u003c/summary\u003e\npublic readonly struct HtmxRequestHeaders\n{\n    /// \u003csummary\u003e\n    /// Gets a value indicating whether the request\n    /// was made using AJAX instead of a normal navigation.\n    /// \u003c/summary\u003e\n    public bool Boosted { get; }\n\n    /// \u003csummary\u003e\n    /// Gets the current URL of the browser.\n    /// \u003c/summary\u003e\n    public string? CurrentUrl { get; }\n\n    /// \u003csummary\u003e\n    /// Gets a value indicating whether the request\n    /// is for history restoration after a miss in the local history cache.\n    /// \u003c/summary\u003e\n    public bool HistoryRestoreRequest { get; }\n\n    /// \u003csummary\u003e\n    /// Gets the user response to an hx-prompt on the client.\n    /// \u003c/summary\u003e\n    public string? Prompt { get; }\n\n    /// \u003csummary\u003e\n    /// Gets a value indicating whether the current request is htmx request.\n    /// \u003c/summary\u003e\n    public bool Request { get; }\n\n    /// \u003csummary\u003e\n    /// Gets the ID of the target element if it exists.\n    /// \u003c/summary\u003e\n    public string? Target { get; }\n\n    /// \u003csummary\u003e\n    /// Gets the name of the triggered element if it exists.\n    /// \u003c/summary\u003e\n    public string? TriggerName { get; }\n\n    /// \u003csummary\u003e\n    /// Gets the ID of the triggered element if it exists\n    /// as indicated by the \u003cc\u003eHX-Trigger\u003c/c\u003e header.\n    /// \u003c/summary\u003e\n    public string? Trigger { get; }\n}\n```\n\nExample of usage:\n\n```csharp\nif (Request.GetHtmxHeaders().HistoryRestoreRequests)\n{\n    ...\n}\n```\n\nThe library also provides a set of predefined string constants for request headers,\nso you don't have to remember them each time and risk making mistakes in spelling.\nYou can find them in the `HtmxRequestHeaderNames` class.\n\n```csharp\n/// \u003csummary\u003e\n/// Defines constants for the well-known names of htmx request headers.\n/// For more information, see https://htmx.org/reference/#request_headers\n/// \u003c/summary\u003e\npublic static class HtmxRequestHeaderNames\n{\n    /// \u003csummary\u003e\n    /// The \u003cc\u003eHX-Boosted\u003c/c\u003e header indicates whether the request was made using AJAX\n    /// instead of a normal navigation.\n    /// \u003c/summary\u003e\n    public const string Boosted = \"HX-Boosted\";\n\n    /// \u003csummary\u003e\n    /// The \u003cc\u003eHX-Current-URL\u003c/c\u003e header contains the current URL of the browser.\n    /// \u003c/summary\u003e\n    public const string CurrentUrl = \"HX-Current-URL\";\n\n    ...\n    // The list of other constants is omitted for brevity\n}\n```\n\n### HtmxRequestAttribute\n\nTo simplify some manual checks, the library provides an ASP.NET Core result filter\nthat can be applied to an action controller, page handler, or the entire controller:\n\n```csharp\npublic class UserController : ControlleBase\n{\n    [HtmxRequest]\n    public IActionResult UpdateProfile(UserProfile profile)\n    {\n        ...\n    }\n}\n```\n\nIf you are processing boosted requests in a special way, add the `Boosted` parameter.\n\n```csharp\npublic class UserController : ControlleBase\n{\n    ...\n    [HtmxRequest(Boosted = true)]\n    public IActionResult UpdateProfile(UserProfile profile)\n    {\n        ...\n    }\n}\n```\n\n## HttpResponse\n\nFor working with response headers, the library also provides a set of classes.\nThe first one is the `HttpResponseExtension` class with extension methods:\n\n```csharp\n/// \u003csummary\u003e\n/// Provides extension methods for the \u003csee cref=\"HttpResponse\"/\u003e class.\n/// \u003c/summary\u003e\npublic static class HttpResponseExtensions\n{\n    /// \u003csummary\u003e\n    /// Returns the \u003csee cref=\"HtmxResponseHeaders\"/\u003e that provides well-known htmx headers.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"response\"\u003eThe HTTP response.\u003c/param\u003e\n    /// \u003creturns\u003e\n    /// The \u003csee cref=\"HtmxResponseHeaders\"/\u003e.\n    /// \u003c/returns\u003e\n    public static HtmxResponseHeaders GetHtmxHeaders(this HttpResponse response);\n\n    /// \u003csummary\u003e\n    /// Configures the htmx response headers.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"response\"\u003eThe HTTP response to configure.\u003c/param\u003e\n    /// \u003cparam name=\"configure\"\u003eThe function to configure the htmx response headers.\u003c/param\u003e\n    public static void Htmx(this HttpResponse response, Action\u003cHtmxResponse\u003e configure);\n\n    /// \u003csummary\u003e\n    /// Configures the htmx response headers.\n    /// \u003c/summary\u003e\n    /// \u003cparam name=\"response\"\u003eThe HTTP response to configure.\u003c/param\u003e\n    /// \u003cparam name=\"configure\"\u003eThe function to configure the htmx response headers.\u003c/param\u003e\n    /// \u003cparam name=\"state\"\u003eThe value to pass to the \u003cparamref name=\"configure\"/\u003e.\u003c/param\u003e\n    public static void Htmx\u003cTState\u003e(this HttpResponse response, Action\u003cHtmxResponse, TState\u003e configure, TState state);\n}\n```\n\nThe `GetHtmxHeaders` method provides access to strongly typed response headers\nthat control HTMX behavior.\n\n```csharp\n/// \u003csummary\u003e\n/// Represents strongly typed HTMX response headers.\n/// \u003c/summary\u003e\npublic sealed class HtmxResponseHeaders\n{\n    /// \u003csummary\u003e\n    /// Gets or sets the \u003cc\u003eHX-Location\u003c/c\u003e header to a client-side redirect\n    /// that does not do a full page reload.\n    /// \u003c/summary\u003e\n    [MaybeNull]\n    public string Location { get; set; }\n\n    /// \u003csummary\u003e\n    /// Gets or sets the \u003cc\u003eHX-Push-Url\u003c/c\u003e header to push a new URL into the history stack.\n    /// \u003c/summary\u003e\n    [MaybeNull]\n    public string PushUrl { get; set; }\n\n    ...\n    // The remaining properties are omitted for brevity\n}\n```\n\nJust like `HtmxRequestHeaderNames`, which consists of predefined string constants for HTMX request headers,\nthere is a corresponding `HtmxResponseHeaderNames` class containing\na list of string constants for HTMX response headers.\n\n```csharp\n/// \u003csummary\u003e\n/// Defines constants for the well-known names of htmx response headers.\n/// For more information, see https://htmx.org/reference/#response_headers\n/// \u003c/summary\u003e\npublic static class HtmxResponseHeaderNames\n{\n    /// \u003csummary\u003e\n    /// The \u003cc\u003eHX-Location\u003c/c\u003e header is used to a client-side redirect that does not do a full page reload.\n    /// \u003c/summary\u003e\n    public const string Location = \"HX-Location\";\n\n    /// \u003csummary\u003e\n    /// The \u003cc\u003eHX-Push-Url\u003c/c\u003e header is used to push a new URL into the history stack.\n    /// \u003c/summary\u003e\n    public const string PushUrl = \"HX-Push-Url\";\n\n    /// \u003csummary\u003e\n    /// The \u003cc\u003eHX-Redirect\u003c/c\u003e header is used to client-side redirect to a new location.\n    /// \u003c/summary\u003e\n    public const string Redirect = \"HX-Redirect\";\n\n    ...\n    // The list of other constants is omitted for brevity\n}\n```\n\nHowever, the most convenient and efficient way is by using one of the provided `Htmx` methods\nwith a callback that accepts `HtmxResponse`, allowing you to specify response headers\nin a fluent style:\n\n```csharp\nResponse.Htmx(h =\u003e h\n    .TriggerEvent(\n        eventName: \"process\",\n        detail: new { Value = ... })\n    .StopPolling(ShouldStopPolling));\n```\n\n:bulb: The second Htmx method accepts an additional parameter to avoid unnecessary allocations due to closures:\n\n```csharp\nResponse.Htmx(\n    static (h, stop) =\u003e h\n        .TriggerEvent(\n            eventName: \"process\",\n            detail: new { Value = ... })\n        .StopPolling(stop),\n    ShouldStopPolling);\n```\n\n:bulb: The `Htmx` extension methods are also available for `IActionResult`, allowing you to write:\n\n```csharp\nreturn Json(profile).Htmx(h =\u003e h.StopPolling(ShouldStopPolling));\n```\n\nIn both cases, the headers will be set only in the case of an `htmx` request.\nIn the case of a regular request, the callback passed to the `Htmx(this)` method will not be executed,\nwhich allows avoiding unnecessary work.\n\n### The declarative way of setting response headers\n\nSome of the response headers can be set declaratively using the `HtmxResponseAttribute`,\nwhich is applied to the controller, action, or page.\n\n```csharp\npublic class UserController : ControlleBase\n{\n    [HtmxRequest]\n    [HtmxResponse(\n        StopPolling = true,\n        Reswap = HtmxSwap.OuterHtml)]\n    public IActionResult UpdateProfile(UserProfile profile)\n    {\n        ...\n    }\n}\n```\n\n:bulb: If a more complex expression is needed for `swap`, for example, `innerHTML show:#result:top`,\nyou can use the `Reswap` method in the `HtmxResponse` class, which accepts a string.\n\n```csharp\n/// \u003csummary\u003e\n/// Sets the \u003cc\u003eHX-Reswap\u003c/c\u003e header to specify how the response will be swapped.\n/// \u003c/summary\u003e\n/// \u003cparam name=\"value\"\u003eThe header value to set.\u003c/param\u003e\n/// \u003creturns\u003e\n/// The current \u003csee cref=\"HtmxResponse\"/\u003e instance.\n/// \u003c/returns\u003e\npublic HtmxResponse Reswap(string value);\n\n/// \u003csummary\u003e\n/// Sets the \u003cc\u003eHX-Reswap\u003c/c\u003e header to specify how the response will be swapped.\n/// \u003c/summary\u003e\n/// \u003cparam name=\"value\"\u003eThe header value to set.\u003c/param\u003e\n/// \u003creturns\u003e\n/// The current \u003csee cref=\"HtmxResponse\"/\u003e instance.\n/// \u003c/returns\u003e\npublic HtmxResponse Reswap(HtmxSwap value);\n```\n\nAnd for the `HtmxResponseAttribute`, there is the `ReswapExpression` property.\n\n```csharp\n/// \u003csummary\u003e\n/// Gets or sets the \u003cc\u003eHX-Reswap\u003c/c\u003e header that allows to specify how the response will be swapped.\n/// \u003c/summary\u003e\n[MaybeNull]\npublic string ReswapExpression { get; set; }\n\n/// \u003csummary\u003e\n/// Gets or sets the \u003cc\u003eHX-Reswap\u003c/c\u003e header that allows to specify how the response will be swapped.\n/// \u003c/summary\u003e\npublic HtmxSwap Reswap { get; set; }\n```\n\nallowing you to flexibly configure the `swap` header you need.\n\n## TagHelpers\n\nThe library provides 3 tag helpers:\n\n* `HtmxUrlTagHelper`\n* `HtmxHeaderTagHelper`\n* `HtmxConfigTagHelper`\n\nTo make them available in your project, add the `@addTagHelper` directive in the Razor view.\n\n```razor\n@addTagHelper *, Ramstack.HtmxToolkit\n```\n\nTo make the tag helpers available globally for the entire application, you should add this line\nto the `_ViewImports.cshtml` file, which is inherited by all view files by default.\n\n### HtmxUrlTagHelper\n\nThe `HtmxUrlTagHelper` allows generating links for HTMX methods similar to how it's done in ASP.NET Core\nfor generating links, just replace the `asp-` prefix with the `hx-` prefix.\n\n```html\n\u003cdiv hx-target=\"this\"\u003e\n    \u003cbutton hx-area=\"Sessions\"\n            hx-controller=\"Speaker\"\n            hx-action=\"Detail\"\n            hx-route-id=\"@Model.SpeakerId\"\u003eShow Info\u003c/button\u003e\n\u003c/div\u003e\n```\n\nThe following code will be generated:\n\n```html\n\u003cdiv hx-target=\"this\"\u003e\n    \u003cbutton hx-get=\"/Sessions/Speaker/Detail/1\"\u003eShow Info\u003c/button\u003e\n\u003c/div\u003e\n```\n\nBy default, if no HTMX method is specified, `hx-get` is used. To specify a particular method,\nyou can choose one from the following attributes: `hx-get`, `hx-post`, `hx-put`, `hx-delete`, or `hx-patch`.\n\nFor instance, in the following example, we use `hx-post`:\n```html\n\u003cdiv hx-target=\"this\"\u003e\n    \u003cbutton hx-post\n            hx-area=\"Sessions\"\n            hx-controller=\"Speaker\"\n            hx-action=\"Detail\"\n            hx-route-id=\"@Model.SpeakerId\"\u003eShow Info\u003c/button\u003e\n\u003c/div\u003e\n```\n\nIn this case, the following code will be generated:\n\n```html\n\u003cdiv hx-target=\"this\"\u003e\n    \u003cbutton hx-post=\"/Sessions/Speaker/Detail/1\"\u003eShow Info\u003c/button\u003e\n\u003c/div\u003e\n```\n\nThe following attributes are also available for obtaining links to a page and a page handler:\n\n```html\n\u003cdiv hx-target=\"this\"\u003e\n    \u003cbutton hx-page=\"/Attendee\"\n            hx-page-handler=\"Profile\"\n            hx-route-attendeeid=\"1\"\u003eAttendee Profile\u003c/button\u003e\n\u003c/div\u003e\n```\n\nThe following code will be generated:\n\n```html\n\u003cdiv hx-target=\"this\"\u003e\n    \u003cbutton hx-get=\"/Attendee?attendeeid=1\u0026handler=Profile\"\u003eAttendee Profile\u003c/button\u003e\n\u003c/div\u003e\n```\n\nAlso, the `hx-all-route-data` attribute is available, which accepts a dictionary where\nthe key is the parameter name, and the value is the parameter value. In the example below,\na dictionary with specific parameters is created, which is then used as the value\nof the `hx-all-route-data` attribute.\n\n```html\n@{\n    var parameters = new {\n        category = \"science\",\n        pdf = true\n    };\n}\n\n\u003cbutton hx-target=\"#result\"\n        hx-action=\"List\"\n        hx-all-route-data=\"parameters\"\u003eBooks\u003c/a\u003e\n```\n\nThe following code will be generated:\n\n```html\n\u003cbutton hx-target=\"#result\" hx-get=\"/Books/List?category=science\u0026pdf=true\"\u003eBooks\u003c/a\u003e\n```\n\nIn addition to the examples mentioned, the following properties are also available:\n* `hx-host`\n* `hx-protocol`\n* `hx-fragment`\n\n### HtmxHeaderTagHelper\n\nThe `htmx` library allows adding custom headers that will be submitted with an AJAX request.\nHowever, since JSON format should be used for this, writing it out manually is not always convenient,\nespecially considering the need to escape special characters. Fortunately, the library provides\nthe `HtmxHeaderTagHelper` class, which takes care of this and allows specifying headers\nin a clearer and more readable format.\n\n```html\n \u003cdiv hx-action=\"example\"\n      hx-header-Key-1=\"Value-1\"\n      hx-header-Key-2=\"Value-2\"\u003e\n      Get Some HTML, Including A Custom Header in the Request\n  \u003c/div\u003e\n```\n\nThe following code will be generated:\n\n```html\n \u003cdiv hx-get=\"/home/example\"\n      hx-headers='{\"Key-1\":\"Value-1\",\"Key-2\":\"Value-2\"}'\u003e\n      Get Some HTML, Including A Custom Header in the Request\n  \u003c/div\u003e\n```\n\nAlso, if you have a dictionary with the headers you need,\nyou can assign them to the `hx-all-headers` attribute:\n\n```html\n \u003cdiv hx-action=\"example\"\n      hx-all-headers=\"headers\"\u003e\n      Get Some HTML, Including A Custom Header in the Request\n  \u003c/div\u003e\n```\n\nThe `HtmxHeaderTagHelper` will take care of all the remaining work regarding JSON serialization and escaping.\n\n### HtmxConfigTagHelper\n\nAs with `hx-headers`, configuring `htmx` settings requires a JSON representation.\nFor working with configuration, the `HtmxConfigTagHelper` class is provided.\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta htmx-config\n          default-swap-style=\"HtmxSwap.OuterHtml\"\n          use-template-fragments=\"true\"\n          scroll-behavior=\"HtmxScrollBehavior.Smooth\"\n          include-antiforgery-token=\"true\" /\u003e\n\u003c/head\u003e\n```\nThe following code will be generated:\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml lang=\"en\"\u003e\n\u003chead\u003e\n    \u003cmeta name=\"htmx-config\"\n          content='{\"defaultSwapStyle\":\"outerHTML\",\"useTemplateFragments\":true,\"scrollBehavior\":\"smooth\",\"antiForgery\":{\"headerName\":\"RequestVerificationToken\",\"formFieldName\":\"__RequestVerificationToken\",\"requestToken\":\"...\"}}' /\u003e\n\u003c/head\u003e\n```\n\nIf desired or for the purpose of semantics, you can use `htmx-config` as the standalone name of the element:\n```html\n\u003chtmx-config default-swap-style=\"HtmxSwap.OuterHtml\"\n             use-template-fragments=\"true\"\n             scroll-behavior=\"HtmxScrollBehavior.Smooth\"\n             include-antiforgery-token=\"true\" /\u003e\n```\n\n## Antiforgery Token\n\nIf you have enabled the generation of the **Antiforgery** token in the configuration\n(`include-antiforgery-token=\"true\"`), then you need to include a small JavaScript file\nthat will ensure this token is present in form parameters or headers\nand refresh it in a timely manner.\n\nTo do this, you can directly include the contents of the JavaScript file on the page:\n\n```html\n\u003cscript\u003e\n  @Html.HtmxAntiforgeryScript()\n\u003c/script\u003e\n```\n\nAlternatively, to retrieve the debug version of the script,\nyou can pass the debug parameter with a value of `true`:\n\n```html\n\u003cscript\u003e\n  @Html.HtmxAntiforgeryScript(debug: true)\n\u003c/script\u003e\n```\n\nThe `debug` parameter determines which version will be included. By default, the minimized version\nof the script will be returned, which weighs very little and takes up approximately 520 bytes.\n\nThe method returns a pre-initialized `HtmlString` with the script content,\nso there will be no unnecessary conversions and allocations every time it's used.\n\nAlternatively, you can register the corresponding endpoint for the script by calling:\n\n```csharp\napp.UseAuthorization();\n...\napp.MapHtmxAntiforgeryScript();\napp.MapControllers();\n```\n\nBy default, the registered path is mapped to `/htmxtoolkit/[sha1-hash]`,\nwhere **[sha1-hash]** represents a precalculated hash of the script content.\nThis approach eliminates the need to worry about cache invalidating\nwhen updating the script in the future as the hash automatically changes\nwhen the script content is modified.\n\nIf you want to change the path to your own, specify this path in the parameter.\n\n```csharp\napp.MapHtmxAntiforgeryScript(\"/my-path\");\n```\n\nNow, include it on the page.\n\n```html\n\u003cscript src=\"@Html.HtmxAntiforgeryScriptPath()\"\u003e\u003c/script\u003e\n```\n\nAlternatively, to retrieve the debug version of the script, you can pass the `debug` parameter\nwith a value of `true`, which instructs to include a query parameter `?debug` in the path.\nThe presence of this parameter determines the loading of the debug version:\n\n```html\n\u003cscript src=\"@Html.HtmxAntiforgeryScriptPath(debug: true)\"\u003e\u003c/script\u003e\n```\n\nThe `debug` parameter determines whether to load the minimized version (used by default)\nor the debug version of the script.\n\n## Supported Versions\n\n|      | Version    |\n|------|------------|\n| .NET | 6, 7, 8, 9 |\n\n## Contributions\n\nBug reports and contributions are welcome.\n\n## Changelog\n\n### 1.2.2\nExplicitly pass `document` object to event listeners in `htmx-toolkit.js` to improve compatibility\n\n### 1.2.1\nAdd `[DisallowNull]` attribute to `Reswap` property to disallow null input\n\n### 1.2.0\n* Add `AjaxContext` to align with the capabilities provided by htmx\n* Add method overloads for `PushUrl` and `ReplaceUrl` that prevents URL changes (`PreventPushUrl` / `PreventReplaceUrl`)\n* Add support `\u003chtmx-config /\u003e` element as a standalone HTML element\n\n### 1.1.0\n* Add overloads for IsHtmxRequest and IsHtmxBoosted methods enabling retrieval of htmx request headers\n* Improve HtmxRequestAttribute\n\n## License\nThis package is released as open source under the **MIT License**.\nSee the [LICENSE](https://github.com/rameel/ramstack.htmxtoolkit/blob/main/LICENSE) file for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frameel%2Framstack.htmxtoolkit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frameel%2Framstack.htmxtoolkit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frameel%2Framstack.htmxtoolkit/lists"}