Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 37 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,15 @@ to your project with the following command:
dotnet add package Ramstack.HtmxToolkit
```

Register the toolkit and select the HTMX version used by the application:

```csharp
builder.Services.AddHtmxToolkit(options =>
{
options.UseHtmxV2(config =>
{
config.DefaultSwapStyle = HtmxSwap.OuterHtml;
config.Timeout = 5000;
config.GlobalViewTransitions = true;
});
});
```

HTMX 2.x is used by default. Calling `UseHtmxV2` is optional when no version-specific
settings are required:
Register the toolkit. HTMX 2.x is used by default:

```csharp
builder.Services.AddHtmxToolkit();
```

To select another major version or override HTMX defaults, see
[`HtmxConfigTagHelper`](#htmxconfigtaghelper).

## HttpRequest

The library provides the `HttpRequestExtensions` class for working with `HttpRequest`.
Expand Down Expand Up @@ -365,7 +353,7 @@ public static class HtmxResponseHeaderNames
}
```

The most convenient approach is to use one of the `Htmx` extension methods.
The most convenient approach is to use one of the `HttpResponse.Htmx` extension methods.
Its callback receives an `HtmxResponse`, allowing you to configure response headers in a fluent style:

```csharp
Expand All @@ -388,10 +376,14 @@ Response.Htmx(
ShouldStopPolling);
```

:bulb: The `Htmx` extension methods are also available for `IActionResult`, allowing you to write:
:bulb: The same API works in Minimal API handlers by binding `HttpResponse`:

```csharp
return Json(profile).Htmx(h => h.StopPolling(ShouldStopPolling));
app.MapGet("/profile", (HttpResponse response) =>
{
response.Htmx(h => h.Retarget("#profile"));
return TypedResults.Content("<div>Profile</div>", "text/html");
});
```

In all these examples, headers are set only for an HTMX request. For a regular request,
Expand All @@ -400,18 +392,18 @@ the callback passed to `Htmx` is not executed, avoiding unnecessary work.
### The declarative way of setting response headers

Some response headers can be set declaratively by applying `HtmxResponseAttribute`
to a controller or action:
to a controller or action. For example, an action that renders one new comment can append
it to the element targeted by the request:

```csharp
public class UserController : ControllerBase
public class CommentController : Controller
{
[HtmxRequest]
[HtmxResponse(
StopPolling = true,
Reswap = HtmxSwap.OuterHtml)]
public IActionResult UpdateProfile(UserProfile profile)
[HtmxResponse(Reswap = HtmxSwap.BeforeEnd)]
public IActionResult Add(CommentInput input)
{
...
var comment = ...;
return PartialView("_Comment", comment);
}
}
```
Expand Down Expand Up @@ -689,16 +681,17 @@ With HTMX 4.x selected, the following HTML will be generated:
### HtmxConfigTagHelper

HTMX configuration is defined at application startup through `AddHtmxToolkit`.
The version-specific callback exposes only settings supported by the selected HTMX version:
The values apply application-wide and override HTMX defaults, so configure only behavior
the application relies on. For example, a form-oriented application can report native
validation failures before sending a request and scroll restored focus into view after a swap:

```csharp
builder.Services.AddHtmxToolkit(options =>
{
options.UseHtmxV2(config =>
{
config.DefaultSwapStyle = HtmxSwap.OuterHtml;
config.Timeout = 5000;
config.GlobalViewTransitions = true;
config.ReportValidityOfForms = true;
config.DefaultFocusScroll = true;
});
});
```
Expand All @@ -716,7 +709,7 @@ The following markup will be generated:
```html
<head>
<meta name="htmx-config"
content='{"defaultSwapStyle":"outerHTML","timeout":5000,"globalViewTransitions":true}'
content='{"defaultFocusScroll":true,"reportValidityOfForms":true}'
data-antiforgery-request-token="..."
data-antiforgery-header-name="RequestVerificationToken"
data-antiforgery-form-field-name="__RequestVerificationToken" />
Expand All @@ -734,20 +727,10 @@ version explicitly. Each configuration type follows the names used by that HTMX
and 2.x expose `DefaultSwapStyle` and `Timeout`, while HTMX 4.x exposes `DefaultSwap` and
`DefaultTimeout`. Selecting different versions in the same configuration throws an exception.

HTMX 4.x is currently in beta. To target it, select it explicitly and use its version-specific
settings:
HTMX 4.x is currently in beta. To target it, select it explicitly:

```csharp
builder.Services.AddHtmxToolkit(options =>
{
options.UseHtmxV4(config =>
{
config.DefaultSwap = HtmxSwap.OuterHtml;
config.DefaultTimeout = 5000;
config.Transitions = true;
config.NoSwap = ["204", "304", "4xx", "5xx"];
});
});
builder.Services.AddHtmxToolkit(options => options.UseHtmxV4());
```

The configured values remain available through dependency injection:
Expand Down Expand Up @@ -784,7 +767,17 @@ builder.Services.AddHtmxToolkit(options =>
```

HTMX 4.x removes `responseHandling`. To retain HTMX 2.x behavior that does not swap error
responses, configure `NoSwap` as shown in the HTMX 4.x example above.
responses, configure `NoSwap` explicitly:

```csharp
builder.Services.AddHtmxToolkit(options =>
{
options.UseHtmxV4(config =>
{
config.NoSwap = ["204", "304", "4xx", "5xx"];
});
});
```

