Hotwire.AspNetCore 0.0.1

dotnet add package Hotwire.AspNetCore --version 0.0.1
                    
NuGet\Install-Package Hotwire.AspNetCore -Version 0.0.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Hotwire.AspNetCore" Version="0.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Hotwire.AspNetCore" Version="0.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Hotwire.AspNetCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Hotwire.AspNetCore --version 0.0.1
                    
#r "nuget: Hotwire.AspNetCore, 0.0.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Hotwire.AspNetCore@0.0.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Hotwire.AspNetCore&version=0.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Hotwire.AspNetCore&version=0.0.1
                    
Install as a Cake Tool

Hotwire.AspNetCore

A Hotwire implementation library for ASP.NET Core.

Tests .NET

Overview

Hotwire is an approach for building fast, modern web applications while minimizing the use of JavaScript. This library makes it easy to use Hotwire in ASP.NET Core applications.

Features

✅ Turbo Drive

  • Fast page transitions: AJAXifies links and form submissions to prevent full page reloads
  • Progressive enhancement: Works even when JavaScript is disabled
  • Persistent elements: Elements that maintain state across page transitions (e.g., music players)
  • Tag Helper support: <turbo-drive-meta>, <turbo-permanent>, and more

✅ Turbo Frames

  • Partial page updates: Update only specific portions of the page
  • Lazy loading: Load content on demand
  • Tag Helper support: Easily define frames with <turbo-frame>

✅ Turbo Streams

  • Real-time updates: Dynamically update pages using WebSocket or SSE
  • 16 standard actions: append, prepend, replace, update, remove, before, after, append_all, prepend_all, replace_all, update_all, remove_all, before_all, after_all, morph, refresh
  • Custom actions: Define your own DOM manipulation logic (Rails parity achieved)
  • Tag Helper support: Easily generate Turbo Streams with <turbo-stream> and <turbo-stream-custom>
  • SignalR integration: Real-time broadcast functionality (see below)

✅ Stimulus

Full Stimulus support (separate package Stimulus.AspNetCore):

  • 5 Tag Helpers: Controller, Action, Target, Value, Class
  • 9 HTML extension methods: Programmatically generate Stimulus attributes
  • Lightweight JavaScript framework: Minimal JavaScript for HTML manipulation
  • 20 tests: All passing
  • Sample app: WireStimulus provides 5 controller examples

✅ SignalR Integration

Real-time Turbo Streams using SignalR:

  • TurboStreamsHub: SignalR Hub for managing WebSocket connections
  • ITurboStreamBroadcaster: Service for broadcasting views in real-time
  • Channel-based subscriptions: Broadcast only to specific channels
  • Automatic reconnection: Automatic retry on connection loss
  • turbo-signalr.js: Client-side JavaScript library
  • Sample app: WireSignal provides notification and chat demos

Installation

dotnet add package Hotwire.AspNetCore

Or, individual packages:

dotnet add package Turbo.AspNetCore
dotnet add package Stimulus.AspNetCore

Quick Start

Using Turbo Drive

  1. Add Tag Helpers to _ViewImports.cshtml:
@addTagHelper *, Turbo.AspNetCore
  1. Set meta tags in _Layout.cshtml:
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"]</title>
    
    @* Load Turbo.js *@
    <script type="module" src="https://cdn.jsdelivr.net/npm/@@hotwired/turbo@@latest/dist/turbo.es2017-esm.min.js"></script>
    
    @* Enable Turbo Drive *@
    <turbo-drive-meta enabled="true" transition="fade" />
</head>
<body>
    @RenderBody()
</body>
  1. Create persistent elements (optional):
<turbo-permanent id="music-player">
    <audio controls>
        <source src="/audio/music.mp3" type="audio/mpeg">
    </audio>
</turbo-permanent>

Using Turbo Frames

<turbo-frame id="messages">
    <h2>Messages</h2>
    <p>Latest messages will appear here</p>
    <a href="/messages/1">Read message</a>
</turbo-frame>

