-
Notifications
You must be signed in to change notification settings - Fork 1
Styling
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:
- Abstraction: Components author what to style — typed C# values, never CSS strings.
- One semantics, two targets: the same style vocabulary drives dp values on native (Photon) and CSS on the web.
- Performance: build-time class generation and deduplication — no CSS-in-JS runtime overhead.
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.
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.
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.
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" }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.
| 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. |