-
Notifications
You must be signed in to change notification settings - Fork 1
Components
Complete reference of the eQuantic.UI component system — architecture, catalog, and production patterns.
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)
| 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 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
}| Interface | Purpose | Documentation |
|---|---|---|
IRequireAssets |
Declare script/CSS dependencies | Asset Management |
IHandleMetadata |
Configure SEO metadata | Server Integration |
| 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") }
}}| 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, Native
|
Radio |
Radio button |
Checked, OnChange, Name
|
RadioGroup |
Radio button group |
Value, OnChange, Children
|
RadioOption |
Option within RadioGroup |
Value, Label
|
Select |
Dropdown select |
Value, OnChange, Multiple, Options
|
SelectOption |
Option within Select |
Value, Label
|
Switch |
Toggle switch |
Checked, OnChange
|
Slider |
Range slider |
Value, Min, Max, Step, OnChange
|
All inputs inherit from InputComponent<TValue>, which provides:
-
Value/OnChange/OnInputevent binding -
Disabled,ReadOnly,Requiredstates - Theme integration via
IInputTheme
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
| Component | Description | Key Props |
|---|---|---|
FormField |
Label + input + error wrapper |
Label, Error, Required, HelperText, For
|
InputGroup |
Input with prefix/suffix addons |
Prefix, Suffix, 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" }
}
}| Component | Description | Key Props |
|---|---|---|
Badge |
Status/category badge | Variant |
Avatar |
User avatar (image or initials) |
Src, Alt, Initials, Size
|
Heading |
H1-H6 heading |
Level (1-6) |
Text |
Text span/paragraph | Variant |
Icon |
Unified icon component |
Name (e.g., "lucide:search"), Size
|
CodeBlock |
Syntax-highlighted code |
Code, Language, Collapsible
|
List |
Ordered/unordered list |
Ordered, Items
|
Table<T> |
Data table |
Data, Columns, Sortable, OnRowClick
|
Spinner |
Loading spinner | Size |
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
new Table<User> {
Data = users,
Columns = new[] {
new TableColumn { Header = "Name", Field = "Name" },
new TableColumn { Header = "Email", Field = "Email", Sortable = true }
}
}| Component | Description | Key Props |
|---|---|---|
Card |
Card container |
Variant, Shadow
|
CardHeader |
Card header section | Children |
CardTitle |
Card title | InnerText |
CardDescription |
Card description | InnerText |
CardBody |
Card body content | Children |
CardFooter |
Card footer | Children |
new Card { Variant = CardVariant.Elevated, Shadow = Shadow.Large, Children = {
new CardHeader { Children = {
new CardTitle { InnerText = "Q1 2026 Roadmap" },
new CardDescription { InnerText = "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 }
}}
}}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| Component | Description | Key Props |
|---|---|---|
Alert |
Alert message | Variant |
AlertTitle |
Alert title | InnerText |
AlertDescription |
Alert description | InnerText |
Toast |
Toast notification |
Variant, Duration
|
Spinner |
Loading indicator | Size |
new Alert { Variant = Variant.Warning, Children = {
new AlertTitle { InnerText = "Warning" },
new AlertDescription { InnerText = "This action cannot be undone." }
}}| Component | Description | Key Props |
|---|---|---|
Tabs |
Tab navigation | Children |
TabsList |
Tab header list | Children |
TabsTrigger |
Tab trigger button |
Value, InnerText
|
TabsContent |
Tab content panel |
Value, Children
|
Accordion |
Collapsible sections |
Type (Single/Multiple) |
AccordionItem |
Accordion section |
Value, Trigger, Content
|
Breadcrumb |
Breadcrumb navigation | Items |
Navbar |
Top navigation bar | Children |
Sidebar |
Side navigation panel | Children |
NavigationMenu |
Complex nav menu | Children |
new Tabs { Children = {
new TabsList { Children = {
new TabsTrigger { Value = "tab1", InnerText = "General" },
new TabsTrigger { Value = "tab2", InnerText = "Advanced" }
}},
new TabsContent { Value = "tab1", Content = ... },
new TabsContent { Value = "tab2", Content = ... }
}}| Component | Description | Key Props |
|---|---|---|
Modal |
Modal dialog |
IsOpen, Title, OnClose
|
Drawer |
Slide-out panel |
IsOpen, Side, OnClose
|
DrawerContent |
Drawer body | Children |
DrawerTrigger |
Drawer open trigger | Children |
ContextMenu |
Right-click menu | Items |
new Drawer { Side = DrawerSide.Right, IsOpen = isOpen, Children = {
new DrawerContent { Children = {
new Heading { Level = 3, InnerText = "Settings" },
// content...
}}
}}| 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, IsLoading, Disabled
|
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 |
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>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 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()Component themes inject an IColorTheme interface that maps semantic colors to concrete classes, facilitating global color palette customization.
Inputs support state-based variants for validation feedback:
-
Success- Valid/successful input -
Warning- Warning state -
Destructive- Error state -
Ghost- Minimal style
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",
_ => ""
};
}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
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-errorclass on wrapper
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" } } }
}
}- Use compound components for complex UIs (Card, Tabs, Accordion)
- Use controlled mode for real-time validation, uncontrolled for simple forms
- Wrap inputs in FormField for consistent validation UX
- Add loading states to all async action buttons
- Add Data/ARIA attributes for testing and accessibility
| 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 |
- Asset Management - Component asset dependencies
- Styling - Theme system and styling patterns
- Server Integration - SSR, SEO, and server configuration
- Architecture - Overall framework architecture