Skip to main content
Avalonia can run in web browsers using WebAssembly (WASM), enabling you to deploy your desktop and mobile applications directly to the web.

Browser Support

Modern Browsers

Chrome 90+, Firefox 88+, Edge 90+, Safari 15+

WebAssembly Required

All browsers must support WebAssembly and WebGL

Getting Started

Project Setup

Create a browser-based Avalonia application:
using System.Runtime.Versioning;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Browser;

[assembly: SupportedOSPlatform("browser")]

internal partial class Program
{
    private static async Task Main(string[] args)
    {
        await BuildAvaloniaApp()
            .StartBrowserAppAsync("out");
    }

    public static AppBuilder BuildAvaloniaApp()
        => AppBuilder.Configure<App>()
            .UseBrowser();
}
Source: src/Browser/Avalonia.Browser/BrowserAppBuilder.cs:66

Browser Platform Options

Configure browser-specific options:
using Avalonia.Browser;

await BuildAvaloniaApp()
    .With(new BrowserPlatformOptions
    {
        // Rendering mode with fallbacks
        RenderingMode = new[]
        {
            BrowserRenderingMode.WebGL2,      // Preferred
            BrowserRenderingMode.WebGL1,      // Fallback
            BrowserRenderingMode.Software2D   // Last resort
        },
        
        // Asset path resolution
        FrameworkAssetPathResolver = fileName => $"./{fileName}",
        
        // Service worker for file dialogs
        RegisterAvaloniaServiceWorker = false,
        
        // Force file dialog polyfill
        PreferFileDialogPolyfill = false,
        
        // Use managed thread dispatcher (for threading support)
        PreferManagedThreadDispatcher = true
    })
    .StartBrowserAppAsync("out");
Source: src/Browser/Avalonia.Browser/BrowserAppBuilder.cs:19

Rendering Modes

WebGL Rendering

Hardware-accelerated rendering in the browser:
// WebGL 2.0 (recommended)
// - Best performance
// - Modern browsers only
// - OpenGL ES 3.0 equivalent
BrowserRenderingMode.WebGL2
Source: src/Browser/Avalonia.Browser/BrowserAppBuilder.cs:12

Automatic Fallback

Avalonia automatically tries rendering modes in order:
RenderingMode = new[]
{
    BrowserRenderingMode.WebGL2,      // Try this first
    BrowserRenderingMode.WebGL1,      // Fall back to this
    BrowserRenderingMode.Software2D   // Final fallback
}

HTML Integration

Single View Mode

Embed Avalonia in a specific HTML element:
<!DOCTYPE html>
<html>
<head>
    <title>My Avalonia App</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
        }
        #avalonia-container {
            width: 100%;
            height: 100%;
        }
    </style>
</head>
<body>
    <div id="avalonia-container"></div>
    <script src="main.js"></script>
</body>
</html>
// Attach to the 'avalonia-container' div
await BuildAvaloniaApp()
    .StartBrowserAppAsync("avalonia-container");
Source: src/Browser/Avalonia.Browser/BrowserAppBuilder.cs:74

Multiple Views

Create multiple Avalonia views on one page:
using Avalonia.Browser;

// Setup without creating views
await BuildAvaloniaApp()
    .SetupBrowserAppAsync();

// Create views dynamically
var view1 = new AvaloniaView("container1")
{
    Content = new MyControl1()
};

var view2 = new AvaloniaView("container2")
{
    Content = new MyControl2()
};
Source: src/Browser/Avalonia.Browser/BrowserAppBuilder.cs:130

Browser Features

Supported Features

  • Touch Input: Full touch and pointer support
  • Keyboard: Standard keyboard input with IME
  • Mouse: Mouse events and cursor management
  • Clipboard: Browser clipboard API integration
  • File Dialogs: Native or polyfilled file pickers
  • Drag & Drop: Drag and drop support
  • Screen Info: Browser viewport information
  • Dark Mode: System theme detection
  • Storage: Local storage integration
Source: src/Browser/Avalonia.Browser/BrowserPlatformSettings.cs:7

