Widget vs Module Taxonomy - Decision Matrix

Comprehensive guidelines for classifying components as widgets or modules

🏷️ Widget vs Module Taxonomy - Decision Matrix

Last Updated: November 14, 2025
Status: 🎯 ACTIVE GUIDELINES
Purpose: Clear, actionable criteria for component classification


🎯 CORE PRINCIPLE

Widget (Pure UI + I/O Contract) + Functionality (Flows/Logic/State) = Module (Reusable System)

Philosophy: Start simple (widget), promote when complexity requires it (module).


πŸ“Š DECISION MATRIX

Quick Reference Table

Component Start As Promote When Example Progression
Input Field Widget + Validation flow gg-input β†’ validated-input-module
Select Dropdown Widget + Data source API gg-select β†’ data-select-module
Button Widget + Multi-step flow gg-button β†’ action-button-module
Card Widget + Contains modules gg-card β†’ module-card-container
Badge Widget Never (pure UI) gg-badge (stays widget)
Icon Widget Never (pure UI) gg-icon (stays widget)
Modal Module Always modal-module (immediate)
Sidebar Module Always sidebar-nav-module (immediate)
Navigation Module Always top-nav-module (immediate)
Data Grid Module Always data-grid-module (immediate)
Form (simple) Widget + Validation logic gg-form β†’ smart-form-module
Form (multi-step) Module Always wizard-form-module (immediate)
Chart Widget + Live data source gg-chart β†’ live-chart-module
Calendar Widget + Event management gg-calendar β†’ event-calendar-module

πŸ” CLASSIFICATION CRITERIA

Widget Definition

A widget is:

Widget Characteristics:

@Component({
  selector: 'gg-input',
  standalone: true,
  template: '<input [value]="value" (input)="valueChange.emit($event.target.value)" />',
  inputs: ['value', 'placeholder', 'disabled', 'type'],
  outputs: ['valueChange', 'blur', 'focus']
})
export class GgInputWidget {
  // Pure UI logic only
  // No business logic
  // No API calls
  // No complex state
}

Module Definition

A module is:

Module Characteristics:

@Component({
  selector: 'lib-validated-input',
  standalone: true,
  template: `
    <gg-input [value]="value()" (valueChange)="onChange($event)"></gg-input>
    <div *ngIf="error()">{{ error() }}</div>
  `
})
export class ValidatedInputModule implements BrowserModuleContract {
  readonly manifest: ModuleManifest = {
    id: 'validated-input',
    name: 'Validated Input',
    type: 'feature',
    actions: ['validate', 'reset', 'getValue'],
    flows: ['validation-flow']
  };
  
  // Business logic
  async validate(): Promise<boolean> { /* ... */ }
  
  // Flow integration
  private attachedFlows: string[] = [];
  
  // Complex state
  private validationState = signal<ValidationState>({ /* ... */ });
}

🚦 PROMOTION TRIGGERS

Automatic Promotion (Any of these β†’ Module)

  1. Singularity Integration ⚑

    // Widget with attached flow = Module
    if (component.hasAttachedFlows) {
      classify = 'module';
    }
    
  2. Routing πŸ—ΊοΈ

    // Component with routes = Module
    if (component.hasRoutes) {
      classify = 'module';
    }
    
  3. Child Modules 🧩

    // Component containing modules = Module
    if (component.containsModules) {
      classify = 'module';
    }
    
  4. Backend Integration 🌐

    // Component making API calls = Module
    if (component.hasApiCalls) {
      classify = 'module';
    }
    
  5. Complex State πŸ’Ύ

    // Component with persistence/sync = Module
    if (component.usesStorage || component.hasFlashState) {
      classify = 'module';
    }
    
  6. Lifecycle Logic πŸ”„

    // Component with business logic in lifecycle = Module
    if (component.hasBusinessLogicInLifecycle) {
      classify = 'module';
    }
    