Using Turbo Streams

Controller:

using Turbo.AspNetCore;

public class MessagesController : Controller
{
    public IActionResult Create(MessageViewModel model)
    {
        // Validation...
        
        if (Request.IsTurboStreamRequest())
        {
            return TurboStream(model);
        }
        
        return RedirectToAction("Index");
    }
}

View (Create.cshtml):

<turbo-stream action="append" target="messages">
    <template>
        <div class="message">
            <p>@Model.Content</p>
        </div>
    </template>
</turbo-stream>

Using Turbo Custom Actions

JavaScript (Define custom action):

// wwwroot/js/custom-actions.js
Turbo.StreamActions.notify = function() {
  const message = this.getAttribute("message");
  const type = this.getAttribute("type") || "info";
  alert(`[${type}] ${message}`);
}

View (Tag Helper):

<turbo-stream-custom action="notify" message="Saved successfully!" type="success"></turbo-stream-custom>

Or HTML extension method:

@Html.TurboStreamCustom("notify", new { message = "Saved successfully!", type = "success" })

For details, see the Turbo Custom Actions Guide.

Using Stimulus

Add Tag Helpers to _ViewImports.cshtml:

@addTagHelper *, Stimulus.AspNetCore

View (Dropdown example):

<div stimulus-controller="dropdown" 
     stimulus-value-dropdown-open="false"
     stimulus-class-dropdown-active="show">
    
    <button stimulus-action="click->dropdown#toggle" 
            class="btn btn-primary">
        Open Dropdown
    </button>
    
    <div stimulus-target="dropdown.menu" 
         class="dropdown-menu">
        <a class="dropdown-item" href="#">Action</a>
        <a class="dropdown-item" href="#">Another action</a>
    </div>
</div>

JavaScript (Stimulus controller):

// wwwroot/js/controllers/dropdown_controller.js
import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static targets = ["menu"]
  static classes = ["active"]
  static values = { open: Boolean }

  toggle(event) {
    event.preventDefault()
    this.openValue = !this.openValue
  }

  openValueChanged() {
    if (this.openValue) {
      this.menuTarget.classList.add(this.activeClass)
    } else {
      this.menuTarget.classList.remove(this.activeClass)
    }
  }
}

For details, see the Stimulus.AspNetCore README.

Real-time Turbo Streams with SignalR

Setup in Program.cs:

using Turbo.AspNetCore;

var builder = WebApplication.CreateBuilder(args);

// Add SignalR
builder.Services.AddSignalR();

// Add Turbo Stream Broadcaster
builder.Services.AddTurboStreamBroadcaster();

var app = builder.Build();

// Map SignalR Hub
app.MapHub<TurboStreamsHub>("/hubs/turbo-streams");

app.Run();

Broadcasting in controller:

using Turbo.AspNetCore;

public class NotificationsController : Controller
{
    private readonly ITurboStreamBroadcaster _broadcaster;

    public NotificationsController(ITurboStreamBroadcaster broadcaster)
    {
        _broadcaster = broadcaster;
    }

    [HttpPost]
    public async Task<IActionResult> Create(Notification notification)
    {
        // Broadcast to all subscribers
        await _broadcaster.BroadcastViewAsync(
            "notifications",     // Channel name
            "_Notification",     // Partial view
            notification         // Model
        );

        return this.TurboStream("_Notification", notification);
    }
}

Client-side connection (JavaScript):

// After loading turbo-signalr.js
const turboSignalR = new TurboSignalR();
await turboSignalR.start();
await turboSignalR.subscribe('notifications');

// Event listener
document.addEventListener('turbo-signalr:streamReceived', (event) => {
    console.log('Real-time update received!');
});

For details, see the SignalR Integration Guide and WireSignal Sample.

Sample Applications

This repository contains 5 sample applications demonstrating each Hotwire feature.

1. WireDrive - Turbo Drive Demo

Demo of fast page transitions and persistent elements.

cd examples/WireDrive
dotnet run

