Skip to content

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

bash
npm install @hermes/bridge @hermes/svelte

createInvokeStore

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).

svelte
<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:

svelte
<script>
  import { createInvokeStore } from '@hermes/svelte';

  const greeting = createInvokeStore<string>('greet', 'Alice');
</script>

<p>{$greeting.data}</p>

Store Shape

typescript
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.

svelte
<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.

svelte
<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:

svelte
<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):

csharp
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):

svelte
<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