How can an "advanced" version of apackage extend the UI/options of a property editor from the "basic" verison?

I am building an Umbraco 17 package that will have a “basic” and “advanced” versions. The advanced version will depend on and install the basic version automatically.

The basic package provides:

  • a single custom property editor
  • a custom UI
  • a few built-in options in a drop-down list

Inside the property editor, the user selects an option in the DDL and the UI changes depending on the selected option.

The advanced package should extend this SAME property editor by adding more options to the DDL and their corresponding UI/fields.

I do want to make separate property editors or data types.

I would like the basic package to have one property editor whose available options and rendered UI can be extended by the advanced package.

My question is specifically about the TypeScript/backoffice side in Umbraco 17.

What is the recommended Umbraco-native way for one package to extend the options/UI of a property editor provided by another package?

Is sharing/extending state between backoffice entrypoints the normal approach here, or is there a better extension pattern in Umbraco 17 for this kind of plugin architecture?

hello @Eaglef90 :waving_hand:

This is exactly the kind of plugin architecture that Umbraco’s Extension Registry was designed to support.

The idiomatic approach here is to treat your DDL options as first-class extension points. In your basic package, instead of hardcoding the options array, define a custom extension type — something like my-package-option-provider — and have your property editor element query the registry for all registered providers at runtime:

const providers = umbExtensionsRegistry.getByType('my-package-option-provider');

your basic package then registers its own built-in options as manifests of that type. The advanced package simply registers additional manifests of the same type — no patching or monkey-patching of the basic package needed.

For the UI side, each option provider manifest can declare which element/component to render when that option is selected. Your property editor dynamically loads the matching element based on the current DDL value. This keeps the two packages fully decoupled.

This is essentially the same pattern Umbraco itself uses for sections, dashboards, and property editors

if you want the DDL to update reactively when providers are registered late (e.g. the advanced package loads after the property editor element is already connected), prefer byType() over getByType():

umbExtensionsRegistry.byType('my-package-option-provider')
  .subscribe(providers => { this._options = providers; });

byType() returns an Observable<T[]> and integrates cleanly with Lit’s UmbControllerBase, so your DDL will automatically re-render whenever a new provider manifest is registered — no manual polling needed.

Thanks for the information. Sorry I am late responding. My normal job has been horrible to me the past week and I have been very exhausted and not wanting to do anything past my normal 55 hour work week. I will look into the extension registry and give it a test.

1 Like