Theme engine

A generated OKLCH token layer for runtime customization. The engine switches mode, base gray, primary, radius, font, and style recipe through data-zits-* attributes, so components keep using the same utility classes.

Overview

ThemeStylesheet.Generate() writes a committed zits-theme.css static asset from C#. The CSS is deterministic, culture independent, and drift guarded by unit tests. It composes the dimensions as small attribute-keyed blocks instead of generating one class for every possible combination.

Generated

C# StringBuilder output, committed as a static web asset.

Runtime

A scoped service writes attributes and persists JSON to localStorage.

Scoped

Any subtree can carry its own full theme, including forced light or dark.

Live switcher

Open the switcher and pick a dimension. The whole page changes because the selected values are written to <html>. Reset removes the runtime attributes and returns this docs site to its signal-red token theme.

The panel also exposes the resolved :root and .dark CSS export.

Card

Surface tokens

Secondary

Recipe tokens

Primary

Brand token

Install

Two paths, depending on how you consume zits/ui. Package mode references the Zits.Ui package and serves the engine assets from its static web assets. Vendored mode copies them into your own project with navius add theme.

Package mode

AddZitsUi() ships with the package and registers the theme service.

MyApp.csproj xml
<PackageReference Include="Zits.Ui" Version="0.3.0-preview.5" />
Program.cs csharp
builder.Services.AddNavius();
builder.Services.AddZitsUi();
index.html or App.razor head html
<script src="_content/Zits.Ui/zits-theme-init.js"></script>
<link href="_content/Zits.Ui/zits-ui.css" rel="stylesheet" />
<link href="_content/Zits.Ui/zits-theme.css" rel="stylesheet" />

Vendored mode

There is no AddZitsUi() without the package: register the vendored ZitsThemeService directly, and call AddNavius() for the overlay services its switcher popover uses. The assets copy into your wwwroot, so they serve from the app root.

Terminal bash
navius add theme
Program.cs csharp
builder.Services.AddNavius();                 // brain overlay + keyboard services
builder.Services.AddScoped<ZitsThemeService>(); // the vendored theme service
index.html or App.razor head html
<script src="/zits-theme-init.js"></script>
<link href="/zits-ui.css" rel="stylesheet" />
<link href="/zits-theme.css" rel="stylesheet" />

Scoped themes

ZitsThemeScope renders a normal container with the six theme attributes. Custom properties resolve at the element that uses them, so nested cards, buttons, and form controls pick up the scoped theme without component changes.

Forced light

This box stays light inside a dark page.

Forced dark

This box stays dark inside a light page.

CSS export

ThemeStylesheet.GenerateCss(theme) resolves one selection to a standalone :root and .dark block. Use it when you want to stop depending on the runtime switcher and bake the chosen design back into your own token file.

C# csharp
var theme = new ZitsTheme(
    ZitsThemeMode.System,
    Base: "neutral",
    Primary: "blue",
    Radius: "md",
    Font: "system",
    Style: "standard");

var css = ThemeStylesheet.GenerateCss(theme);