Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Chapter 22: UI Component Library

The Shared Design System

This chapter defines the complete UI component library shared across all POS Platform applications. These specifications ensure visual consistency, reduce development time, and enable rapid prototyping.


Design Tokens

Color Palette

Primary Colors

TokenHexRGBUsage
--color-primary#1976D225, 118, 210Main brand, primary buttons, links
--color-primary-dark#1565C021, 101, 192Hover states, headers
--color-primary-light#BBDEFB187, 222, 251Selected backgrounds, info panels
--color-primary-50#E3F2FD227, 242, 253Subtle backgrounds

Secondary Colors

TokenHexRGBUsage
--color-secondary#42424266, 66, 66Secondary buttons, icons
--color-secondary-dark#21212133, 33, 33Text, headings
--color-secondary-light#757575117, 117, 117Secondary text, labels

Status Colors

TokenHexRGBUsage
--color-success#4CAF5076, 175, 80Success states, positive
--color-success-light#E8F5E9232, 245, 233Success backgrounds
--color-success-dark#2E7D3246, 125, 50Success text on light bg
--color-warning#FF9800255, 152, 0Warning states, caution
--color-warning-light#FFF3E0255, 243, 224Warning backgrounds
--color-warning-dark#E65100230, 81, 0Warning text on light bg
--color-error#F44336244, 67, 54Error states, destructive
--color-error-light#FFEBEE255, 235, 238Error backgrounds
--color-error-dark#C62828198, 40, 40Error text on light bg
--color-info#2196F333, 150, 243Informational states
--color-info-light#E3F2FD227, 242, 253Info backgrounds
--color-info-dark#1565C021, 101, 192Info text on light bg

Neutral Colors

TokenHexUsage
--color-white#FFFFFFCard backgrounds, content areas
--color-gray-50#FAFAFAAlternating row backgrounds
--color-gray-100#F5F5F5Page backgrounds, disabled
--color-gray-200#EEEEEELight borders, dividers
--color-gray-300#E0E0E0Standard borders
--color-gray-400#BDBDBDInput borders, icons
--color-gray-500#9E9E9EDisabled text, placeholders
--color-gray-600#757575Secondary text
--color-gray-700#616161Icons, labels
--color-gray-800#424242Body text
--color-gray-900#212121Headings, primary text
--color-black#000000Maximum contrast

Typography Scale

Font Families

--font-family-base: 'Segoe UI', -apple-system, BlinkMacSystemFont,
                    'Roboto', 'Helvetica Neue', Arial, sans-serif;

--font-family-mono: 'Cascadia Code', 'Fira Code', 'Consolas',
                    'Monaco', 'Courier New', monospace;

Font Sizes

TokenSizeLine HeightUsage
--font-size-xs11px1.4Captions, badges
--font-size-sm12px1.4Secondary text, timestamps
--font-size-base14px1.5Body text, inputs
--font-size-md16px1.5Emphasized body
--font-size-lg18px1.4Section headers
--font-size-xl20px1.3Card titles
--font-size-2xl24px1.3Page titles
--font-size-3xl30px1.2Dashboard stats
--font-size-4xl36px1.1Large numbers

Font Weights

TokenWeightUsage
--font-weight-light300Large titles
--font-weight-normal400Body text
--font-weight-medium500Buttons, emphasized
--font-weight-semibold600Headers, labels
--font-weight-bold700Stats, strong emphasis

Spacing System

TokenValueUsage
--space-00No spacing
--space-14pxTight, inline elements
--space-28pxComponent padding, gaps
--space-312pxCard padding
--space-416pxSection margins
--space-520pxLarger gaps
--space-624pxPanel padding
--space-832pxSection spacing
--space-1040pxLarge separations
--space-1248pxPage margins

Border Radius

TokenValueUsage
--radius-none0Sharp corners
--radius-sm2pxSubtle rounding
--radius-base4pxInputs, buttons
--radius-md6pxCards
--radius-lg8pxPanels, modals
--radius-xl12pxLarge cards
--radius-full9999pxPills, circles

