Creating your first extension
Learn how to create your first extension for Umbraco.
This guide will help you set up your first extension using vanilla JavaScript or Vite, Typescript, and Lit. It is also part of the prerequisites for Creating a Property Editor and Creating a Custom Dashboard tutorials.
By the end of this tutorial, we will have a extension up and running with a Web Component. This will be made with Vanilla JavaScript or made and set up with Vite, Typescript, and Lit.
If you want to set up an extension with Vite, Typescript, and Lit, you can skip the section "Extension with Vanilla JavaScript".
Extensions will go into a folder called
App_Plugins
. If you don't have this folder, you can create it at the root of your Umbraco project.We consider it best practice to use at least TypeScript and some kind of build tool to write your extensions. However, since Umbraco's extension system is written entirely in JavaScript, it's possible to create extensions with vanilla JavaScript. For the sake of posterity, we will briefly go through what that looks like:
- Go to the
App_Plugins
folder and create a new folder calledmy-package
- Navigate into the folder and create a file called
umbraco-package.json
, and paste the following code. This code sets up a basic package with a dashboard extension:
umbraco-package.json
1
{
2
"$schema": "../../umbraco-package-schema.json",
3
"name": "My.Package",
4
"version": "0.1.0",
5
"extensions": [
6
{
7
"type": "dashboard",
8
"alias": "my.custom.dashboard",
9
"name": "My Dashboard",
10
"js": "/App_Plugins/my-package/dashboard.js",
11
"weight": -1,
12
"meta": {
13
"label": "My Dashboard",
14
"pathname": "my-dashboard"
15
},
16
"conditions": [
17
{
18
"alias": "Umb.Condition.SectionAlias",
19
"match": "Umb.Section.Content"
20
}
21
]
22
}
23
]
24
}
Adding
$schema
to umbraco-package.json
will give you IntelliSense for this file to help you see different options for your package.- Next, create a new JavaScript file called
dashboard.js
and insert the following code:
dashboard.js
1
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
2
import { UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
3
4
const template = document.createElement('template');
5
template.innerHTML = `
6
<style>
7
:host {
8
padding: 20px;
9
display: block;
10
box-sizing: border-box;
11
}
12
</style>
13
14
<uui-box>
15
<h1>Welcome to my dashboard</h1>
16
<p>Example of vanilla JS code</p>
17
18
<uui-button label="Click me" id="clickMe" look="secondary"></uui-button>
19
</uui-box>
20
`;
21
22
export default class MyDashboardElement extends UmbElementMixin(HTMLElement) {
23
/** @type {import('@umbraco-cms/backoffice/notification').UmbNotificationContext} */
24
#notificationContext;
25
26
constructor() {
27
super();
28
this.attachShadow({ mode: 'open' });
29
this.shadowRoot.appendChild(template.content.cloneNode(true));
30
31
this.shadowRoot.getElementById('clickMe').addEventListener('click', this.onClick.bind(this));
32
33
this.consumeContext(UMB_NOTIFICATION_CONTEXT_TOKEN, (instance) => {
34
this.#notificationContext = instance;
35
});
36
}
37
38
onClick = () => {
39
this.#notificationContext?.peek('positive', { data: { headline: 'Hello' } });
40
};
41
}
42
43
customElements.define('my-custom-dashboard', MyDashboardElement);
Now we have a JavaScript file with a Web Component which gets linked to a Dashboard Extension as part of the Package Manifest JSON.
Press the F5 button in your favorite IDE or run
dotnet run
in a command line. Then you should be able to see the new dashboard show up in the Content section.Umbraco recommends building extensions with a setup using TypeScript and a build tool such as Vite. Umbraco uses the library Lit for building web components which we will be using throughout this guide.
Vite comes with a set of really good presets to get you quickly up and running with libraries and languages. Examples: Lit, Svelte, and vanilla Web Components with both JavaScript and TypeScript. We will use their preset of Lit and TypeScript.
Find a place where you want to keep your source files, this could be the App_Plugins folder in your Umbraco project. And paste the following command:
npm create vite@latest --template lit-ts my-extension
This sets up our new project in a folder named
my-extension
and creates a package.json
file, which includes the necessary packages. Navigate to the new project folder and install the packages using:npm install
The last thing we need to install now is our Backoffice package. You can install the package using the following command:
npm install -D @umbraco-cms/backoffice
If you see any errors during this process, make sure that you have the right tools installed (Node, .NET, and so on). Also, make sure you have followed the steps on how to Setup Your Development Environment.
Next, create a new file called
vite.config.ts
and insert the following code:import { defineConfig } from "vite";
export default defineConfig({
build: {
lib: {
entry: "src/my-element.ts", // your web component source file
formats: ["es"],
},
outDir: "dist", // your web component will be saved in this location
sourcemap: true,
rollupOptions: {
external: [/^@umbraco/],
},
},
});
This alters the Vite default output into a "library mode", where the output is a JavaScript file with the same name as the
name
attribute in package.json
. The name is my-extension
if you followed this tutorial with no changes.Navigate to
src/my-element.ts
, open the file and replace it with the following code:src/my-element.ts
1
import { LitElement, html, customElement } from "@umbraco-cms/backoffice/external/lit";
2
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
3
import { UmbNotificationContext, UMB_NOTIFICATION_CONTEXT_TOKEN } from '@umbraco-cms/backoffice/notification';
4
5
@customElement('my-element')
6
export default class MyElement extends UmbElementMixin(LitElement) {
7
#notificationContext?: UmbNotificationContext;
8
9
constructor() {
10
super();
11
this.consumeContext(UMB_NOTIFICATION_CONTEXT_TOKEN, (_instance) => {
12
this.#notificationContext = _instance;
13
});
14
}
15
16
#onClick = () => {
17
this.#notificationContext?.peek('positive', { data: { message: '#h5yr' } });
18
}
19
20
render() {
21
return html`
22
<uui-box headline="Welcome">
23
<p>A TypeScript Lit Dashboard</p>
24
<uui-button look="primary" label="Click me" @click=${this.#onClick}></uui-button>
25
</uui-box>
26
`;
27
}
28
}
29
30
declare global {
31
interface HTMLElementTagNameMap {
32
'my-element': MyElement;
33
}
34
}
The code above defines a Web Component that contains a button that when clicked will open a notification with a message to the user.
Next, we are going to build the
ts
file so we can use it in our package:npm run build
After running the build, you will see a new file in the
dist
folder with the name my-extension.js
. Copy this file and navigate to App_Plugins
in your Umbraco project, and create a new folder called my-package
. Here we are going to insert the copied file.Finally, add a file called
umbraco-package.json
the root of the foldermy-package
and insert the following code:umbraco-package.json
1
{
2
"$schema": "../../umbraco-package-schema.json",
3
"name": "My Package",
4
"version": "0.1.0",
5
"extensions": [
6
{
7
"type": "dashboard",
8
"alias": "My.Dashboard.MyExtension",
9
"name": "My Dashboard",
10
"js": "/App_Plugins/my-package/my-extension.js",
11
"weight": -1,
12
"meta": {
13
"label": "My Dashboard",
14
"pathname": "my-dashboard"
15
},
16
"conditions": [
17
{
18
"alias": "Umb.Condition.SectionAlias",
19
"match": "Umb.Section.Content"
20
}
21
]
22
}
23
]
24
}
Now we have a JavaScript file with a Web Component which gets linked to a Dashboard Extension as part of the Package Manifest JSON.
Press the F5 button in your favorite IDE or run
dotnet run
in a command line. Then you should be able to see the new dashboard show up in the Content section.