Theme & Colors

Customize MonorailCSS color palettes, font families, and other design tokens

The theme is where your design tokens live. Colors, fonts, spacing, breakpoints — every value MonorailCSS knows about is keyed by a CSS custom property name (like --color-blue-500 or --font-display) and emitted as a real CSS variable in the output. Customizing the theme means adding, replacing, or aliasing those keys.

Adding a Color Palette

The most common customization: introduce a new palette so utilities like bg-brand-500 and text-brand-700 resolve to your brand colors.

csharp
public static CssFramework Build()
{
    var theme = new ThemeModel().AddColorPalette("brand", new Dictionary<string, string>
    {
        { "50",  "oklch(0.985 0.013 280)" },
        { "100", "oklch(0.961 0.027 280)" },
        { "200", "oklch(0.918 0.058 280)" },
        { "300", "oklch(0.852 0.108 280)" },
        { "400", "oklch(0.745 0.165 280)" },
        { "500", "oklch(0.638 0.207 280)" },
        { "600", "oklch(0.554 0.207 280)" },
        { "700", "oklch(0.464 0.182 280)" },
        { "800", "oklch(0.378 0.151 280)" },
        { "900", "oklch(0.298 0.116 280)" },
        { "950", "oklch(0.220 0.090 280)" },
    }.ToImmutableDictionary());
  
    return new CssFramework(new CssFrameworkSettings { Theme = theme });
}

Once registered, every utility that consumes the --color-* namespace works with your new palette: bg-brand-500, border-brand-200, ring-brand-300, from-brand-50, etc.

What about the shade keys?

The standard scale is 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950 — the same shades the built-in palettes use. You don't have to provide every shade, but you do need to provide the ones you reference in markup. Missing shades simply won't generate utilities.

Overriding a Single Shade

Need to nudge a single color without rebuilding a palette? Use Theme.Add directly with the fully-qualified key:

csharp
public static CssFramework Build()
{
    var theme = new ThemeModel()
        .Add("--color-blue-500", "#1d4ed8")
        .Add("--color-blue-600", "#1e40af");
  
    return new CssFramework(new CssFrameworkSettings { Theme = theme });
}

This changes only --color-blue-500 and --color-blue-600. The rest of the blue scale, and every other palette, are untouched.

Aliasing a Palette

Aliases let you give a semantic name (primary, accent, surface) to an existing palette. Behind the scenes the alias becomes a thin layer of CSS variables pointing at the source palette, so swapping the source later is a one-line change.

csharp
public static CssFramework Build()
{
    var theme = new ThemeModel().MapColorPalette("sky", "primary");
  
    return new CssFramework(new CssFrameworkSettings { Theme = theme });
}

After this runs, bg-primary-500 emits the same color as bg-sky-500, but the markup is in design-system terms.

Starting From an Empty Theme

If you don't want any of the built-in defaults — no Tailwind palette, no preset spacing scale — start from Theme.CreateEmpty() and build up only what you need:

csharp
public static CssFramework Build()
{
    var theme = ThemeModel.CreateEmpty()
        .AddColorPalette("brand", new Dictionary<string, string>
        {
            { "500", "#3b82f6" },
            { "700", "#1d4ed8" },
        }.ToImmutableDictionary());
  
    return new CssFramework(new CssFrameworkSettings { Theme = theme });
}

This is useful for design systems that ship a constrained token set.

Adding Font Families

Font families are stored under the --font-* namespace and surface as font-{name} utilities.

csharp
public static CssFramework Build()
{
    var theme = new ThemeModel()
        .AddFontFamily("display", "'Inter', system-ui, sans-serif")
        .AddFontFamily("mono", "'JetBrains Mono', ui-monospace, monospace");
  
    return new CssFramework(new CssFrameworkSettings { Theme = theme });
}

Now font-display and font-mono are available alongside the built-in font-sans and font-serif.

Next steps

© 2026 MonorailCss · A Tailwind 4.3 compatible CSS engine written in .NET