CUSTOM WIDGET GUIDE
Ecosistema completo para organización y gestión de contenido con interfaces espaciales
Custom Widget Creation Guide
🚀 Widget Builder: Create Reusable Widgets
The Widget Builder is your visual tool for creating custom, reusable widgets that can be used across your entire platform.
📍 Where to Find the Widget Builder
Route
/space/{spaceSlug}/editor/widget-builder
From Landing Editor
Navigate to:
http://localhost:5200/space/space-{id}/editor/widget-builder
From Editor Navigation
- Go to the Editor landing page
- Click the widget builder option (if available in nav)
- Or directly navigate to the route above
🎨 Widget Builder Features
1. Design Panel
Visually design your widget's appearance and structure
2. Inputs Panel
Configure widget inputs (properties/parameters):
- Name & Type (string, number, boolean, object, array)
- Description
- Required/Optional
- Default values
- Validation rules
3. Theme Integration Panel
Map widget properties to theme variables:
- Background Color →
--theme-surface,--theme-primary, etc. - Text Color →
--theme-text-primary,--theme-text-secondary - Border Color →
--theme-border,--theme-primary
This makes your widget automatically adapt to theme changes!
4. Preview Panel
Test your widget across breakpoints:
- 📱 Mobile (375px)
- 📱 Tablet (768px)
- 💻 Desktop (1920px)
5. Export Panel
Three export options:
- Standalone Component: Single
.tsfile - NX Library: Full library structure
- Widget Registry: Register for platform-wide use
🛠️ Creating a Custom Widget
Step 1: Start from Template or Blank
Widget Templates Available:
// Button Widget
{ id: 'button', name: 'Custom Button', icon: 'hand-pointer' }
// Card Widget
{ id: 'card', name: 'Info Card', icon: 'id-card' }
// Form Widget
{ id: 'form', name: 'Form Builder', icon: 'wpforms' }
// Chart Widget
{ id: 'chart', name: 'Chart Widget', icon: 'chart-line' }
// List Widget
{ id: 'list', name: 'Dynamic List', icon: 'list' }
// Image Gallery Widget
{ id: 'gallery', name: 'Image Gallery', icon: 'images' }
Or click "Create Blank Widget" to start from scratch.
Step 2: Define Inputs
Click "Add Input" in the Inputs panel:
// Example: Button Widget Inputs
{
name: 'label',
type: 'string',
description: 'Button text',
required: true,
defaultValue: 'Click me'
}
{
name: 'variant',
type: 'string',
description: 'Button style variant',
required: false,
defaultValue: 'primary',
options: ['primary', 'secondary', 'danger', 'success']
}
{
name: 'disabled',
type: 'boolean',
description: 'Disable button',
required: false,
defaultValue: false
}
{
name: 'icon',
type: 'string',
description: 'Icon class (e.g., fas fa-check)',
required: false
}
Step 3: Define Outputs (Events)
Click "Add Output" for widget events:
// Example: Button Widget Outputs
{
name: 'onClick',
type: 'event',
description: 'Fired when button is clicked'
}
{
name: 'onHover',
type: 'event',
description: 'Fired when button is hovered'
}
Step 4: Theme Integration
Map widget styles to theme variables:
Background Color → --theme-primary
Text Color → --theme-text-primary
Border Color → --theme-border
This ensures your widget respects the active theme!
Step 5: Generate Code
Click "Generate Code" to see the Angular component code:
@Component({
selector: 'custom-button',
standalone: true,
template: `
<button
[class]="'btn btn-' + variant()"
[disabled]="disabled()"
(click)="handleClick()">
@if (icon()) {
<i [class]="icon()"></i>
}
{{ label() }}
</button>
`,
styles: [`
.btn {
background: var(--theme-primary);
color: var(--theme-text-primary);
border: 1px solid var(--theme-border);
}
`]
})
export class CustomButtonWidget {
// Inputs
label = input<string>('Click me');
variant = input<string>('primary');
disabled = input<boolean>(false);
icon = input<string | null>(null);
// Outputs
onClick = output<void>();
onHover = output<void>();
handleClick() {
if (!this.disabled()) {
this.onClick.emit();
}
}
}
Step 6: Save to Registry
Click "Save to Registry" to make your widget available platform-wide!
📊 Widget Registration Flow
Widget Builder
↓
Generate Code
↓
Save to Registry (WidgetRegistryService)
↓
Widget Metadata Stored (Flash Persistence)
↓
Widget Available in Editor Palette
↓
Widget appears in EditorService.widgetCategories
↓
Users can drag-and-drop your widget!
🔧 Widget Registry Service
The WidgetRegistryService manages all registered widgets:
Storage Key
flash:widget-registry-state
Registered Widget Structure
{
"widget-123": {
"id": "widget-123",
"name": "Custom Button",
"category": "custom",
"isPublic": true,
"tags": ["custom", "button", "interactive"],
"metadata": {
"createdAt": "2025-01-01T00:00:00Z",
"updatedAt": "2025-01-01T00:00:00Z",
"version": "1.0.0",
"author": "Widget Builder"
},
"inputs": [...],
"outputs": [...],
"themeVariables": {...},
"html": "...",
"typescript": "..."
}
}
🎯 Export Options Explained
1. Standalone Component (Quick & Simple)
- Generates a single
.component.tsfile - Perfect for one-off custom widgets
- Copy-paste into your project
- Manually import where needed
Use when: Creating a widget for a specific feature
2. NX Library (Enterprise-Ready)
- Full NX library structure with:
- Component file
- Template file
- Styles file
- Unit tests
- Barrel exports
- README
- Publishable to npm
- Versionable and maintainable
Use when: Creating reusable widgets for the team
3. Widget Registry (Platform-Wide)
- Saves to Flash Persistence
- Immediately available in all editors
- No import needed
- Discoverable in widget palette
Use when: You want instant platform-wide availability
🧩 Using Your Custom Widget
After Registration
Your widget becomes available in the Editor:
- Editor Palette: Appears in the "Custom" category
- Drag & Drop: Users can drag it onto the canvas
- Properties Panel: All inputs appear as editable properties
- Events Panel: All outputs appear as bindable events
Widget Appears Here
// In EditorService.widgetCategories computed signal
{
name: 'Personalizados',
types: [
...
'custom-button', // ← Your widget!
...
]
}
📝 Best Practices
1. Clear Naming
- Widget Name: Descriptive and unique (e.g., "CTA Button", "Hero Card")
- Input Names: Follow camelCase (e.g.,
buttonLabel,imageUrl) - Output Names: Start with "on" (e.g.,
onClick,onSubmit)
2. Comprehensive Inputs
- Always provide defaults
- Add descriptions for clarity
- Mark required vs. optional
- Use enums for fixed options
3. Theme Variables
- Map ALL colors to theme variables
- Use semantic names (primary, secondary, surface)
- Test in both light and dark themes
4. Responsive Design
- Test on all breakpoints
- Use responsive units (
rem,%,vw/vh) - Consider mobile-first approach
5. Documentation
- Add descriptions to all inputs/outputs
- Include usage examples
- Document theme variable mappings
🔄 Workflow Example
Creating a "Product Card" Widget
Navigate to Widget Builder
/space/my-space/editor/widget-builderClick "Card" Template
- Starts with basic card structure
Define Inputs
productName(string, required)price(number, required)imageUrl(string, required)description(string, optional)inStock(boolean, default: true)
Define Outputs
onAddToCart(event)onViewDetails(event)
Theme Integration
- Card background →
--theme-surface - Text →
--theme-text-primary - Price →
--theme-primary - Border →
--theme-border
- Card background →
Preview
- Test on mobile, tablet, desktop
- Adjust spacing/sizing
Generate Code
- Review the generated Angular component
- Tweak if needed
Save to Registry
- Widget is now platform-wide!
- Available in ALL editors
Use in Editor
- Open any page in Editor
- Find "Product Card" in Custom widgets
- Drag onto canvas
- Configure properties
- Bind
onAddToCartevent to actions
🚀 Next Steps
After creating your widget:
- Test Thoroughly: Use it in real pages
- Get Feedback: Share with team
- Iterate: Improve based on usage
- Version: Update when adding features
- Document: Write usage guides
- Share: Export as NX lib for other projects
🎨 Advanced: Custom Widget Templates
You can create widget templates for common patterns:
Template Structure
{
id: 'my-template',
name: 'My Custom Template',
description: 'Template for X use case',
icon: 'magic',
category: 'custom',
baseStructure: {
html: '<div class="template">...</div>',
typescript: '// Template logic',
styles: '.template { ... }',
inputs: [...],
outputs: [...]
}
}
Add templates in:
libs/editor-web-lib/src/lib/components/widget-builder/widget-builder.component.ts
📚 Related Documentation
- Editor Persistence Flow
- Module Builder Guide
- Widget Registry API (to be documented)
- Theme System (to be documented)
🎯 Quick Reference
| Feature | Location | Storage Key |
|---|---|---|
| Widget Builder | /editor/widget-builder |
- |
| Widget Registry | WidgetRegistryService |
flash:widget-registry-state |
| Current Widget | WidgetBuilderService |
flash:widget-builder-state |
| Editor Palette | EditorService |
flash:editor-state |
Happy Widget Building! 🎨✨