Creating your own UI extension points in Umbraco v14 - Part 2: Extension Slots

2 min read

In our first post in this series, we looked at the basics of setting up our “quick actions” section for our UI.

Quick Action Buttons

In that post we manually fetched and observed the extensions registry for quick action definitions and then rendered out our button elements individually.

In this post we’ll take a look at how we can do without this repetitive manual setup and make use of some other manifest extension points.

Componentization

Lets start by moving our quick action button to it’s own component.

@customElement("quick-action")
export class QuickActionElement extends UmbElementMixin(LitElement) {

    @property({ type: Object, attribute: false })
    manifest!: ManifestQuickAction;

    render() {
        return html`<uui-button 
                look=${this.manifest.meta.look ?? 'secondary'}
                @click=${() => console.log(this.manifest.meta.label)}>
                ${this.manifest.meta.label}
           </uui-button>`
    }
}

export default QuickActionElement;

declare global {
    interface HTMLElementTagNameMap {
        "quick-action": QuickActionElement;
    }
}

This should be a relatively familiar setup for creating a web component. The only “special” thing here is the manifest property which accepts a copy of the manifest definition for the given quick action that this instance of the component is rendering.

Component registration

For the time being, we need to make our component definition globally accessible and so to do this we need to export it in our root level index.ts file.

export * from "./components/quick-action.element.ts";

We’ll handle this better in a future blog post, but for now, this is the simplest way to make our component easily instantiatable.

Rendering

Now we can update our workspace component, removing all the code we wrote in our constructor, and getting rid of the state variable that held out quick action definitions and we can instead make use of a helper component that will take care of all of this for us.

Update your render function as follows:

render() {
   return html`<uui-box headline="Actions">
       <umb-extension-slot 
           type="quickAction"
           default-element="quick-action-button">
       </umb-extension-slot>
   </uui-box>`
}

So now, instead of us manually fetching our definitions, the umb-extension-slot will do the manifests lookup for us. It will fetch all manifests of the defined type and render each one using our quick-action-button element, as defined by the default-element attribute (this is why we needed to register our component globally for now, as it has to be referenced by name).

In addition, each instantiated element will also have the given manifest automatically injecting into its manifest property, allowing it to configure it’s behavior accordingly.

What’s next?

In this post we’ve componentized our quick actions, and made use of the umb-extension-slot to save us having to write a bunch of repetitive code.

Effectively though are buttons are still tied to a single implementation so in the next post we’ll take a look at how we can make the buttons click handler customizable.

Until then 👋