Shadows

TokenValueUsage
--shadow-sm0 1px 2px rgba(0,0,0,0.05)Subtle lift
--shadow-base0 2px 4px rgba(0,0,0,0.1)Standard cards
--shadow-md0 4px 8px rgba(0,0,0,0.12)Elevated cards
--shadow-lg0 8px 16px rgba(0,0,0,0.15)Dropdowns, popovers
--shadow-xl0 12px 24px rgba(0,0,0,0.2)Modals

Component Specifications

1. StatCard

Purpose: Display key metrics with trend indicators on dashboards.

ASCII Wireframe:

┌────────────────────────────────────┐
│  [icon]                            │
│                                    │
│  LABEL                             │
│  12,450                            │
│  +12.3% vs previous                │
│                                    │
└────────────────────────────────────┘

Variants:

STANDARD                    COMPACT                     INLINE
┌──────────────────┐       ┌──────────────────┐       ┌──────────────────────────┐
│ [icon]           │       │ Orders    1,234  │       │ [icon] Orders: 1,234 +5% │
│ Orders           │       │ +12% ▲           │       └──────────────────────────┘
│ 1,234            │       └──────────────────┘
│ +12% ▲           │
└──────────────────┘

Props:

PropTypeDefaultDescription
TitlestringrequiredMetric label
ValuestringrequiredPrimary value
IconIconTypenullOptional icon
ChangestringnullChange indicator (e.g., “+12%”)
IsPositivebooltrueTrend direction
Colorstring“primary”primary, success, warning, error
Sizestring“standard”standard, compact, inline

Blazor Usage:

<StatCard Title="Today's Sales"
          Value="$12,450"
          Icon="IconType.DollarSign"
          Change="+12.3%"
          IsPositive="true"
          Color="success" />

2. DataGrid

Purpose: Display tabular data with sorting, filtering, and pagination.

ASCII Wireframe:

┌─────────────────────────────────────────────────────────────────────┐
│ [x] │ ORDER #  ▼ │ DATE       │ CUSTOMER      │ AMOUNT ▼ │ STATUS  │
├─────┼────────────┼────────────┼───────────────┼──────────┼─────────┤
│ [ ] │ #1234      │ 12/29/2024 │ John Smith    │   $99.00 │ ● New   │
│ [x] │ #1235      │ 12/29/2024 │ Jane Doe      │  $149.00 │ ● Done  │
│ [ ] │ #1236      │ 12/28/2024 │ Bob Johnson   │   $75.50 │ ! Error │
├─────┴────────────┴────────────┴───────────────┴──────────┴─────────┤
│ Showing 1-50 of 256                        << < Page 1 of 6 > >>   │
└─────────────────────────────────────────────────────────────────────┘

Column Types:

TEXT COLUMN         NUMBER COLUMN       STATUS COLUMN       ACTION COLUMN
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│ John Smith  │    │     $99.00  │    │ ● Completed │    │ [Ed] [Del]  │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
     Left               Right              Center            Center

Props:

PropTypeDefaultDescription
ItemsIEnumerablerequiredData source
ColumnsListrequiredColumn definitions
SelectableboolfalseEnable row selection
SortablebooltrueEnable column sorting
PaginatebooltrueEnable pagination
PageSizeint25Items per page
OnRowClickEventCallbacknullRow click handler
OnSelectionChangeEventCallbacknullSelection handler

Column Definition:

public class Column<T>
{
    public string Header { get; set; }
    public Func<T, object> ValueFunc { get; set; }
    public string Align { get; set; } = "left";  // left, center, right
    public bool Sortable { get; set; } = true;
    public string Width { get; set; } = "auto";
    public Func<T, RenderFragment> Template { get; set; }
}

Blazor Usage:

