Skip to content

Components

Edgar Mesquita edited this page Jul 31, 2026 · 11 revisions

Components

Warning

Outdated: the legacy web component library documented below was EXCISED on 2026-07-31 — the write-once library (WriteOnceComponents, 28 components) is the only architecture. This page is kept for history.

Note

This catalog covers the legacy web component library (eQuantic.UI.Components). The framework is migrating to a write-once library (eQuantic.UI.Components.Shared) authored against the Photon vocabulary and realized on web AND native — 8 components migrated so far, mixing is safe in both directions. See Write-Once Components.

Complete reference of the eQuantic.UI component system — architecture, catalog, and production patterns.

Component Architecture

HtmlNode (Virtual DOM)

HtmlNode is the basic unit of the Virtual DOM — a lightweight representation of a real DOM element.

  • Tag: HTML tag name (e.g., div, button)
  • Key: Unique identifier for reconciliation optimization
  • Attributes: Dictionary of HTML attributes (class, id, style, etc.)
  • Events: C# delegates converted into event listeners
  • Children: List of child HtmlNodes
  • TextContent: Used for text nodes (#text)

Component Types

Type Description Use Case
StatelessComponent Functional components depending only on props. Override Build() to return the component tree. Visual components: Text, Heading, Badge
StatefulComponent Components with persistent internal state. SetState triggers re-render of the component and children. Interactive pages, forms, dashboards
HtmlElement Low-level primitives mapping directly to HTML tags. Box, Flex, Grid, Container
InputComponent<TValue> Base for input components with value binding, events, and theme integration. TextInput, Select, Checkbox

Events

Events follow the On{EventName} convention. The compiler removes the On prefix and converts to lowercase in TypeScript:

new Button {
    Text = "Clear",
    Variant = Variant.Secondary,
    OnClick = HandleClear
}

Component Interfaces

Interface Purpose Documentation
IRequireAssets Declare script/CSS dependencies Asset Management
IHandleMetadata Configure SEO metadata Server Integration

Component Catalog

Layout

Component Description Key Props
Container Responsive max-width container MaxWidth, Fluid
Box Generic block container (div) Children
Flex Flexbox container Direction, Justify, Align, Gap, Wrap
Row Horizontal flex container Inherits from Flex
Column Vertical flex container Inherits from Flex
Stack Stack layout with spacing Direction, Gap
Grid CSS Grid layout Columns, Gap
GridItem Grid child with placement ColSpan, RowSpan
new Grid { Columns = 3, Gap = "4", Children = {
    new GridItem { ColSpan = 2, Content = new Text("Wide") },
    new GridItem { Content = new Text("Narrow") }
}}

Inputs

Component Description Key Props
TextInput Text input field Type, Placeholder, Value, OnChange, Size, Disabled
TextArea Multi-line text input Rows, Value, OnChange, Disabled
Checkbox Checkbox with optional rich UI Checked, OnChange, IsNative
Radio Radio button Checked, OnChange, Name, Label
RadioGroup Radio button group Value, OnChange, Options, Direction
RadioOption Data class for radio options Value, Label, Disabled
Select Dropdown select Value, OnChange, Multiple, Options, IsNative
SelectOption Data class for select options Value, Label, Disabled
Switch Toggle switch (inherits Checkbox) Value, OnChange, Label
Slider Range slider Value, Min, Max, Step, OnChange

All inputs inherit from InputComponent<TValue>, which provides:

  • Value / OnChange / OnInput event binding
  • Disabled, ReadOnly, Required states
  • Theme integration via IInputTheme

Controlled vs Uncontrolled

All input components support both modes:

// Controlled — external state management, real-time validation
new TextInput {
    Value = email,
    OnChange = (value) => SetState(() => email = value)
}

// Uncontrolled — internal state, simple forms
new TextInput {
    DefaultValue = "user@example.com",
    Name = "email"
}

When to use each:

  • Controlled: Real-time validation, dependent fields, complex forms
  • Uncontrolled: Simple forms, server-side validation, minimal state

Forms

Component Description Key Props
FormField Label + input + error wrapper Label, Error, Required, HelperText, For
InputGroup Input with prefix/suffix addons Children
// FormField with validation
new FormField {
    Label = "Email Address",
    Required = true,
    Error = validationError,
    HelperText = "We'll never share your email",
    For = "email-input",
    Children = {
        new TextInput { Id = "email-input", Type = "email", Name = "email" }
    }
}

// InputGroup with addons
new InputGroup {
    Children = {
        new InputAddon { Text = "https://" },
        new TextInput { Placeholder = "example.com" },
        new Button { Text = "Go" }
    }
}

Display

Component Description Key Props
Badge Status/category badge Text, Variant
Avatar User avatar (image or initials) ImageUrl, AltText, Initials, Size
Heading H1-H6 heading Content, Level (1-6)
Text Text span/paragraph Content, Variant, Paragraph
Icon Unified icon component Name (e.g., "lucide:search"), Size
CodeBlock Syntax-highlighted code Code, Language, Collapsible
List Ordered/unordered list Ordered, Unstyled, Children
ListItem List item Active, Disabled, OnClick
Table<T> Data table Data, Columns, Striped, OnRowClick

CodeBlock

Renders syntax-highlighted code using Prism.js with automatic dark/light theme switching:

new CodeBlock("Console.WriteLine(\"Hello\");", "csharp") { Collapsible = true }

Features:

  • Prism.js loaded automatically via IRequireAssets
  • Copy to clipboard button
  • Collapsible/expandable code blocks
  • Dark/light theme auto-switches with the page theme

Table<T>

new Table<User> {
    Data = users,
    Columns = new[] {
        new TableColumn { Header = "Name", Field = "Name" },
        new TableColumn { Header = "Email", Field = "Email", Sortable = true }
    }
}

Surfaces

Component Description Key Props
Card Card container Variant, Shadow
CardHeader Card header section Children
CardTitle Card title Text
CardDescription Card description Text
CardBody Card body content Children
CardFooter Card footer Children

Compound Pattern

new Card { Variant = CardVariant.Elevated, Shadow = Shadow.Large, Children = {
    new CardHeader { Children = {
        new CardTitle { Text = "Q1 2026 Roadmap" },
        new CardDescription { Text = "Key initiatives" }
    }},
    new CardBody { Children = {
        new Text("Launch mobile app"),
        new Text("Implement AI features")
    }},
    new CardFooter { Children = {
        new Button { Text = "View Details", Variant = Variant.Outline },
        new Button { Text = "Share", Variant = Variant.Ghost }
    }}
}}

Card Variants

CardVariant.Default    // Filled card with background
CardVariant.Outline    // Border only, transparent background
CardVariant.Elevated   // Prominent shadow for emphasis
CardVariant.Subtle     // Minimal visual weight
CardVariant.Ghost      // No background or border

Feedback

Component Description Key Props
Alert Alert message Variant
AlertTitle Alert title Text
AlertDescription Alert description Text
Toast Toast notification Variant, DelayMs, Title, Message
ToastContainer Toast positioning container Position (TopRight, BottomLeft, etc.)
Spinner Loading indicator Variant (Border/Grow), Size (Small/Normal)
new Alert { Variant = Variant.Warning, Children = {
    new AlertTitle { Text = "Warning" },
    new AlertDescription { Text = "This action cannot be undone." }
}}

Navigation

Component Description Key Props
Tabs Tab navigation DefaultValue, Value, OnValueChange
TabsList Tab header list Children
TabsTrigger Tab trigger button Value, Text
TabsContent Tab content panel Value, Children
Accordion Collapsible sections Type (Single/Multiple), Collapsible
AccordionItem Accordion section Value, Children
AccordionTrigger Accordion trigger button Text
AccordionContent Accordion content panel Children
Breadcrumb Breadcrumb navigation Items, Separator
Navbar Top navigation bar Brand, Items, Dark, Fixed
Sidebar Side navigation panel Items, Width, Collapsed
NavigationMenu Complex nav menu Children (compound pattern)
new Tabs { DefaultValue = "tab1", Children = {
    new TabsList { Children = {
        new TabsTrigger { Value = "tab1", Text = "General" },
        new TabsTrigger { Value = "tab2", Text = "Advanced" }
    }},
    new TabsContent { Value = "tab1", Children = { ... } },
    new TabsContent { Value = "tab2", Children = { ... } }
}}

Overlays

Component Description Key Props
Modal Modal dialog IsOpen, Title, OnClose
Drawer Slide-out panel IsOpen, Side, OnClose
DrawerContent Drawer body Width, Children
DrawerTrigger Drawer open trigger Children
ContextMenu Right-click menu Children (compound pattern)
ContextMenuItem Menu item Disabled, Shortcut
new Drawer { Side = DrawerSide.Right, IsOpen = isOpen, Children = {
    new DrawerContent { Children = {
        new DrawerTitle { Text = "Settings" },
        // content...
    }}
}}

Utility

Component Description
DynamicElement Generic HTML element (any tag, attributes, events)
NullComponent Empty/null component (renders nothing)
Link Anchor tag with Href, Target
Button Button with Variant, Size, Loading, Disabled

Common Props

All components inherit from IComponent and share:

Prop Type Description
Id string? HTML id attribute
ClassName string? CSS class(es)
Style HtmlStyle? Inline styles
DataAttributes Dictionary<string, string>? data-* attributes
AriaAttributes Dictionary<string, string>? aria-* attributes
Children List<IComponent> Child components

Data & ARIA Attributes

new Button {
    Text = "Submit",
    DataAttributes = new Dictionary<string, string> {
        ["testid"] = "submit-button",
        ["analytics"] = "checkout-submit"
    },
    AriaAttributes = new Dictionary<string, string> {
        ["label"] = "Submit order",
        ["describedby"] = "submit-help"
    }
}
// Renders: <button data-testid="submit-button" aria-label="Submit order">Submit</button>

Theme & Styling

Variants & Sizes

Most components support theme-driven styling:

  • Variant: Primary, Secondary, Destructive, Outline, Ghost, Link, Success, Warning, Info
  • Size: Small, Medium, Large, XLarge

Themes are provided by IAppTheme (default eQuantic theme or Tailwind via AddTailwind()).

StyleBuilder

StyleBuilder is a utility inspired by CVA (Class Variance Authority) for managing conditional CSS classes:

["class"] = StyleBuilder.Create(theme?.Base)
                .Add(theme?.GetVariant(Variant))
                .Add(theme?.GetSize(Size))
                .Add(ClassName)
                .Build()

IColorTheme

Component themes inject an IColorTheme interface that maps semantic colors to concrete classes, facilitating global color palette customization.

Input Variants

Inputs support state-based variants for validation feedback:

  • Success - Valid/successful input
  • Warning - Warning state
  • Destructive - Error state
  • Ghost - Minimal style

Custom Themes

public class MyCardTheme : ICardTheme
{
    public string Container => "my-custom-card";
    public string Title => "my-custom-title";
    public string GetVariant(CardVariant variant) => variant switch
    {
        CardVariant.Outline => "my-outline-variant",
        _ => ""
    };
}

Production Patterns

Loading States

new Button {
    Text = "Submit Order",
    Loading = isSubmitting,  // Automatic spinner + disabled state
    OnClick = HandleSubmit
}

Features:

  • Automatic spinner rendering
  • Button disabled during loading
  • data-loading="true" attribute for CSS targeting
  • Accessible with aria-hidden="true" on spinner

Error States & Validation

new FormField {
    Label = "Email Address",
    Required = true,
    Error = validationError,
    HelperText = "We'll never share your email",
    Children = {
        new TextInput { Type = "email", Name = "email" }
    }
}

Features:

  • Label with automatic required indicator (*)
  • Error messages styled with role="alert" for accessibility
  • Helper text displayed when no errors present
  • Automatic .eq-error class on wrapper

Compound Components

For complex UIs, use the compound pattern for semantic structure:

// Recommended — semantic and flexible
new Card {
    Variant = CardVariant.Elevated,
    Children = {
        new CardHeader { Children = { new CardTitle { Text = "Title" } } },
        new CardBody { Children = { new Text("Content") } },
        new CardFooter { Children = { new Button { Text = "Save" } } }
    }
}

Best Practices

  1. Use compound components for complex UIs (Card, Tabs, Accordion)
  2. Use controlled mode for real-time validation, uncontrolled for simple forms
  3. Wrap inputs in FormField for consistent validation UX
  4. Add loading states to all async action buttons
  5. Add Data/ARIA attributes for testing and accessibility

Comparison with shadcn/ui

Feature eQuantic.UI shadcn/ui Advantage
Compound Components Full support Full support Parity
Variants 5+ per component 5+ per component Parity
Controlled/Uncontrolled TextInput, Select, Checkbox Full support Parity
Loading States Button + inputs Button + inputs Parity
Error States FormField component Form component Parity
Input Groups Full support Full support Parity
Data/ARIA Attributes Native support Native support Parity
Documentation XML (IntelliSense) JSDoc eQuantic
Type Safety C# Compiler TypeScript eQuantic
Theming System DI + Fallback CSS vars eQuantic
Performance Compile-time Runtime eQuantic

See Also

Clone this wiki locally