Svelte Integration preview
The @hermes/svelte package provides Svelte stores that wrap the Hermes bridge, giving you a reactive, idiomatic way to call C# methods and listen for backend events from Svelte components.
Installation
npm install @hermes/bridge @hermes/sveltecreateInvokeStore
createInvokeStore creates a readable Svelte store that calls a C# method and exposes loading, data, and error state. It invokes the method immediately on creation (with an optional initial argument).
<script>
import { createInvokeStore } from '@hermes/svelte';
const runtime = createInvokeStore<string>('getRuntime');
</script>
{#if $runtime.loading}
<p>Loading...</p>
{:else if $runtime.error}
<p>Error: {$runtime.error.message}</p>
{:else}
<p>Running on {$runtime.data}</p>
{/if}With an Initial Argument
Pass a second argument to invoke the C# method with a parameter on creation:
<script>
import { createInvokeStore } from '@hermes/svelte';
const greeting = createInvokeStore<string>('greet', 'Alice');
</script>
<p>{$greeting.data}</p>Store Shape
interface InvokeStoreValue<T> {
data: T | null; // Last successful result
loading: boolean; // True while a call is in flight
error: Error | null; // Last error, or null
}createEventStore
createEventStore creates a readable store that updates whenever the C# backend sends an event. Provide a default value for the initial state.
<script>
import { createEventStore } from '@hermes/svelte';
const tick = createEventStore<number>('tick', 0);
</script>
<p>Seconds elapsed: {$tick}</p>The store value updates automatically each time the backend calls app.Bridge?.Send("tick", value).
hermesConnected
A readable boolean store that indicates whether the component is running inside a Hermes desktop window.
<script>
import { hermesConnected } from '@hermes/svelte';
</script>
{#if $hermesConnected}
<p>Running as a desktop app</p>
{:else}
<p>Running in a browser</p>
{/if}Using the Bridge Directly
For cases where stores don't fit, use the bridge directly:
<script>
import { onMount, onDestroy } from 'svelte';
import { bridge } from '@hermes/bridge';
let progress = 0;
let unsubscribe: (() => void) | undefined;
onMount(() => {
unsubscribe = bridge.on<{ percent: number }>('download-progress', (data) => {
progress = data.percent;
});
});
onDestroy(() => {
unsubscribe?.();
});
</script>
<progress value={progress} max={100} />Complete Example
Here's a full Svelte + Hermes.Web application.
Program.cs (C# host):
using Hermes;
using Hermes.Web;
HermesWindow.Prewarm();
var builder = HermesWebAppBuilder.Create(args);
builder.ConfigureWindow(opts =>
{
opts.Title = "Svelte Desktop App";
opts.Width = 800;
opts.Height = 600;
opts.DevToolsEnabled = true;
});
#if DEBUG
builder.UseDevServer("http://localhost:5174");
#else
builder.UseStaticFiles("frontend/dist");
builder.UseSpaFallback();
#endif
builder.UseInteropBridge(bridge =>
{
bridge.Register<string, string>("greet", name => $"Hello from C#, {name}!");
bridge.Register("getRuntime", () => $".NET {Environment.Version}");
bridge.Register("getPlatform", () => Environment.OSVersion.Platform.ToString());
});
var app = builder.Build();
app.Run();App.svelte (Svelte frontend):
<script lang="ts">
import { createInvokeStore, hermesConnected } from '@hermes/svelte';
import { bridge } from '@hermes/bridge';
const runtime = createInvokeStore<string>('getRuntime');
const platform = createInvokeStore<string>('getPlatform');
let name = '';
let greeting = '';
async function greet() {
greeting = await bridge.invoke<string>('greet', name);
}
</script>
<main>
<h1>Hermes + Svelte</h1>
{#if $runtime.loading}
<p>Loading...</p>
{:else}
<p>{$runtime.data} on {$platform.data}</p>
{/if}
<input bind:value={name} placeholder="Your name" />
<button on:click={greet}>Greet</button>
{#if greeting}
<p>{greeting}</p>
{/if}
</main>Next Steps
- JavaScript Bridge - Full bridge API reference
- Web Quick Start - Getting started with Hermes.Web
- React Integration - React hooks for Hermes
- Menus Guide - Adding native menu bars
