Skip to content

Styling

Edgar Mesquita edited this page Aug 10, 2026 · 10 revisions

eQuantic.UI Styling Architecture

Core Philosophy

eQuantic.UI provides a Flutter-inspired developer experience (DX) while leveraging the full power of each rendering target. The styling architecture is built on three pillars:

  1. Abstraction: Components author what to style — typed C# values, never CSS strings.
  2. One semantics, two targets: the same style vocabulary drives dp values on native (Photon) and CSS on the web.
  3. Performance: build-time class generation and deduplication — no CSS-in-JS runtime overhead.

1. Styling Components — Typed C#, No CSS Plane

Component styling is authored entirely in typed C# (BoxStyle, StyleDiff, design tokens) and lowered by the atomic style engine: every regular declaration becomes ONE deduplicated atomic class, byte-identical between SSR (C#) and hydration (TS); theme colors reference var(--eq-color-*) custom properties. Hover/focus states, window-size-class adaptivity, sticky positioning and transforms are all part of the vocabulary — zero JavaScript involved.

The code face

A monospaced run (Text with Mono, a rich run, a CodeBlock) draws in a stack the framework owns, and it lands on an atomic class — which beats a body { font-family } rule, and whose name is a content hash that moves between builds. So there was nowhere to hang your own code face. The hook is a variable:

:root { --eq-font-mono: 'JetBrains Mono', ui-monospace, monospace; }

Every mono run follows it, with the platform stack as the fallback when nothing sets it.

The measurer reads the same variable, and that is not an implementation detail you can ignore if you ship a code editor: CodeEditor places its caret from a measured column advance, so measuring in one face while drawing in another puts the caret beside the character it is on rather than under it.

The full engine — laws, pseudo-states, size classes, the generated stylesheet — is documented in DesignSystem. The abstract vocabulary itself (Box, Row/Column, Grid, Stack, …) is documented in Write-Once Components.

Theming = providing an IAppTheme

Themes are typed C# too — colors as light/dark ColorToken pairs, type roles, shape scale, elevation — selected in one line and bridged SSR→client:

builder.Services.AddUI(options =>
{
    options.ScanAssembly(typeof(Program).Assembly)
           .UseTheme(PhotonTheme.Instance);          // or MaterialTheme.FromSeed(color)
});

Two implementations ship: PhotonTheme (the default) and MaterialTheme (real Material 3, including dynamic color from a seed). Swap the theme and every component rebrands — server and client, web and native. Runtime light/dark switching is a service (IThemeController); see DesignSystem.


2. The HTML Escape Hatch

The low-level web layer (eQuantic.UI.Core) mirrors the DOM 1:1. Every HtmlElement exposes the attributes the browser has:

public abstract class HtmlElement : IComponent {
    /// <summary>Raw CSS classes (space-separated).</summary>
    public string? ClassName { get; set; }

    /// <summary>Inline styles for dynamic values (e.g., coordinates, colors from DB).</summary>
    public HtmlStyle? Style { get; set; }
}

This contract means the web layer does not enforce any CSS framework — it renders HTML attributes. DynamicElement goes further and renders any tag with any attributes. Standard CSS classes from any stylesheet work natively:

new DynamicElement("aside") { ClassName = "my-sidebar" }

3. Bringing external CSS

The framework ships exactly one styling engine — the typed C# pipeline above. There is no bundled CSS framework and no adapter layer: a page that needs hand-written markup uses the escape hatch (HtmlElement/DynamicElement + ClassName), and any stylesheet the app brings — its own CSS file, a utility framework it builds itself — is referenced like on any web project:

builder.Services.AddUI(options =>
{
    options.ConfigureHtmlShell(shell => shell.AddStylesheet("/css/app.css"));
});

The framework neither generates nor processes that CSS; it is the app's own build concern.

4. Package Roles

Package Purpose
eQuantic.UI.Primitives Typed styles, design tokens, the abstract vocabulary — the styling source of truth.
eQuantic.UI.Core The DOM-mirror layer: HtmlElement, ClassName, HtmlStyle, DynamicElement.
eQuantic.UI.Web The web realizer + atomic style engine (StyleAtomizer) + generated stylesheet.

Clone this wiki locally