Limited Features

  • No Native Menus: Browser doesn’t support native menus
  • No System Tray: Not applicable in browsers
  • No Window Management: Runs in a div, not a window
  • Limited File System: Sandboxed file access only

File System Access

File Picker

Use the browser file picker:
using Avalonia.Platform.Storage;

public async Task OpenFileAsync()
{
    var topLevel = TopLevel.GetTopLevel(this);
    var files = await topLevel.StorageProvider.OpenFilePickerAsync(
        new FilePickerOpenOptions
        {
            Title = "Select a file",
            AllowMultiple = false,
            FileTypeFilter = new[]
            {
                new FilePickerFileType("Images")
                {
                    Patterns = new[] { "*.png", "*.jpg", "*.jpeg" },
                    MimeTypes = new[] { "image/png", "image/jpeg" }
                }
            }
        });
    
    if (files.Count > 0)
    {
        await using var stream = await files[0].OpenReadAsync();
        // Process file
    }
}
Source: src/Browser/Avalonia.Browser/Storage/BrowserStorageProvider.cs:8

File Picker Polyfill

For browsers without native file system API:
.With(new BrowserPlatformOptions
{
    // Force polyfill usage
    PreferFileDialogPolyfill = true,
    
    // Enable service worker for downloads
    RegisterAvaloniaServiceWorker = true,
    AvaloniaServiceWorkerScope = "/"
})

JavaScript Interop

Calling JavaScript from C#

Use JSImport attributes:
using System.Runtime.InteropServices.JavaScript;

public partial class JavaScriptHelper
{
    [JSImport("alert", "window")]
    public static partial void Alert(string message);
    
    [JSImport("console.log", "window")]
    public static partial void ConsoleLog(string message);
    
    public static void ShowMessage(string message)
    {
        Alert(message);
        ConsoleLog($"Message shown: {message}");
    }
}

Calling C# from JavaScript

Expose C# methods to JavaScript:
using System.Runtime.InteropServices.JavaScript;

public partial class CSharpHelper
{
    [JSExport]
    public static string GetData()
    {
        return "Data from C#";
    }
    
    [JSExport]
    public static int Calculate(int a, int b)
    {
        return a + b;
    }
}
Then in JavaScript:
const data = Module.CSharpHelper.GetData();
const result = Module.CSharpHelper.Calculate(5, 3);

Browser Application Lifetime

Browser apps use a single view lifetime:
using Avalonia.Browser;
using Avalonia.Controls.ApplicationLifetimes;

public override void OnFrameworkInitializationCompleted()
{
    if (ApplicationLifetime is BrowserSingleViewLifetime lifetime)
    {
        // Access the main view
        lifetime.View = new AvaloniaView("out")
        {
            Content = new MainView()
        };
    }

    base.OnFrameworkInitializationCompleted();
}
Source: src/Browser/Avalonia.Browser/BrowserSingleViewLifetime.cs:11

Responsive Design

Adapt to different screen sizes:
using Avalonia.Controls;

public class ResponsiveView : UserControl
{
    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
    {
        base.OnAttachedToVisualTree(e);
        
        // Listen to browser window resizing
        var topLevel = TopLevel.GetTopLevel(this);
        if (topLevel != null)
        {
            topLevel.PropertyChanged += (s, args) =>
            {
                if (args.Property == TopLevel.ClientSizeProperty)
                {
                    UpdateLayout(topLevel.ClientSize);
                }
            };
            
            UpdateLayout(topLevel.ClientSize);
        }
    }
    
    private void UpdateLayout(Size clientSize)
    {
        // Adjust layout based on size
        if (clientSize.Width < 600)
        {
            // Mobile layout
        }
        else if (clientSize.Width < 1200)
        {
            // Tablet layout
        }
        else
        {
            // Desktop layout
        }
    }
}

Input Handling

Touch and Mouse

Browser supports both touch and mouse:
protected override void OnPointerPressed(PointerPressedEventArgs e)
{
    base.OnPointerPressed(e);
    
    var props = e.GetCurrentPoint(this).Properties;
    
    if (props.PointerUpdateKind == PointerUpdateKind.LeftButtonPressed)
    {
        // Handle click/tap
        var position = e.GetPosition(this);
    }
}
Source: src/Browser/Avalonia.Browser/BrowserInputHandler.cs:18