<DataGrid Items="@orders" Selectable="true" OnRowClick="ViewOrder">
    <Column Header="Order #" ValueFunc="@(o => o.OrderNumber)" />
    <Column Header="Date" ValueFunc="@(o => o.Date.ToShortDateString())" />
    <Column Header="Amount" ValueFunc="@(o => o.Total)" Align="right" />
    <Column Header="Status">
        <Template>
            <StatusBadge Status="@context.Status" />
        </Template>
    </Column>
</DataGrid>

3. StatusBadge

Purpose: Display color-coded status indicators.

ASCII Wireframe:

SUCCESS           WARNING           ERROR             INFO              NEUTRAL
┌─────────┐      ┌─────────┐      ┌─────────┐      ┌─────────┐      ┌─────────┐
│● Active │      │● Pending│      │● Failed │      │● Syncing│      │● Draft  │
└─────────┘      └─────────┘      └─────────┘      └─────────┘      └─────────┘
 Green bg         Orange bg        Red bg           Blue bg          Gray bg

Size Variants:

SMALL                 MEDIUM (Default)           LARGE
┌──────────┐         ┌─────────────┐            ┌────────────────┐
│ ● Active │         │  ● Active   │            │   ● Active     │
└──────────┘         └─────────────┘            └────────────────┘
  11px font            13px font                   15px font

Props:

PropTypeDefaultDescription
StatusstringrequiredStatus text
Variantstring“info”success, warning, error, info, neutral
Sizestring“medium”small, medium, large
ShowDotbooltrueShow status dot

CSS Classes:

.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    border-radius: var(--radius-base);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.status-badge--success {
    background: var(--color-success-light);
    color: var(--color-success-dark);
}

.status-badge--warning {
    background: var(--color-warning-light);
    color: var(--color-warning-dark);
}

.status-badge--error {
    background: var(--color-error-light);
    color: var(--color-error-dark);
}

.status-badge--info {
    background: var(--color-info-light);
    color: var(--color-info-dark);
}

.status-badge--neutral {
    background: var(--color-gray-100);
    color: var(--color-gray-700);
}

.status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: currentColor;
}

Blazor Usage:

<StatusBadge Status="Active" Variant="success" />
<StatusBadge Status="Pending" Variant="warning" />
<StatusBadge Status="Failed" Variant="error" ShowDot="false" />

4. SearchInput

Purpose: Debounced search input with autocomplete support.

ASCII Wireframe:

EMPTY STATE                          WITH VALUE
┌────────────────────────────────┐  ┌────────────────────────────────┐
│ [O] Search products...         │  │ [O] galaxy v-neck          [X] │
└────────────────────────────────┘  └────────────────────────────────┘

WITH AUTOCOMPLETE                    LOADING STATE
┌────────────────────────────────┐  ┌────────────────────────────────┐
│ [O] galaxy v                   │  │ [O] galaxy v-neck      [...]   │
├────────────────────────────────┤  └────────────────────────────────┘
│ Galaxy V-Neck Tee              │
│ Galaxy V-Neck Tank             │
│ Galaxy Vintage Wash            │
└────────────────────────────────┘

Props:

PropTypeDefaultDescription
Valuestring“”Current value
Placeholderstring“Search…”Placeholder text
DebounceMsint300Debounce delay
AutoCompleteboolfalseEnable autocomplete
ItemsIEnumerablenullAutocomplete items
OnSearchEventCallbacknullSearch handler
OnSelectEventCallbacknullSelection handler
DisabledboolfalseDisable input

Blazor Usage:

<SearchInput @bind-Value="searchTerm"
             Placeholder="Search products..."
             DebounceMs="300"
             OnSearch="HandleSearch" />

<SearchInput @bind-Value="productSearch"
             AutoComplete="true"
             Items="@productSuggestions"
             OnSelect="SelectProduct" />

5. Modal

Purpose: Overlay dialog for forms, confirmations, and detail views.

ASCII Wireframe:

