Skip to content

Blazor Quick Start

Hermes provides first-class Blazor integration through the Hermes.Blazor package. This guide shows you how to build a Blazor desktop application.

Project Setup

Create a new Blazor project:

bash
dotnet new blazor -n MyBlazorApp --interactivity None
cd MyBlazorApp
dotnet add package Hermes.Blazor

Or use the Hermes template:

bash
dotnet new hermes-blazor -n MyBlazorApp

Update Program.cs

Replace your Program.cs with:

csharp
using Hermes;
using Hermes.Blazor;
using MyBlazorApp;

// Optional: Pre-warm WebView for faster startup (Windows)
HermesWindow.Prewarm();

var builder = HermesBlazorAppBuilder.CreateDefault(args);

builder.ConfigureWindow(options =>
{
    options.Title = "My Blazor App";
    options.Width = 1024;
    options.Height = 768;
    options.CenterOnScreen = true;
    options.DevToolsEnabled = true;
});

builder.RootComponents.Add<App>("#app");

var app = builder.Build();
app.Run();

Update App.razor

Ensure your App.razor has a root element with id app:

razor
<!DOCTYPE html>
<html>
<head>
    <title>My Blazor App</title>
    <link href="css/app.css" rel="stylesheet" />
</head>
<body>
    <div id="app">
        <Router AppAssembly="@typeof(App).Assembly">
            <Found Context="routeData">
                <RouteView RouteData="@routeData" />
            </Found>
            <NotFound>
                <h1>Page not found</h1>
            </NotFound>
        </Router>
    </div>
    <script src="_framework/blazor.web.js"></script>
</body>
</html>

Adding Menus

Access the main window through the app builder:

csharp
var app = builder.Build();

// Configure menus
app.MainWindow.MenuBar
    .AddMenu("File", file =>
    {
        file.AddItem("New", "file.new", item => item.WithAccelerator("Ctrl+N"))
            .AddSeparator()
            .AddItem("Exit", "file.exit", item => item.WithAccelerator("Alt+F4"));
    })
    .AddMenu("Edit", edit =>
    {
        edit.AddItem("Cut", "edit.cut", item => item.WithAccelerator("Ctrl+X"))
            .AddItem("Copy", "edit.copy", item => item.WithAccelerator("Ctrl+C"))
            .AddItem("Paste", "edit.paste", item => item.WithAccelerator("Ctrl+V"));
    });

app.MainWindow.MenuBar.ItemClicked += itemId =>
{
    if (itemId == "file.exit")
    {
        app.MainWindow.Close();
    }
};

app.Run();

Dependency Injection

Register services as you would in any Blazor app:

csharp
builder.Services.AddSingleton<IMyService, MyService>();
builder.Services.AddScoped<IScopedService, ScopedService>();

Access them in your components:

razor
@inject IMyService MyService

<h1>@MyService.GetGreeting()</h1>

Window Options

Configure the window through ConfigureWindow:

csharp
builder.ConfigureWindow(options =>
{
    // Basic settings
    options.Title = "My App";
    options.Width = 1024;
    options.Height = 768;

    // Positioning
    options.CenterOnScreen = true;
    // Or specific position:
    // options.X = 100;
    // options.Y = 100;

    // Size constraints
    options.MinWidth = 640;
    options.MinHeight = 480;

    // Behavior
    options.Resizable = true;
    options.DevToolsEnabled = true;
    options.ContextMenuEnabled = false;

    // Custom title bar (for frameless windows)
    options.CustomTitleBar = true;

    // Remember window position/size between launches
    options.WindowStateKey = "main-window";
});

macOS Dock Menu

On macOS, you can add items to the dock menu:

csharp
if (HermesApplication.DockMenu is { } dockMenu)
{
    dockMenu
        .AddItem("New Window", "dock.new")
        .AddSeparator()
        .AddSubmenu("Recent", "dock.recent", recent =>
        {
            recent.AddItem("File1.txt", "recent.1")
                  .AddItem("File2.txt", "recent.2");
        });

    dockMenu.ItemClicked += itemId =>
    {
        Console.WriteLine($"Dock menu clicked: {itemId}");
    };
}

Communicating with JavaScript

Send messages to JavaScript:

csharp
app.MainWindow.SendMessage("Hello from C#!");

Receive messages from JavaScript:

csharp
app.MainWindow.OnWebMessage(message =>
{
    Console.WriteLine($"Received: {message}");
});

In your HTML/JavaScript:

javascript
// Send to C#
window.chrome.webview.postMessage("Hello from JS!");

// Receive from C#
window.chrome.webview.addEventListener("message", (e) => {
    console.log("Received:", e.data);
});

Complete Example

csharp
using Hermes;
using Hermes.Blazor;
using Microsoft.Extensions.DependencyInjection;
using MyBlazorApp;

HermesWindow.Prewarm();

var builder = HermesBlazorAppBuilder.CreateDefault(args);

builder.ConfigureWindow(options =>
{
    options.Title = "My Blazor App";
    options.Width = 1024;
    options.Height = 768;
    options.CenterOnScreen = true;
    options.DevToolsEnabled = true;
    options.WindowStateKey = "main";
});

// Register services
builder.Services.AddSingleton<IAppState, AppState>();

// Add root component
builder.RootComponents.Add<App>("#app");

var app = builder.Build();

// Configure menus
app.MainWindow.MenuBar
    .AddMenu("File", file =>
    {
        file.AddItem("Exit", "file.exit", item => item.WithAccelerator("Ctrl+Q"));
    })
    .AddMenu("Help", help =>
    {
        help.AddItem("About", "help.about");
    });

app.MainWindow.MenuBar.ItemClicked += itemId =>
{
    if (itemId == "file.exit") app.MainWindow.Close();
};

app.Run();

Next Steps

Released under the Elastic License 2.0