DEV Community

Cover image for Blazor Native: HTML and CSS Without a Browser
Florian Rappl
Florian Rappl

Posted on AI-assisted

Blazor Native: HTML and CSS Without a Browser

Almost 14 years ago, I had an idea: what if you could build a cross-platform desktop UI with HTML and CSS, but write all of its behavior in C#?

At the time, the missing piece was obvious. HTML and CSS are not just convenient ways to describe a UI; they come with a whole ecosystem of parsing, layout, rendering, browser APIs, and edge cases. "Let's just support the useful parts" sounds simple right up until you try to define what useful means.

So the idea stayed around, somewhere between "maybe one day" and "that would be a fun project."

Then AngleSharp started growing in a direction that made me ask a slightly uncomfortable question: don't we already have the pieces? And isn't Blazor already the C# component model for building UIs?

It turns out the answer is: mostly, yes. The result is BlazorSharp, a proof of concept that renders Blazor components into an AngleSharp DOM and paints that DOM in an Avalonia desktop application.

No Chromium. No embedded webview. No JavaScript renderer bridge. The components, DOM updates, and rendering pipeline all run in managed .NET code.

What Does "Native" Mean Here?

Let's get the terminology out of the way first. This isn't a new native widget toolkit, and it isn't a browser engine with complete web-platform compatibility. By "native" I mean that the UI is hosted by a cross-platform desktop application, while HTML, CSS, component logic, and DOM operations run in the application's .NET process.

The UI is still described with Razor components and CSS. Avalonia provides the desktop window and input surface. AngleSharp provides the document and browser-like rendering engine. Blazor provides the component model and the render tree.

The interesting bit is connecting those parts without putting a conventional browser in the middle.

The Rendering Pipeline

The sample has three main pieces:

  1. Blazor components describe the UI and respond to events.
  2. A custom Blazor renderer receives Blazor render batches and applies their edits to an AngleSharp DOM.
  3. AngleSharp.Browser lays out and paints that DOM into an Avalonia control.

In a diagram:

Architecture layers

The reverse direction matters just as much: input events from the control are converted into DOM events, then routed back to the component handlers. Clicking a button or changing a checkbox is still ordinary Blazor component interaction.

The implementation's central piece is a custom renderer. Blazor hands it a render batch; the batch processor translates the changes into DOM operations. AngleSharp then evaluates the document's styles, lays it out, and paints the result. The demo's image files and CSS are embedded with the Razor component assembly and resolved locally - there is no web server serving the UI.

That's the basic trick: use the same component model, but replace the usual browser-facing renderer with one that talks directly to a managed DOM.

What Can the Demo Do?

The sample isn't just a static page. It includes a counter, navigation, a picture gallery with a timer-driven slideshow, a ToDo list, and settings that update the theme and accent. The components use familiar Razor event handlers such as @onclick and @oninput; the state changes and rendering stay in C#.

The home screen contains already a counter to illustrate that click events properly propagate, are retrieved in Blazor, and layout changes from Blazor are also finding their way back:

Home Screen

For another example, the ToDo page filters and sorts its items directly in the component:

@foreach (var todo in Visible)
{
    <li @key="todo" class="todo @(todo.IsDone ? "done" : null)">
        <label>
            <input type="checkbox" @bind="todo.IsDone" />
            <span>@todo.Title</span>
        </label>
    </li>
}
Enter fullscreen mode Exit fullscreen mode

The syntax is familiar because it is Blazor. The unusual part is what receives the resulting render batch: not a browser runtime, but the custom renderer and AngleSharp document hosted by the desktop app.

How Is This Different From Blazor Hybrid?

Blazor Hybrid is a great fit when you want Blazor components inside a native app and need the compatibility of a real webview. That webview has its own browser engine, resource management, and rendering process. Blazor communicates with it through a JavaScript interop layer.

This proof of concept takes another route. The DOM lives in AngleSharp, in the same application process as the components. The renderer applies changes to that DOM directly, so it doesn't need a webview or a JavaScript bridge to perform the rendering work.

That direct connection is appealing, but it doesn't make the webview obsolete. A real browser has years of work behind it: CSS behavior, accessibility, input methods, developer tools, and compatibility with the many assumptions made by web component libraries. BlazorSharp doesn't inherit all of that just because it accepts HTML and CSS.

The Part Where the Caveats Arrive

This is a proof of concept, not a browser replacement or a general-purpose hosting package. There are several important limits:

  • CSS coverage is incomplete. Complex grid cases, transitions, animations, sticky positioning, fonts, and form-control sizing may differ from a mainstream browser. Libraries such as MudBlazor or Fluent UI can rely on browser behavior the renderer doesn't yet implement.
  • DOM updates can be expensive. Mutations can trigger layout, and layout and painting currently share the event loop with component work. Large lists or tables can therefore affect frame rate and input responsiveness.
  • There is no accessibility tree. The current output is painted as a bitmap, so screen readers and operating-system accessibility APIs cannot inspect the UI.
  • Text input is not browser-equivalent. IME support, spell checking, rich text editing, selection, and context menus are limited. Text inputs also have event behavior differences that affect default binding and form validation.
  • JavaScript interop is deliberately limited. A custom IJSRuntime provides a few built-in operations used by Blazor, such as focus and page title handling. Other JavaScript calls need a .NET implementation; otherwise they fail. Many Blazor libraries depend on JavaScript for charts, editors, maps, file input, clipboard, or measurements.
  • Some Blazor features are missing. For example, Virtualize, scoped CSS, external Razor class library static assets, prerendering, and enhanced navigation aren't supported by this sample.
  • The renderer depends on framework internals. Applying Blazor render batches means working with APIs that are marked as internal-use territory. A future .NET release could require changes here.

Those limitations don't make the experiment less interesting; they define where it might be useful today. A small, self-contained UI with controlled CSS and no dependency on browser-only libraries is a much better fit than a large existing web application.

Trying It Out

The repository contains a .NET 10 solution. With the .NET 10 SDK installed, clone the project and run the Avalonia app:

dotnet run --project BlazorExample.App
Enter fullscreen mode Exit fullscreen mode

The demo is a good place to explore the rendering path: try the counter, navigate between pages, start and stop the gallery slideshow, or change settings. The source is split between the Avalonia host, the Razor components, and the renderer/DOM integration in BlazorExample.Core.

If you're interested in the AngleSharp side of the story, I wrote more about the project's beginnings in My OSS Projects: AngleSharp. BlazorSharp is one of those cases where years of work on a foundational library suddenly make a much older idea feel practical.

Was It Worth Waiting 14 Years?

Probably not if the only goal was to have a desktop UI toolkit. There are already excellent options for that.

But the question was always more interesting to me than the answer: how much of the web's UI model can we bring into a managed, cross-platform application without bringing a browser along with it?

With Blazor, AngleSharp, and Avalonia, the pieces fit together well enough to make that question runnable. There's plenty left to improve - especially around rendering performance and browser compatibility - but the core loop works: write a component, update its state in C#, update the DOM, and paint the result in a desktop window.

I'm not sure it was worth the wait. I do like that we can finally try it.

Top comments (0)