STANDARD MODAL
┌────────────────────────────────────────────────────────────┐
│ Modal Title                                           [X]  │
├────────────────────────────────────────────────────────────┤
│                                                            │
│  Modal content goes here.                                  │
│                                                            │
│  This can include forms, text, images, or any other        │
│  content that needs to be displayed in an overlay.         │
│                                                            │
├────────────────────────────────────────────────────────────┤
│                                     [Cancel]  [Confirm]    │
└────────────────────────────────────────────────────────────┘

CONFIRMATION MODAL (Compact)
┌─────────────────────────────────────────────┐
│ [!] Delete Item?                       [X]  │
├─────────────────────────────────────────────┤
│                                             │
│ Are you sure you want to delete this item?  │
│ This action cannot be undone.               │
│                                             │
├─────────────────────────────────────────────┤
│                    [Cancel]  [Delete]       │
└─────────────────────────────────────────────┘

FULLSCREEN MODAL (Mobile)
╔═════════════════════════════════════════════╗
║ [<] Modal Title                             ║
╠═════════════════════════════════════════════╣
║                                             ║
║  Full content area                          ║
║  (scrollable)                               ║
║                                             ║
╠═════════════════════════════════════════════╣
║            [Primary Action]                 ║
╚═════════════════════════════════════════════╝

Size Variants:

SizeWidthUse Case
small400pxConfirmations, alerts
medium600pxForms, details
large800pxComplex forms, tables
fullscreen100%Mobile, immersive

Props:

PropTypeDefaultDescription
TitlestringnullModal title
IsOpenboolfalseVisibility state
Sizestring“medium”small, medium, large, fullscreen
ShowClosebooltrueShow close button
CloseOnOverlaybooltrueClose on backdrop click
OnCloseEventCallbacknullClose handler
ChildContentRenderFragmentrequiredModal body
FooterRenderFragmentnullFooter actions

Blazor Usage:

<Modal Title="Edit Product"
       IsOpen="@showModal"
       Size="medium"
       OnClose="CloseModal">
    <ChildContent>
        <EditForm Model="@product">
            <!-- Form fields -->
        </EditForm>
    </ChildContent>
    <Footer>
        <Button Variant="secondary" OnClick="CloseModal">Cancel</Button>
        <Button Variant="primary" OnClick="SaveProduct">Save</Button>
    </Footer>
</Modal>

6. Toast

Purpose: Non-blocking notifications that auto-dismiss.

ASCII Wireframe:

SUCCESS TOAST                    ERROR TOAST
┌──────────────────────────┐    ┌──────────────────────────┐
│ [check] Product saved    │    │ [X] Failed to save       │
│         successfully     │    │     Please try again     │
│                     [X]  │    │                     [X]  │
└──────────────────────────┘    └──────────────────────────┘

WARNING TOAST                    INFO TOAST
┌──────────────────────────┐    ┌──────────────────────────┐
│ [!] Low inventory        │    │ [i] Sync completed       │
│     Check stock levels   │    │     245 items updated    │
│                     [X]  │    │                     [X]  │
└──────────────────────────┘    └──────────────────────────┘

TOAST WITH ACTION
┌──────────────────────────────────────────┐
│ [!] Order requires attention             │
│     Missing shipping address             │
│                          [View] [Dismiss]│
└──────────────────────────────────────────┘

Position Options:

TOP-RIGHT (Default)             TOP-CENTER              BOTTOM-RIGHT
┌─────────────────┐            ┌─────────────────┐
│                 │            │                 │
│            [T]  │            │       [T]       │
│            [T]  │            │       [T]       │     ┌─────────────────┐
│                 │            │                 │     │                 │
│                 │            │                 │     │            [T]  │
└─────────────────┘            └─────────────────┘     └─────────────────┘

Props:

PropTypeDefaultDescription
MessagestringrequiredToast message
TitlestringnullOptional title
Variantstring“info”success, warning, error, info
Durationint5000Auto-dismiss (ms), 0 = persist
Positionstring“top-right”Toast position
ShowClosebooltrueShow dismiss button
ActionRenderFragmentnullAction buttons

