Custom UI Components
Source-backed guide to customizing Elsa Studio input editors in release 3.8.0 using backend UI hints, property UI handlers, and Studio UI hint handlers.
This guide is based on release/3.8.0 in elsa-core and elsa-studio.
Custom activity editors in Elsa 3.8.0 are built in two layers:
Your activity declares a
UIHintand optionalUIHandlermetadata on the backend.Elsa Studio resolves that metadata to a Studio-side
IUIHintHandlerthat renders the editor component.
Use this guide when you need a custom input editor for an activity property. If you only need to add UI around an existing editor, use Field Extensions instead.
The Customization Model
elsa-core and elsa-studio each have an IUIHintHandler, but they do different jobs:
In
elsa-core,IUIHintHandlermaps a UI hint string such asdropdownorjson-editorto one or more backendIPropertyUIHandlertypes that provide UI metadata.In
elsa-studio,IUIHintHandleris the rendering contract. Studio asksIUIHintServicefor the first handler whoseGetSupportsUIHint(string uiHint)returnstrue, then callsDisplayInputEditor(DisplayInputEditorContext context).
That means a working custom editor usually needs both sides:
a backend activity descriptor with the right
UIHinta Studio handler that knows how to render that hint
When To Use Each Extension Point
Use UIHint when you need a different editor type.
Use UIHandler or UIHandlers when you want to keep an existing editor type but supply metadata such as options, adornments, editor height, or refresh behavior.
Use a Studio IUIHintHandler when Studio needs to render a brand-new editor for a hint string that the default handler set does not support.
Use a Studio IUIFieldExtensionHandler when you want to decorate an existing editor instead of replacing it.
How The Pieces Fit Together
For a typical activity input, the flow is:
ActivityDescriberinspects your[Input]attribute.It sets the input descriptor's
UIHint.PropertyUIHandlerResolvercollects any explicitUIHandlerorUIHandlers, then adds default metadata handlers associated with the chosen backend UI hint.The resulting UI metadata is stored in
InputDescriptor.UISpecifications.Studio loads the activity descriptor, looks up a Studio
IUIHintHandler, and renders the editor in the workflow inspector.If the metadata contains
"Refresh": true, Studio posts to/descriptors/activities/{activityTypeName}/options/{propertyName}to recompute UI metadata with the current input values as context.
This split is important: backend code decides what metadata an input has, but Studio code decides how that input is rendered.
Step 1: Mark The Activity Input
Start by assigning a UI hint on the activity:
If your goal is only to customize a built-in editor, keep a built-in hint and attach a property UI handler instead:
That pattern is used throughout the release branch for inputs such as:
HTTP endpoint paths
dispatcher channel selection
SQL client selection
Kafka producer and consumer selection
Step 2: Add Backend UI Metadata When Needed
Backend IPropertyUIHandler implementations provide the metadata that Studio editors consume.
For example, a dropdown options provider can inherit DropDownOptionsProviderBase:
If the available options depend on other inputs, override RefreshOnChange in one of these base classes:
DropDownOptionsProviderBaseCheckListOptionsProviderBaseRadioListOptionsProviderBase
When RefreshOnChange returns true, the backend includes "Refresh": true in the UI metadata and Studio refreshes the descriptor options through the activity descriptor options endpoint.
Step 3: Render The Custom Hint In Studio
If you introduce a new hint string such as custom-email-input, Studio must also know how to render it.
Implement Elsa.Studio.Contracts.IUIHintHandler:
Register it with DI:
Studio resolves the first handler whose GetSupportsUIHint method matches the hint. If none matches, DefaultUIHintService falls back to UnsupportedUIHintHandler. If you are overriding a built-in hint, registration order matters because the first matching handler wins.
Step 4: Build The Editor Component
Studio editor components receive a DisplayInputEditorContext.
For literal string input, a component typically reads the current value with GetLiteralValueOrDefault() and writes changes with UpdateValueOrLiteralExpressionAsync(...):
The same context also supports:
GetValueOrDefault<T>()GetObjectValueOrDefault()GetExpressionValueOrDefault()UpdateValueAsync(...)UpdateExpressionAsync(...)UpdateValueOrObjectExpressionAsync(...)
Those helpers matter because many activity inputs are wrapped as Input<T>, not plain values.
Built-In Studio Handlers In 3.8.0
AddDefaultUIHintHandlers() in elsa-studio registers handlers for:
singlelinecheckboxchecklistdictionarymultitextmultilinedropdowncode-editorexpression-editorjson-editorswitch-editorhttp-status-codesvariable-pickerinput-pickertype-pickerworkflow-definition-pickeroutput-pickerradiolistoutcome-pickerdynamic-outcomesdatetime-picker
The secrets module also adds a secret-picker Studio handler.
If you can express your requirement with one of those hints plus backend metadata, that is usually simpler than inventing a brand-new hint.
Field Extensions Versus Custom Editors
Field extensions are Studio-only decorations around existing editors. They implement IUIFieldExtensionHandler and are registered with:
Choose a field extension when you want to add helper UI, warnings, buttons, or toolbars around an existing input component. Choose a custom UI hint handler when the editor itself needs to change.
Custom Elements Are A Different Feature
The custom-elements host is for embedding Elsa Studio surfaces in another application. It does not register input editors.
The Elsa.Studio.Host.CustomElements host registers these elements in release/3.8.0:
elsa-backend-providerelsa-workflow-definition-editorelsa-workflow-instance-viewerelsa-workflow-instance-listelsa-workflow-definition-list
The React wrapper forwards remote-endpoint, api-key, and access-token attributes to elsa-backend-provider. Use that model for embedding Studio. Use IUIHintHandler when you want to change how an activity input is edited inside Studio.
Practical Guidance
Start with a built-in UI hint before introducing a custom one.
Use backend
UIHandlermetadata providers for options, adornments, and editor configuration.Add a Studio
IUIHintHandleronly when the built-in handlers cannot render the experience you need.Keep the backend and Studio halves aligned. A custom hint string is not enough on its own.
Prefer field extensions when you are augmenting, not replacing, an existing editor.
Related Reading
Last updated