One component, Node or C# on the server
Render an HTML Next component with request data in Node or C#. The browser then hydrates the rendered elements and continues the component's state and computed dependencies.
The two runnable examples use identical HTML, JavaScript module, browser entry and Vite configuration. Both initially render Count: 12 and Double: 24. Clicking the hydrated button changes them to Count: 13 and Double: 26.
Run the Node application
Requires Node 24. Get the examples:
git clone --depth 1 https://github.com/nextwebwg/html-next.git
cd html-next/packages/html-next/examples/full-stack-node
npm install
npm run build
npm startOpen http://localhost:5001/?start=12 and click the button. Disable JavaScript and reload to inspect the initial HTML independently.
The server reads the component with parseComponent and calls the Node renderer:
import { parseComponent } from "@nextwebwg/html-next";
import { renderComponents } from "@nextwebwg/html-next/server";
const definition = parseComponent(source, componentURL);
const { html } = await renderComponents("<x-counter></x-counter>", {
definitions: [definition],
props: { "x-counter": { start: 12 } },
});Serve html in the application document and load the built browser entry. The complete Node example includes its HTTP server and static asset delivery. The Node rendering reference covers stylesheets, preparation, cancellation and renderer lifetime.
Run the C# application
Requires .NET 10 and Node 24. In another terminal, use the C# directory from the same checkout:
cd html-next/packages/html-next-dotnet/examples/counter
dotnet restore
npm install
npm run build
dotnet run --urls http://localhost:5000Open http://localhost:5000/?start=12. C# produces the same count and computed value before JavaScript loads. The browser module then continues the same interaction.
The application installs NextWebWG.HtmlNext 1.0.0-alpha.2. It loads the built manifest and compiles the component once at startup:
var assets = HtmlNextServerAssets.FromManifest(
await File.ReadAllTextAsync("wwwroot/assets/html-next.manifest.json"));
var graph = HtmlNextCompiler.CompileResource(
await File.ReadAllTextAsync("counter.html"), "counter.html", assets: assets);
var counter = graph.Template("x-counter");
// Per request, using application-supplied data:
var html = counter.Render(new { start = 12 }, cancellationToken,
options: new HtmlNextRenderOptions { Interactive = true });The complete ASP.NET example supplies Program.cs, the project file and static asset setup. C# and .NET starts with an installation and a minimal server response; the API reference describes source graphs, validation and prepared data.
Build and hydrate the browser side
Both examples use the same entry and Vite setup, with SDK packages 1.0.0-alpha.94:
import { hydrate } from "virtual:html-next/hydrate";
hydrate();import { defineConfig } from "vite";
import htmlNext from "@nextwebwg/html-next-unplugin/vite";
export default defineConfig({
plugins: [htmlNext({ entries: ["counter.html"], hydrate: true })],
build: {
outDir: "wwwroot/assets",
emptyOutDir: true,
lib: { entry: "main.js", formats: ["es"], fileName: () => "app.js" },
},
});Run the frontend build before starting either server. Deploy the matching component source and built assets together. The C# renderer checks the source fingerprint against the manifest; source edits require a new build. Include emitted stylesheets for components that use them.
The server owns request data and initial rendering. The generated browser factories adopt the initial elements, restore their state and connect the module. Browser modules own later events, refreshes and subscriptions. C# does not need a JavaScript engine to evaluate this component's declared initial dataflow.
The example uses the supported module connect hook for browser behavior. The current C# compiler's supported input excludes declarative <handler> bodies and on: attributes; see its implementation status.
Why the graph travels between hosts
The component declares its prop, state seed, computed expression and text bindings in HTML. Those dependencies belong to the component language. A host can evaluate them using its own implementation, while the browser evaluates later changes from the same definition. The event module writes count; it does not repeat the computed formula or update either text node manually.
This is a benefit of a declared dependency language across implementation hosts. JavaScript module code keeps its own language and browser capabilities. Applications still supply host-specific request handling and data services. The reactivity proposal defines the dependency and availability semantics.
Template rendering and hydration
Fluid, the .NET Liquid engine, renders templates from data. Applications can add client behavior around that output. HTML Next supplies a matching generated component runtime and hydration records as part of its rendering workflow.
Liquid is also used outside server-only environments: LiquidJS supports browser rendering. Other component frameworks support server rendering and hydration too, such as React's hydrateRoot. The examples here demonstrate HTML Next's shared component dataflow across Node, C# and the browser.
See performance and size for measured C# template rendering and JavaScript browser-update comparisons. Those are separate workloads and execution phases.