Toast Service:

public interface IToastService
{
    void ShowSuccess(string message, string title = null);
    void ShowError(string message, string title = null);
    void ShowWarning(string message, string title = null);
    void ShowInfo(string message, string title = null);
    void Show(ToastOptions options);
    void DismissAll();
}

Blazor Usage:

@inject IToastService Toast

<button @onclick="SaveProduct">Save</button>

@code {
    async Task SaveProduct()
    {
        try
        {
            await productService.SaveAsync(product);
            Toast.ShowSuccess("Product saved successfully");
        }
        catch
        {
            Toast.ShowError("Failed to save product", "Error");
        }
    }
}

7. LoadingSpinner

Purpose: Indicate loading states.

ASCII Wireframe:

SPINNER ONLY           WITH TEXT              OVERLAY
    ◐                    ◐                 ┌─────────────────┐
   ╱ ╲                 Loading...          │    ░░░░░░░░░    │
  ◜   ◝                                    │    ░  ◐   ░    │
                                           │    ░Loading░    │
                                           │    ░░░░░░░░░    │
                                           └─────────────────┘

Size Variants:

SizeDiameterUse Case
small16pxInline, buttons
medium24pxCards, sections
large48pxPage, full overlay

Props:

PropTypeDefaultDescription
Sizestring“medium”small, medium, large
TextstringnullLoading text
OverlayboolfalseFull overlay mode
Colorstring“primary”Spinner color

Blazor Usage:

<!-- Inline spinner -->
<LoadingSpinner Size="small" />

<!-- With text -->
<LoadingSpinner Text="Saving..." />

<!-- Full overlay -->
<LoadingSpinner Overlay="true" Text="Processing order..." />

<!-- In button -->
<Button Disabled="@isSaving">
    @if (isSaving)
    {
        <LoadingSpinner Size="small" Color="white" />
        <span>Saving...</span>
    }
    else
    {
        <span>Save</span>
    }
</Button>

8. EmptyState

Purpose: Display meaningful placeholder when no data is available.

ASCII Wireframe:

STANDARD EMPTY STATE
┌─────────────────────────────────────────────────────┐
│                                                     │
│                    [  ICON  ]                       │
│                                                     │
│              No products found                      │
│                                                     │
│     Try adjusting your search or filters to         │
│     find what you're looking for.                   │
│                                                     │
│              [Clear Filters]                        │
│                                                     │
└─────────────────────────────────────────────────────┘

COMPACT EMPTY STATE                 WITH ACTION
┌─────────────────────────┐        ┌─────────────────────────┐
│     [icon]              │        │       [icon]            │
│   No items found        │        │   No orders yet         │
└─────────────────────────┘        │                         │
                                   │   [Create Order]        │
                                   └─────────────────────────┘

Props:

PropTypeDefaultDescription
IconIconTypenullIllustration icon
TitlestringrequiredEmpty state title
DescriptionstringnullExplanatory text
ActionRenderFragmentnullAction button(s)
Sizestring“medium”compact, medium, large

Blazor Usage:

<EmptyState Icon="IconType.Box"
            Title="No products found"
            Description="Try adjusting your search or filters.">
    <Action>
        <Button Variant="secondary" OnClick="ClearFilters">Clear Filters</Button>
    </Action>
</EmptyState>

Button Component

Purpose: Primary interactive element for triggering actions.

ASCII Wireframe:

PRIMARY                 SECONDARY              TERTIARY/TEXT
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│    Save         │    │    Cancel       │    │    Learn More   │
└─────────────────┘    └─────────────────┘    └─────────────────┘
 Solid background       Outlined              No border

DANGER                  WITH ICON              LOADING
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│    Delete       │    │  [+] Add Item   │    │  [o] Saving...  │
└─────────────────┘    └─────────────────┘    └─────────────────┘
 Red background         Icon + text           Spinner + text

