On this page ...

External Component Box Types

External components are fully supported

External components are a fully supported part of the editor framework. While compatibility with every third-party library cannot be guaranteed, the APIs described here are stable.

You can include UI components that are not native to Freon.
See External Components for an overview.

Using external components requires knowledge of the Freon Box Model.
This page documents the API for the various external-component box types.


Simple Additions

Simple additions have no link to the model (AST) and may appear anywhere in a projection.
They are still associated with the node whose projection they are placed in.

  • Syntax: [external=<ComponentName>] (no space after [).
  • The component name must be declared in the global section of the default editor.
  • Box type: SimpleExternalBox
  • Interface: (no specific API beyond common external props and findParam())

Example:

[external=AnimatedGif number="1"]

Fragment Wrappers

A fragment wrapper surrounds a single projection (the child box).
The childBox itself may be a vertical or horizontal layout containing many other boxes.

  • Syntax (positioning): [fragment <NAME> wrap=<ExternalComponent>]
  • Define wrapped content: Provide the fragment body in the fragment’s own bracketed section.
  • Box type: FragmentWrapperBox
  • Interface:
    • childBox: Box — the wrapped projection; render it with RenderComponent.

Example:

MyConcept {
    [
        Here is a fragment [fragment XX wrap=FB_Card]
    ]
    fragment XX [
        My First Card wrapping a property: ${self.isUnderConstruction}
        Great, isn't it!
    ]
}

Property Projections: Wrapping vs. Replacing

A property projection can be wrapped by an external component, or the external component can replace the native projection.
For replacers, you are responsible for reading/writing the property value and handling keyboard/tab behavior.

Wrapping Primitive Properties

  • Syntax: ${self.name wrap=FB_Dialog}
  • Box types: StringWrapperBox, NumberWrapperBox, BooleanWrapperBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): string | number | boolean — type depends on the wrapper box.
    • childBox: Box — the native projection for the property (or for the entire list if wrapping a list).

Wrapping Part List Properties

  • Syntax: ${self.parts wrap=FB_Accordion}
  • Box type: PartListWrapperBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNode[] — cast as needed.
    • childBox: Box — the native projection for the whole list (horizontal/vertical/table).

Wrapping Reference List Properties

  • Syntax: ${self.parts wrap=FB_Accordion}
  • Box type: RefListWrapperBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNodeReference[]
    • childBox: Box — the native projection for the whole list (horizontal/vertical/table).

Wrapping Part Properties

  • Syntax: ${self.part wrap=FB_Dialog}
  • Box type: PartWrapperBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNode — cast as needed.
    • childBox: Box — render with RenderComponent.

Wrapping Reference Properties

  • Syntax: ${self.reference wrap=FB_Dialog}
  • Box type: RefWrapperBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNodeReference
    • childBox: Box — render with RenderComponent.

Replacing Primitive Properties

  • Syntax: ${self.name replace=FB_Dialog}
  • Box types: StringReplacerBox, NumberReplacerBox, BooleanReplacerBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): string | number | boolean
    • setPropertyValue(newValue: string | number | boolean)

Replacing Part List Properties

  • Syntax: ${self.parts replace=FB_Accordion}
  • Box type: PartListReplacerBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNode[]
    • setPropertyValue(newValue: FreNode[])
    • children: Box[] — one box per list element.

Replacing Reference List Properties

  • Syntax: ${self.parts replace=FB_Accordion}
  • Box type: RefListReplacerBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNodeReference[]
    • setPropertyValue(newValue: FreNodeReference[])
    • children: Box[] — one box per list element.

Replacing Part Properties

  • Syntax: ${self.part replace=FB_Dialog}
  • Box type: PartReplacerBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNode
    • setPropertyValue(newValue: FreNode)

Replacing Reference Properties

  • Syntax: ${self.reference replace=FB_Dialog}
  • Box type: RefReplacerBox
  • Interface:
    • getPropertyName(): string
    • getPropertyValue(): FreNodeReference
    • setPropertyValue(newValue: FreNodeReference)

Wiring

  1. Create your Svelte components.
    Identify which box type your component will integrate with, and use that box’s interface to get/set model values.

  2. Declare components in the editor definition.
    Add names in the global section of the default editor (see Global Projections).

    Example:

    global {
        external {
            AnimatedGif,
            FB_Card,
            FB_Accordion,
            FB_Dialog,
            DatePicker
        }
    }
  3. Register components at runtime.
    Call setCustomComponents() from @freon4dsl/core-svelte before launching the app.
    Names must match those declared in step 2.

    Example:

    setCustomComponents([
       { component: ShowAnimatedGif,    knownAs: "AnimatedGif" },
       { component: FB_Card_Component,  knownAs: "FB_Card" },
       { component: FB_Accordion,       knownAs: "FB_Accordion" },
       { component: FB_Dialog,          knownAs: "FB_Dialog" },
       { component: DatePicker,         knownAs: "DatePicker" }
    ]);

External Component Parameters

You can pass parameters to an external component from the .edit file as simple key-value pairs (both strings).
All external-component box types provide:

  • findParam(key: string): string — returns the parameter value (if present).
© 2018 - 2025 Freon contributors - Freon is open source under the MIT License.