Heimdall Docs

Actions

Actions are server-side methods that return HTML. They are triggered by Heimdall attributes and are used to update parts of the UI without reloading the page.

If pages handle routes, actions handle interactions.

1. What an Action Is

An action is a static method marked with [ContentInvocation]. It is discovered automatically and can be invoked by name from the browser.

[ContentInvocation]
public static IHtmlContent Increment()
{
    return Html.Div(d =>
    {
        d.Text("Updated from the server.");
    });
}

2. How Actions Are Triggered

Actions are triggered from the browser using Heimdall attributes.

<button
  heimdall-click="Example.Increment"
  heimdall-target="#result"
  heimdall-swap="inner">
  Click Me
</button>

3. Naming and Discovery

If no name is provided, Heimdall uses TypeName.MethodName. You can also explicitly name an action.

[ContentInvocation("counter.increment")]
public static IHtmlContent Increment()
{
    return Html.Div(d => d.Text("Count updated."));
}

4. Return Types

Actions must return HTML. Heimdall supports synchronous and asynchronous return types.

public static IHtmlContent Sync()

public static Task<IHtmlContent> Async()

public static ValueTask<IHtmlContent> ValueTask()

5. Parameter Binding

Heimdall automatically binds parameters from the request. This includes payloads, framework types, and services.

Payload DTO

public class IncrementRequest
{
    public int Count { get; set; }
}

[ContentInvocation]
public static IHtmlContent Increment(IncrementRequest req)
{
    return Html.Div(d =>
    {
        d.Text($"Count: {req.Count + 1}");
    });
}

Supported Parameters

Payload DTO (exactly one)
HttpContext
CancellationToken
ClaimsPrincipal
Services from DI

6. Service Injection

Actions can receive services directly from dependency injection.

[ContentInvocation]
public static IHtmlContent GetTime(ISystemClock clock)
{
    return Html.Div(d =>
    {
        d.Text($"Time: {clock.UtcNow}");
    });
}

7. The One Payload Rule

Each action can accept exactly one payload DTO. Additional parameters must come from the framework or dependency injection.

// ✅ Valid
Increment(MyDto dto, HttpContext ctx)

// ❌ Invalid
Increment(MyDto dto1, MyOtherDto dto2)

8. Pages vs Actions

This distinction is fundamental to how Heimdall works.

Next Steps

Once you understand actions, the next step is understanding how their responses are applied to the DOM.