Keyboard Input

protected override void OnKeyDown(KeyEventArgs e)
{
    base.OnKeyDown(e);
    
    if (e.Key == Key.Enter)
    {
        // Handle Enter key
        e.Handled = true;
    }
}

Clipboard Access

Access browser clipboard:
using Avalonia.Input.Platform;

public async Task CopyToClipboardAsync(string text)
{
    var clipboard = TopLevel.GetTopLevel(this)?.Clipboard;
    if (clipboard != null)
    {
        await clipboard.SetTextAsync(text);
    }
}

public async Task<string?> PasteFromClipboardAsync()
{
    var clipboard = TopLevel.GetTopLevel(this)?.Clipboard;
    if (clipboard != null)
    {
        return await clipboard.GetTextAsync();
    }
    return null;
}
Source: src/Browser/Avalonia.Browser/BrowserClipboardDataTransfer.cs:11

Performance Optimization

WebGL Optimization

// Prefer WebGL for better performance
.With(new BrowserPlatformOptions
{
    RenderingMode = new[]
    {
        BrowserRenderingMode.WebGL2,
        BrowserRenderingMode.WebGL1
        // Avoid Software2D if possible
    }
})

Loading Performance

  • Trim Unused Code: Enable IL trimming
  • Use AOT Compilation: Faster startup
  • Minimize Assembly Size: Remove unused dependencies
  • Lazy Load Resources: Load images on demand
  • Compress Assets: Use compressed image formats

Runtime Performance

  • Virtualize Lists: Use virtualizing panels
  • Minimize Redraws: Avoid unnecessary invalidations
  • Use Hardware Acceleration: Prefer WebGL
  • Optimize Images: Use appropriate resolutions
  • Cache Data: Store frequently used data

Threading Support

Enable threading in WebAssembly:
.With(new BrowserPlatformOptions
{
    // Enable managed thread dispatcher
    PreferManagedThreadDispatcher = true
})
Note: Requires SharedArrayBuffer support in the browser. Source: src/Browser/Avalonia.Browser/BrowserAppBuilder.cs:62

Deployment

Build for Production

dotnet publish -c Release

Hosting Requirements

  • HTTPS: Required for many browser APIs
  • MIME Types: Properly configure .wasm file types
  • CORS: Configure Cross-Origin Resource Sharing if needed
  • Compression: Enable gzip/brotli compression

Web Server Configuration

IIS (web.config)

<configuration>
  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".wasm" mimeType="application/wasm" />
    </staticContent>
    <httpCompression>
      <staticTypes>
        <add mimeType="application/wasm" enabled="true" />
      </staticTypes>
    </httpCompression>
  </system.webServer>
</configuration>

nginx

location / {
    types {
        application/wasm wasm;
    }
    
    gzip on;
    gzip_types application/wasm;
}

Browser Compatibility

Feature Detection

using Avalonia.Platform;

var runtimeInfo = AvaloniaLocator.Current
    .GetService<IRuntimePlatform>()?.
    GetRuntimeInfo();

if (runtimeInfo != null)
{
    Console.WriteLine($"Browser: {runtimeInfo.OperatingSystem}");
    
    // Check for specific capabilities
    var settings = AvaloniaLocator.Current
        .GetService<IPlatformSettings>();
}
Source: src/Browser/Avalonia.Browser/BrowserRuntimePlatform.cs:13

Limitations

Browser Sandbox

  • Limited file system access
  • No native process launching
  • No direct hardware access
  • Network requests subject to CORS
  • Storage limited to browser APIs

Performance

  • Slower than native desktop
  • Depends on browser JavaScript engine
  • Initial load time for WASM
  • Memory limitations

Workarounds

  • Use web APIs for file access
  • Implement server-side operations
  • Optimize asset loading
  • Use progressive loading

Next Steps

Desktop Platforms

Build native desktop applications

Platform-Specific APIs

Access platform-specific features

Build docs developers (and LLMs) love