Size Variants:

SizeHeightPaddingFont Size
small28px8px 12px12px
medium36px10px 16px14px
large44px12px 20px16px

Props:

PropTypeDefaultDescription
Variantstring“primary”primary, secondary, tertiary, danger
Sizestring“medium”small, medium, large
IconIconTypenullLeading icon
IconPositionstring“left”left, right
LoadingboolfalseShow loading state
DisabledboolfalseDisable button
FullWidthboolfalse100% width
OnClickEventCallbacknullClick handler

Form Components

TextInput

LABEL WITH INPUT                 ERROR STATE
┌────────────────────────────┐  ┌────────────────────────────┐
│ Email Address              │  │ Email Address              │
│ ┌────────────────────────┐ │  │ ┌────────────────────────┐ │
│ │ user@example.com       │ │  │ │ invalid-email          │ │
│ └────────────────────────┘ │  │ └────────────────────────┘ │
└────────────────────────────┘  │ Please enter a valid email │
                                └────────────────────────────┘

Select/Dropdown

CLOSED                          OPEN
┌────────────────────────────┐  ┌────────────────────────────┐
│ Select option          [v] │  │ Option One             [^] │
└────────────────────────────┘  ├────────────────────────────┤
                                │ Option One       [check]   │
                                │ Option Two                 │
                                │ Option Three               │
                                └────────────────────────────┘

Checkbox

UNCHECKED           CHECKED             INDETERMINATE
[ ] Option One      [x] Option Two      [-] Select All

Radio Button

UNSELECTED          SELECTED
( ) Option One      (o) Option Two

Dark Mode Considerations

Color Mapping

Light ModeDark Mode
#FFFFFF (white)#1E1E1E (dark surface)
#F5F5F5 (gray-100)#2D2D2D (elevated surface)
#212121 (text)#FFFFFF (text)
#757575 (secondary)#B0B0B0 (secondary)
#1976D2 (primary)#64B5F6 (lighter primary)

Dark Mode Tokens

:root[data-theme="dark"] {
    --color-background: #121212;
    --color-surface: #1E1E1E;
    --color-surface-elevated: #2D2D2D;
    --color-text-primary: #FFFFFF;
    --color-text-secondary: #B0B0B0;
    --color-text-disabled: #6B6B6B;
    --color-border: #3D3D3D;
    --color-primary: #64B5F6;
    --color-primary-dark: #90CAF9;
}

Component Adjustments

ComponentLightDark
CardsWhite bg, shadowDark surface, border
InputsWhite bg, gray borderDark bg, light border
BadgesColored bgReduced opacity bg
ButtonsStandardSlightly elevated

Accessibility Guidelines

Focus States

*:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}

/* High contrast mode */
@media (prefers-contrast: high) {
    *:focus-visible {
        outline-width: 3px;
    }
}

Color Contrast

RequirementRatioUsage
AA Normal4.5:1Body text
AA Large3:118px+ text
AAA Normal7:1Enhanced
AAA Large4.5:1Enhanced large

ARIA Labels

<!-- Button with icon only -->
<Button Icon="IconType.Search" aria-label="Search products" />

<!-- Loading state -->
<LoadingSpinner aria-label="Loading content" role="status" />

<!-- Badge with context -->
<StatusBadge Status="Error"
             aria-label="Order status: Error - requires attention" />

Summary

The Component Library provides:

  1. StatCard: Dashboard metrics with trends
  2. DataGrid: Sortable, filterable data tables
  3. StatusBadge: Color-coded status indicators
  4. SearchInput: Debounced search with autocomplete
  5. Modal: Overlay dialogs for forms and confirmations
  6. Toast: Non-blocking notifications
  7. LoadingSpinner: Loading state indicators
  8. EmptyState: Meaningful placeholders

All components follow:

  • Consistent design tokens
  • Responsive sizing
  • Dark mode support
  • Accessibility standards

Implementation complete. Ready for engineer review.