Custom Modals

New modals can be added to the system via the extension registry.

This article goes through adding new modals to the system. There are three steps to creating a custom modal:

  • Create a modal element

  • Declare an Extension Manifest

  • (Optional) Create a Modal Token

After completing these steps, refer to the example on how to open the modal.

Create a modal element

A modal element is a web component that is used to render a modal. It should implement the UmbModalExtensionElement interface. The modal context is injected into the element when the modal is opened in the modalContext property. The modal context is used to close the modal, update the value and submit the modal.

Additionally, the modal element can see its data parameters through the modalContext property. In this example, the modal data is of type MyModalData , and the modal value is of type MyModalValue. The modal context is of type UmbModalContext<MyModalData, MyModalValue>. We are using the data to render a headline and the value to update the value and submit the modal.

my-modal.element.ts
import { customElement, html, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbModalExtensionElement } from '@umbraco-cms/backoffice/modal';
import type { UmbModalContext } from '@umbraco-cms/backoffice/modal';
import type { MyModalData, MyModalValue } from './my-modal.token.js';

@customElement('my-dialog')
export class MyDialogElement
    extends UmbLitElement
    implements UmbModalExtensionElement<MyModalData, MyModalValue> {

    @property({ attribute: false })
    modalContext?: UmbModalContext<MyModalData, MyModalValue>;

    @property({ attribute: false })
    data?: MyModalData;

    private _handleCancel() {
        this.modalContext?.submit();
    }

    private _handleSubmit() {
        this.modalContext?.updateValue({ myData: 'hello world' });
        this.modalContext?.submit();
    }

    render() {
        return html`
            <div>
                <h1>${this.modalContext?.data.headline ?? 'Default headline'}</h1>
                <button @click=${this._handleCancel}>Cancel</button>
                <button @click=${this._handleSubmit}>Submit</button>
            </div>
        `;
    }
}

export const element = MyDialogElement;

The class must be exported as an element or default for the Extension Registry to be able to pick up the class.

Declare an Extension Manifest

The modal element needs to be registered in the extension registry. This is done by defining the modal in the manifest file. The element property should point to the file that contains the modal element.

{
    type: 'modal',
    alias: 'My.Modal',
    name: 'My Modal',
    element: '../path/to/my-modal.element.js'
}

Create a modal token

For type safety, it's recommended to use Modal Tokens. Using a Modal Token gives knowledge about the data that can be parsed to the Modal and as well as the type of the value coming back when submitted.

A Modal Token works as a constant that identifies the modal. It is used to open the modal and knows the types of the modal data and modal value. As well, it can contain a preset, containing default data and modal options.

The first argument passed to UmbModalToken is the extension alias; the second is the preset configuration.

import { UmbModalToken } from '@umbraco-cms/backoffice/modal';

export type MyModalData = {
    headline: string;
}

export type MyModalValue = {
    myData: string;
}

export const MY_MODAL_TOKEN = new UmbModalToken<MyModalData, MyModalValue>('My.Modal', {
    modal: {
        type: 'sidebar',
        size: 'small'
    }
});

A modal token is a generic type that takes two arguments(<MyModalData, MyModalValue>):

  • The first defines the type of data passed to the modal when opened.

  • The second defines the type of value returned when the modal is submitted.

Open the modal

To open the modal, call the umbOpenModal method with the Modal Token and data of choice:

my-element.ts
import { customElement, html } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; 
import { MY_MODAL_TOKEN } from './my-modal.token.js';
import { umbOpenModal } from '@umbraco-cms/backoffice/modal';

@customElement('my-element')
class MyElement extends UmbLitElement {

    override render() {
        return html`
            <uui-button look="primary" label="Open modal" @click=${this._openModal}></uui-button>
        `;
    }

    private async _openModal() {
        const returnedValue = await umbOpenModal(this, MY_MODAL_TOKEN, {
            data: {
                headline: "My modal headline",
            },
        }).catch(() => undefined);
    }
}

declare global {
    interface HTMLElementTagNameMap {
        'my-element': MyElement;
    }
}

The Promise of umbOpenModal is caught if it gets rejected. This is because if the Model gets closed without submission, the Promise is rejected. YThis can be used to carry out a certain action if the modal is cancelled. In this case, undefined is returned when the Modal is cancelled (rejected).

Last updated

Was this helpful?