## Toolkit Script

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ public IActionResult OnGetCustomHeader()
{
Response.Htmx(h => h
.TriggerEvent("customEvent", new { message = "#1 Fired from server!" })
.TriggerEvent("logEvent", new { message = $"Custom-Header = {Request.Headers["Custom-Header"]}" }));
.TriggerEvent("logEvent", new { message = $"Custom-Header = {Request.Headers["Custom-Header"]}" })
.TriggerEvent("customEvent", new { message = "#2 Fired from server!" })
.TriggerEvent("customEvent", new { message = "#3 Fired from server!" }));

return Content("<b>Custom headers sent!</b>")
.Htmx(h => h
.TriggerEvent("customEvent", new { message = "#2 Fired from server!" })
.TriggerEvent("customEvent", new { message = "#3 Fired from server!" }));
return Content("<b>Custom headers sent!</b>");
}
}
3 changes: 2 additions & 1 deletion samples/Ramstack.HtmxToolkit.Demo/Program.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Ramstack.HtmxToolkit;
using Ramstack.HtmxToolkit.Builder;
using Ramstack.HtmxToolkit.Configuration;
using Ramstack.HtmxToolkit.Hosting;

var builder = WebApplication.CreateBuilder(args);

Expand Down
34 changes: 0 additions & 34 deletions src/Ramstack.HtmxToolkit/ActionResultExtensions.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Specifies how binary data received over a WebSocket connection is represented.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

using Microsoft.AspNetCore.Html;

namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Represents configuration for a specific major version of HTMX.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Specifies the request mode used by HTMX.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Specifies how HTMX history restoration is handled.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Specifies the scrolling behavior for a boosted link during page transitions.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Specifies the HTMX major version targeted by generated markup.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Represents configuration options for services provided by HTMX Toolkit.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Ramstack.HtmxToolkit;
using Ramstack.HtmxToolkit.Serialization;

namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Represents the configuration for HTMX 1.x.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Text.Json;
using System.Text.Json.Serialization;

using Ramstack.HtmxToolkit.TagHelpers;
using Ramstack.HtmxToolkit.Serialization;

namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Represents the configuration for HTMX 2.x.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Text.Json;
using System.Text.Json.Serialization;

namespace Ramstack.HtmxToolkit;
using Ramstack.HtmxToolkit.Serialization;

namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Represents the configuration for HTMX 4.x.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Ramstack.HtmxToolkit;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Defines the HTTP methods that can be used in HTMX configuration.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Ramstack.HtmxToolkit.TagHelpers;
namespace Ramstack.HtmxToolkit.Configuration;

/// <summary>
/// Represents the response handling configuration for responses that match
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

namespace Ramstack.HtmxToolkit.Builder;
namespace Ramstack.HtmxToolkit.Hosting;

/// <summary>
/// Provides HTMX Toolkit endpoint mappings for an <see cref="IEndpointRouteBuilder" />.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Microsoft.Extensions.DependencyInjection;

namespace Ramstack.HtmxToolkit.Builder;
using Ramstack.HtmxToolkit.Configuration;

namespace Ramstack.HtmxToolkit.Hosting;

/// <summary>
/// Provides HTMX Toolkit service registration for an <see cref="IServiceCollection" />.
Expand Down
2 changes: 1 addition & 1 deletion src/Ramstack.HtmxToolkit/HtmlHelperExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Mvc.Rendering;

using Ramstack.HtmxToolkit.Builder;
using Ramstack.HtmxToolkit.Hosting;

namespace Ramstack.HtmxToolkit;

Expand Down
2 changes: 2 additions & 0 deletions src/Ramstack.HtmxToolkit/HtmxFieldValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Runtime.CompilerServices;
using System.Text.Json.Serialization;

using Ramstack.HtmxToolkit.Serialization;

namespace Ramstack.HtmxToolkit;

/// <summary>
Expand Down
2 changes: 2 additions & 0 deletions src/Ramstack.HtmxToolkit/HtmxLocationOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Text.Json.Serialization;

using Ramstack.HtmxToolkit.Serialization;

namespace Ramstack.HtmxToolkit;

/// <summary>
Expand Down
1 change: 1 addition & 0 deletions src/Ramstack.HtmxToolkit/HtmxResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Microsoft.AspNetCore.Http;

using Ramstack.HtmxToolkit.Internal;
using Ramstack.HtmxToolkit.Serialization;

namespace Ramstack.HtmxToolkit;

Expand Down
8 changes: 0 additions & 8 deletions src/Ramstack.HtmxToolkit/HtmxResponseAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,12 @@ public string Reselect
set => SetValue(HtmxResponseHeaderNames.Reselect, value);
}

/// <summary>
/// Gets or sets a value indicating whether to set HTTP status code <c>286</c> to stop polling.
/// </summary>
public bool StopPolling { get; set; }

/// <inheritdoc />
public void OnResultExecuting(ResultExecutingContext context)
{
if (context.HttpContext.Request.IsHtmxRequest())
{
var response = context.HttpContext.Response;
if (StopPolling)
response.StatusCode = HtmxResponse.StopPollingStatusCode;

var headers = response.Headers;
foreach (ref var kvp in CollectionsMarshal.AsSpan(_headers))
headers[kvp.Key] = kvp.Value;
Expand Down
Loading
Loading