BlazorNova BlazorNova
BlazorNova BlazorNova
☰
☰ Menu
Getting Started
Installation
Project Setup
Source Generator
Core Concepts
Surface System
Color Palette
Fluent CSS API
Style Overrides
CSS Precedence
BlazorNova Classes
Layout
Flexbox & Grid
Spacing
Sizing
Typography
Backgrounds
Borders
Effects
Filters
Transitions & Transforms
Interactivity
Components
Forms
BnEditForm
FormState
Monitors
MenuBar
Horizontal
Vertical
Tabs
BnTab
Icons
Icon Gallery
Buttons
BnButton
Layout
BnStackPanel
BnDrawer
Grid
BnGrid
BnPagedGrid
Navigation
BnNavigator
Carousel
BnCarousel
Charts
BnChart
PDF Viewer
BnPdfViewer
Meet
BnVideoCall

Color Palette

BlazorNova's palette is a structured set of surfaces rather than a flat list of colour tokens. Each surface defines exactly the colours needed for the UI that lives on it, and the system distinguishes clearly between neutral depth and branded intent.

Semantic Tokens Per Surface

Each surface palette defines a focused set of semantic colour tokens:

  • Bg / OnBg — container background and its foreground colour
  • AltBg — subtle alternate background for visual variation within a surface (e.g. alternating table rows)
  • EmphasisBg — emphasis background for interactive states like hover and selection
  • Border — soft mid-tone border colour, much less harsh than OnBg
  • Input / OnInput — input field background and text
  • Error, ErrorContainer, OnErrorContainer
  • Warning, WarningContainer, OnWarningContainer
  • Success, SuccessContainer, OnSuccessContainer

AltBg, EmphasisBg, and Border solve a common problem: components that previously consumed extra surface levels for visual differentiation within a single surface. A grid no longer needs to burn Surface1 for odd rows and Surface2 for hover — it uses bg_AltBg for alternating rows and bg_EmphasisBg for hover/selected states, all within the same surface depth.

Semantic colours (Error, Warning, Success) are per-surface because they need to be readable on top of each specific surface background. A red that works on a white card may not read clearly on a dark navy panel.

No Per-Surface Accent

There is no Accent token on individual surfaces. A "primary action" colour always comes from SurfacePrimary1-Bg; secondary from SurfaceSecondary1-Bg. Brand colours do not have a dependency on the containing surface — they are always the same, regardless of context.

This makes intent explicit: a button declares its visual weight by choosing a ButtonVariant (Primary, Secondary, Tertiary), not by inheriting whatever accent the parent surface happens to define.

csharp
// A button picks its palette explicitly — no ambient accent needed.
<BnButton Label="Save"   Variant="ButtonVariant.Primary" />
<BnButton Label="Cancel" Variant="ButtonVariant.Secondary" />
<BnButton Label="More"   Variant="ButtonVariant.Surface" />

Branded Surface Pairs (1 / 2)

Each branded palette has two levels — Primary1 and Primary2 — not for nesting one branded surface inside another, but to provide the normal and hover/active states required by the rel1 hover mechanism.

Primary1 is the resting state. Primary2 is the hover shade. Because neutral surfaces follow the same rel1 contract (Surface1 → Surface2), all hover expressions are written identically regardless of which palette family a component sits on.

csharp
// For most components, hover uses EmphasisBg — stays within the same surface:
Bn.SetSurface(SurfacePrimary1).bg_Bg.text_OnBg
  .Hover(h => h.bg_EmphasisBg)

// EmphasisBg is a pre-defined hover shade within each palette.
// This avoids consuming the next surface level just for hover.

// The rel1 pattern still exists for true depth nesting:
// SurfacePrimary1-Bg  → resting background  (e.g. Violet-600)
// SurfacePrimary2-Bg  → next depth level    (e.g. Violet-500)
// Use rel1 when a child region genuinely needs a deeper surface.

Customising the Palette

Override LightPalette and/or DarkPalette in your BlazorNovaConfig subclass to supply your brand colours. The generated CSS emits one set of CSS custom properties per palette entry, so the entire component tree — including any installed BlazorNova component libraries — picks up your colours automatically.

csharp
public class MyAppConfig : BlazorNovaConfig
{
    public override string RelativeOutputDirectory { get; } = "/wwwroot/generated";

    public override ThemePalette LightPalette { get; } = new ThemePalette
    {
        // Override specific entries; unset entries use BlazorNova defaults.
        SurfacePrimary1 = new SurfacePrimary1
        {
            Bg    = Color.FromArgb(255, 37, 99, 235),   // Blue-600
            OnBg  = Color.White
        },
        SurfacePrimary2 = new SurfacePrimary2
        {
            Bg    = Color.FromArgb(255, 59, 130, 246),  // Blue-500 (hover)
            OnBg  = Color.White
        }
    };
}