Manual Promotion (Architectural Decision)

  1. Strategic Importance - Core platform capability
  2. Reusability Across Universes - Used in multiple projects
  3. Marketplace Potential - Could be sold/shared
  4. Team Collaboration - Multiple developers need to extend

πŸ“ STORAGE STRUCTURE

Widget Storage

Location: libs/libs-ui/ or libs/widgets/

libs/
β”œβ”€β”€ libs-ui/
β”‚   β”œβ”€β”€ gg-input/
β”‚   β”œβ”€β”€ gg-button/
β”‚   β”œβ”€β”€ gg-select/
β”‚   β”œβ”€β”€ gg-card/
β”‚   └── gg-badge/
β”‚
└── widgets/
    β”œβ”€β”€ chart-widget/
    β”œβ”€β”€ calendar-widget/
    └── table-widget/

Characteristics:

Module Storage

Location: libs/libs-structural/ or libs/libs-module-features/

libs/
β”œβ”€β”€ libs-structural/
β”‚   β”œβ”€β”€ sidebar-nav-lib/
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   └── sidebar-nav.manifest.ts  ← Has manifest
β”‚   β”‚
β”‚   β”œβ”€β”€ modal-system-lib/
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   └── modal.manifest.ts
β”‚   β”‚
β”‚   └── data-grid-lib/
β”‚       β”œβ”€β”€ src/
β”‚       └── data-grid.manifest.ts
β”‚
└── libs-module-features/
    β”œβ”€β”€ validated-input-lib/
    β”‚   β”œβ”€β”€ src/
    β”‚   └── validated-input.manifest.ts
    β”‚
    └── smart-form-lib/
        β”œβ”€β”€ src/
        └── smart-form.manifest.ts

Characteristics:


πŸ”„ PROMOTION WORKFLOW

Step 1: Identify Promotion Need

// Widget starts simple
@Component({
  selector: 'gg-input'
})
export class GgInputWidget { }

// Developer adds validation logic
this.validationService.validate(value);

// 🚨 PROMOTION TRIGGER: Business logic added!

Step 2: Create Module Version

# Create new NX library
nx generate @nx/angular:library validated-input-lib \
  --directory=libs/libs-module-features \
  --standalone

# Move widget code
# Add manifest
# Add business logic
# Register with ModuleRegistry

Step 3: Implement Module Contract

@Component({
  selector: 'lib-validated-input',
  standalone: true
})
export class ValidatedInputModule implements BrowserModuleContract {
  
  // Required: Module ID
  readonly moduleId = 'validated-input';
  
  // Required: Manifest
  readonly manifest: ModuleManifest = {
    id: 'validated-input',
    name: 'Validated Input Field',
    type: 'feature',
    category: 'Form Components',
    version: '1.0.0',
    author: 'GoGrab Team',
    
    // What this module can do
    actions: [
      'validate',
      'getValue',
      'setValue',
      'reset'
    ],
    
    // Attached flows
    flows: ['validation-flow'],
    
    // Access control
    access: {
      visibility: 'public',
      audience: 'space-builder',
      showInBrowser: true,
      showInSelector: true
    }
  };
  
  // Lifecycle methods
  async initialize(): Promise<void> { }
  async start(): Promise<void> { }
  async stop(): Promise<void> { }
  async destroy(): Promise<void> { }
  
  // Public actions
  async validate(): Promise<boolean> { }
  async getValue(): Promise<any> { }
  async setValue(value: any): Promise<void> { }
  async reset(): Promise<void> { }
}

Step 4: Register Module

// In manifest file or module decorator
@ModuleDecorator({
  id: 'validated-input',
  name: 'Validated Input',
  type: 'feature'
})
export class ValidatedInputModule { }

// Auto-registers with ModuleRegistry on app init

Step 5: Deprecate Widget (Optional)

// Mark widget as deprecated
@Component({
  selector: 'gg-input',
  /**
   * @deprecated Use ValidatedInputModule instead
   * @see libs/libs-module-features/validated-input-lib
   */
})
export class GgInputWidget { }