Key features:

  • Fast page transitions (no reload required)
  • Persistent elements (e.g., music player)
  • Progressive enhancement

For details, see the WireDrive README.

2. WireFrame - Turbo Frames Demo

Demo of partial page updates.

cd examples/WireFrame
dotnet run

Key features:

  • Partial page updates
  • Lazy loading
  • Nested frames

3. WireStream - Turbo Streams Demo

Demo of real-time updates and custom actions.

cd examples/WireStream
dotnet run
# Navigate to http://localhost:5000/CustomActions

Key features:

  • 16 standard Turbo Stream actions
  • 5 custom actions (set_title, notify, slide_in, highlight, console_log)
  • DOM manipulation demo

4. WireStimulus - Stimulus Demo

Comprehensive Stimulus controller demo.

cd examples/WireStimulus
dotnet run

Key features:

  • 5 practical Stimulus controllers
    • Dropdown: Toggle + auto-close
    • Clipboard: Copy to clipboard + feedback
    • Counter: Increment/decrement
    • Form: Real-time validation
    • Slideshow: Image carousel + autoplay

For details, see the WireStimulus README.

5. WireSignal - SignalR Integration Demo

Demo of real-time Turbo Streams using SignalR.

cd examples/WireSignal
dotnet run

Key features:

  • Real-time notification system
  • Live chat
  • WebSocket connection via SignalR
  • Channel-based subscriptions

For details, see the WireSignal README.

Documentation

Guides

Implementation Documents

Sample Applications

Requirements

  • .NET 8.0 / 9.0 / 10.0 (library)
  • .NET 10.0+ (sample apps)

Packages

This repository contains 3 packages:

1. Hotwire.AspNetCore

Integrated package with all features (Turbo + Stimulus)

dotnet add package Hotwire.AspNetCore

2. Turbo.AspNetCore

Implementation of Turbo Drive/Frames/Streams

dotnet add package Turbo.AspNetCore

3. Stimulus.AspNetCore

Stimulus Tag Helpers and HTML extensions

dotnet add package Stimulus.AspNetCore

Build

dotnet build

Tests

dotnet test

Test results: All 56 tests (36 Turbo + 20 Stimulus) passing ✅

Project Structure

Hotwire.AspNetCore/
├── src/
│   ├── Hotwire.AspNetCore/      # Integrated package
│   ├── Turbo.AspNetCore/         # Turbo implementation
│   │   ├── TagHelpers/           # Turbo Tag Helpers (6)
│   │   ├── Hubs/                 # SignalR Hub
│   │   └── wwwroot/js/           # turbo-signalr.js
│   └── Stimulus.AspNetCore/      # Stimulus implementation
│       └── TagHelpers/           # Stimulus Tag Helpers (5)
├── test/
│   ├── Turbo.AspNetCore.Test/    # Turbo tests (36)
│   └── Stimulus.AspNetCore.Test/ # Stimulus tests (20)
├── examples/
│   ├── WireDrive/                # Turbo Drive demo
│   ├── WireFrame/                # Turbo Frames demo
│   ├── WireStream/               # Turbo Streams demo
│   ├── WireStimulus/             # Stimulus demo
│   └── WireSignal/               # SignalR demo
└── docs/                         # Documentation

Feature Comparison

Feature Rails (turbo-rails) Hotwire.AspNetCore Status
Turbo Drive Fully implemented
Turbo Frames Fully implemented
Turbo Streams (standard actions) ✅ 16 actions ✅ 16 actions Rails parity
Turbo Streams (custom actions) ✅ turbo_stream.action() ✅ TurboStreamCustom Rails parity
Turbo 8 (morph/refresh) Fully implemented
Real-time streams ✅ ActionCable ✅ SignalR Rails parity
Stimulus ✅ stimulus-rails ✅ Stimulus.AspNetCore Rails parity
Tag Helpers ✅ Rails Helpers ✅ ASP.NET Tag Helpers ASP.NET optimized

License

MIT License

References

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.1 115 3/5/2026