Embeddable Quick Reference

Quick reference guide for creating and registering embeddable components

⚡ Embeddable Quick Reference

TL;DR

// The architecture extends canonical ModuleEmbeddableComponent for visual editing
import { EmbeddableRegistryService, EmbeddableDefinition } from '@libs-widgets/widgets';
import { ModuleEmbeddableComponent, ComponentRegistryService } from '@libs-core/module-base';

// Visual Editor → Use EmbeddableRegistryService
const registry = inject(EmbeddableRegistryService);

// Pure Module Operations → Use ComponentRegistryService  
const moduleRegistry = inject(ComponentRegistryService);

Registering a Built-in Widget

// libs/libs-widgets/widgets/src/lib/registry/widget-registry-init.ts
embeddableRegistry.register({
  id: 'builtin-button',
  name: 'Button',
  description: 'Interactive button component',
  category: 'forms',
  icon: 'smart_button',
  component: ButtonWidgetComponent,
  source: 'builtin',
  inputs: [
    {
      name: 'label',
      type: 'string',
      label: 'Button Label',
      defaultValue: 'Click me',
      group: 'content',
      order: 1,
    },
    {
      name: 'variant',
      type: 'select',
      label: 'Style',
      defaultValue: 'primary',
      options: [
        { value: 'primary', label: 'Primary' },
        { value: 'secondary', label: 'Secondary' },
        { value: 'outline', label: 'Outline' },
      ],
      group: 'appearance',
      order: 1,
    },
  ],
  outputs: [
    { name: 'clicked', label: 'On Click', payloadType: 'MouseEvent' },
  ],
  variants: [
    { id: 'primary', name: 'Primary', description: 'Main CTA', inputOverrides: { variant: 'primary' } },
    { id: 'outline', name: 'Outline', description: 'Transparent', inputOverrides: { variant: 'outline' } },
  ],
});

Registering a libs-ui Component

// libs/libs-ui/ux-button/src/lib/embeddables/button.embeddable.ts
import { UiComponentConfig } from '@libs-ui/ux-ui-core';

export const BUTTON_EMBEDDABLE: UiComponentConfig = {
  id: 'button',          // Will become 'ui-button'
  name: 'UX Button',
  description: 'Advanced button with themes',
  category: 'forms',
  icon: 'smart_button',
  component: UxButtonComponent,
  inputs: [/* ... */],
  outputs: [/* ... */],
  variants: [/* ... */],
};

// Then add to initializer
// libs/libs-ui/ux-ui-core/src/lib/initializers/ui-components-registry.initializer.ts
const UI_EMBEDDABLES = [BUTTON_EMBEDDABLE, /* ... */];

Module Embeddables (Canonical)

// In module manifest
const manifest: ModuleManifest = {
  id: 'my-module',
  embeddableComponents: [{
    id: 'my-widget',
    componentType: MyWidgetComponent,
    displayName: 'My Widget',
    category: 'widget',
    inputs: [
      {
        name: 'title',
        type: 'string',
        required: true,
        description: 'Widget title',
        uiHints: { label: 'Title', placeholder: 'Enter title' },
      },
    ],
  }],
};

// Automatically bridged to EmbeddableRegistryService via ComponentRegistryService

Input Definition Cheat Sheet

Property Type Required Description
name string ✅ @Input() property name
type EmbeddableInputType ✅ 'string' | 'number' | 'boolean' | 'color' | 'select' | 'textarea' | 'object' | 'array'
label string ✅ Human-readable label
defaultValue unknown ✅ Default value
description string Tooltip text
options {value, label}[] For select type
group string Property panel group (e.g., 'appearance', 'content')
order number Sort order within group
responsive boolean Supports per-breakpoint values
min, max, step number Number constraints
required boolean Validation flag

Variant Definition

{
  id: 'email-input',           // Unique ID
  name: 'Email Input',         // Display name in palette
  description: 'Pre-configured for email', 
  inputOverrides: {            // Property overrides
    type: 'email',
    placeholder: 'Enter email',
    icon: 'email',
  },
  thumbnail: 'url-to-preview', // Optional preview image
}

Common Tasks

Get Widget by ID

const widget = registry.get('builtin-button');

Get All Form Widgets

const formWidgets = registry.getByCategory('forms');

Search Widgets

const results = registry.search('button');

Generate Property Panel

const propertyGroups = registry.generatePropertyGroups('builtin-button');

Get Module Embeddables

const moduleWidgets = registry.getBySource('module');

Architecture Relationship

ModuleEmbeddableComponent (canonical)
        ↓ extends
EmbeddableDefinition (visual editor)
        ↓ stored in
EmbeddableRegistryService (unified)
        ↑ bridges
ComponentRegistryService (module components)

Key: Visual editor features extend the canonical module-base architecture without breaking compatibility.


See Also: Widget System Architecture