πŸ“‹ CLASSIFICATION EXAMPLES

Example 1: Input Field Progression

Stage 1: Simple Widget

@Component({ selector: 'gg-input' })
export class GgInputWidget {
  @Input() value: string = '';
  @Input() placeholder: string = '';
  @Output() valueChange = new EventEmitter<string>();
}
// Classification: WIDGET βœ…

Stage 2: With Validation (Promotion Trigger)

export class GgInputWidget {
  @Input() value: string = '';
  @Input() validators: ValidatorFn[] = [];
  
  validate() {
    // Business logic added!
    return this.validators.every(v => v(this.value));
  }
}
// Classification: Should be MODULE ⚠️

Stage 3: As Module

@Component({ selector: 'lib-validated-input' })
export class ValidatedInputModule implements BrowserModuleContract {
  manifest: ModuleManifest = { /* ... */ };
  
  async validate(): Promise<boolean> {
    // Use singularity flow
    return await this.flowExecutor.execute('validation-flow', { value });
  }
}
// Classification: MODULE βœ…

Example 2: Data Grid

Always a Module (Complex state + API + Pagination)

@Component({ selector: 'lib-data-grid' })
export class DataGridModule implements BrowserModuleContract {
  manifest: ModuleManifest = {
    id: 'data-grid',
    type: 'feature',
    actions: ['load', 'sort', 'filter', 'export']
  };
  
  // API integration
  async loadData(endpoint: string) { }
  
  // State management
  private dataState = signal<GridState>({ /* ... */ });
  
  // Pagination logic
  async changePage(page: number) { }
}
// Classification: MODULE βœ… (Always)

Example 3: Modal System

Always a Module (Lifecycle + Overlay + State)

@Component({ selector: 'lib-modal' })
export class ModalModule implements BrowserModuleContract {
  manifest: ModuleManifest = {
    id: 'modal-system',
    type: 'layout',
    actions: ['open', 'close', 'confirm']
  };
  
  // Lifecycle management
  async open() { }
  async close() { }
  
  // Complex interactions
  async confirm(): Promise<boolean> { }
}
// Classification: MODULE βœ… (Always)

🎨 UI LIBRARY AUDIT

Current libs/libs-ui/ Inventory

Pure Widgets (Keep as Widgets):

βœ… gg-button - Pure UI
βœ… gg-input - Pure UI
βœ… gg-select - Pure UI
βœ… gg-badge - Pure UI
βœ… gg-chip - Pure UI
βœ… gg-icon - Pure UI
βœ… gg-avatar - Pure UI
βœ… gg-spinner - Pure UI
βœ… gg-tooltip - Pure UI
βœ… gg-divider - Pure UI

Candidates for Promotion:

⚠️ gg-form β†’ smart-form-module (if validation added)
⚠️ gg-table β†’ data-grid-module (if pagination/sort added)
⚠️ gg-chart β†’ live-chart-module (if live data added)
⚠️ gg-calendar β†’ event-calendar-module (if events added)
⚠️ gg-dropdown-menu β†’ menu-module (if navigation added)
⚠️ gg-tab-group β†’ tab-module (if routing added)

Already Modules (Move to libs-structural):

πŸ”„ gg-modal β†’ modal-system-lib
πŸ”„ gg-sidebar β†’ sidebar-nav-lib (already done βœ…)
πŸ”„ gg-navigation β†’ navigation-module-lib
πŸ”„ gg-panel β†’ panel-module-lib

πŸš€ IMPLEMENTATION STRATEGY

Phase 1: Classification (Week 1)

Phase 2: Promote Critical Components (Week 2)

Phase 3: Create Widget-Builder (Week 3)

Phase 4: Documentation (Week 4)


πŸ“Š SUCCESS METRICS

Classification Clarity

Technical Implementation

Developer Experience


πŸ“š RELATED DOCUMENTS


Status: βœ… GUIDELINES COMPLETE
Next Action: Begin component classification audit
Owner: Development Team + UX Team
Last Updated: November 14, 2025