Getting StartedQuick Start

Getting started

Quick Start

Go from an empty folder to a C# app that renders on the server, hydrates in the browser and reloads as you edit. Four commands and one new file.

Already have .NET? Here is the whole thing:

$ dotnet new install Natrix.Templates$ dotnet new natrix -o MyApp$ cd MyApp$ dotnet watch --project MyApp

Prerequisites

You need the .NET SDK, and nothing from the JavaScript world: no Node.js, no npm and no Tailwind CLI. Tailwind runs inside the C# compiler.

.NET SDK 9 or 10

Natrix targets both. The template defaults to .NET 10.

dotnet --version

A trusted HTTPS certificate

The app serves on https://localhost. Trust the ASP.NET Core development certificate once per machine.

dotnet dev-certs https --trust

wasm-tools (optional)

Not needed to develop. Install it when you publish with AOT compilation (RunAOTCompilation).

dotnet workload install wasm-tools

Don't have the SDK yet? Download .NET for Windows, macOS or Linux.

Create your app

  1. Install the template

    Natrix ships its project template as a NuGet package. Install it once; it stays available to dotnet new from then on.

    $ dotnet new install Natrix.Templates

    To get a newer template later, run dotnet new update.

  2. Create a project

    This creates a MyApp folder with two projects in it: a server that renders HTML and a WebAssembly client that takes over in the browser. Pick any name; it becomes the namespace too.

    $ dotnet new natrix -o MyApp

    Targeting .NET 9?

    Add -F net9.0 to the command. The template defaults to net10.0.

  3. Run it

    dotnet watch builds both projects, starts the server and opens your browser. The first build restores packages and compiles the client, so give it a minute.

    $ cd MyApp$ dotnet watch --project MyApp
    https://localhost:5100
    MyAppHomeAbout

    Build with Natrix

    This project was generated with the natrix template and includes server-side rendering, hydration, routing, and Tailwind CSS.

    Click About in the header: the page changes without a reload. The first view came from the server as plain HTML; everything after it runs in .NET in your browser.

    Prefer a plain run?

    dotnet run --project MyApp starts the same app without watching for changes. The template also includes VS Code launch and build settings.

  4. Add a page

    A page is a component: a class whose Setup method runs once and returns the elements to show. Add a counter page to the client project.

    MyApp.Client/Components/CounterPage.cs
    using Natrix.Core.Components;
    using Natrix.Dom.Components;
    using Natrix.Signals;
    
    namespace MyApp.Client.Components;
    
    public class CounterPage : BaseComponent<NoProps, NoEvents, NoSlots, NoExpose>
    {
        protected override IComponent[] Setup(out NoExpose exposed)
        {
            exposed = default;
    
            // Setup runs once. After that, only what reads `count` updates.
            var count = new Signal<int>(0);
    
            return
            [
                new Section
                {
                    Props = new SectionProps
                    {
                        Class = "max-w-3xl mx-auto px-4 sm:px-8 py-12".ToConstSignal(),
                    },
                    Children =
                    [
                        new P
                        {
                            Props = new PProps
                            {
                                Class = "text-6xl font-bold tabular-nums".ToConstSignal(),
                            },
                            Children = [new DomText { Text = new Computed<string>(() => $"{count.Value}") }],
                        },
                        new Button
                        {
                            Props = new ButtonProps
                            {
                                Class = "mt-6 rounded-lg bg-indigo-600 px-5 py-2.5 font-semibold text-white hover:bg-indigo-500".ToConstSignal(),
                            },
                            Events = new ButtonEvents { OnClick = _ => count.Value++ },
                            Children = [new DomText { Text = "Click me".ToConstSignal() }],
                        },
                    ],
                },
            ];
        }
    }

    Give it a route in App.cs, next to the two that are there,

    MyApp.Client/Components/App.cs
    // Add to the Items of Routes:
    new Route
    {
        Pattern = "/counter",
        Render = () => [new CounterPage { Props = new NoProps() }],
    },

    and a link in the header, in NavItems.cs:

    MyApp.Client/Components/NavItems.cs
    internal static readonly NavItem[] All =
    [
        new("Home", "/"),
        new("About", "/about"),
        new("Counter", "/counter"), // new
    ];

    Save, and dotnet watch picks it up. Open Counter and click: the number updates and nothing else on the page is touched. Now change "Click me" or a class name and save again; the change appears in the open tab without a refresh.

    Where Tailwind looks for classes

    The stylesheet is built from the class names written in plain string literals in the client project. Write each class out in full, like bg-indigo-600, in a string that isn't interpolated, and keep the components that use them in MyApp.Client.

What's in the project

Two projects that share one set of components. The client holds your pages; the server references it and renders those same components to HTML, so a page is written once and runs in both places.

MyApp/The solution folder
MyApp/The server: an ASP.NET Core app
Program.csRenders each request to HTML, data included
Components/AppPage.csThe document around your app: <head>, scripts, styles
MyApp.Client/The client: WebAssembly, and every page you write
Program.csHydrates the server's HTML in the browser
Components/App.csThe layout and the routes
Components/HomePage.csOne component per page; About works the same way
Components/NavItems.csThe header's links
Styles/app.cssTailwind's entry point: themes, plugins, custom CSS
Styles.csCompiles that stylesheet while your code builds
Directory.Packages.propsNatrix package versions, in one place

Troubleshooting

dotnet new can't find a template called natrix

The template isn't installed for the SDK you're running. Run dotnet new install Natrix.Templates again, then check with dotnet new list natrix.

The browser says the connection isn't private

The development certificate isn't trusted yet. Run dotnet dev-certs https --trust, then restart the app and the browser.

Port 5100 is already in use

Change applicationUrl in MyApp/Properties/launchSettings.json to a free port.

A Tailwind class has no effect

Tailwind only generates the classes it finds in plain string literals in the client project. Classes in an interpolated string, like $"px-4 {extra}", classes put together at runtime, and classes named only in the server project are never seen. Write them out in full in a plain string in MyApp.Client.

Moving an existing app to a newer Natrix

Change the versions in Directory.Packages.props. The three Natrix packages are released together, so keep them on the same version.

Next steps

Each example runs live on this site, with its source a click away. Read them in any order.