umbraco-example-generator

Umbraco Example Generator

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "umbraco-example-generator" with this command: npx skills add umbraco/umbraco-cms-backoffice-skills/umbraco-umbraco-cms-backoffice-skills-umbraco-example-generator

Umbraco Example Generator

Generate complete, testable example extensions for the Umbraco backoffice and run them using the Umbraco source's dev infrastructure.

When to Use

  • Creating demonstration extensions

  • Building testable extension examples

  • Rapid development with hot reload

  • Testing extensions without .NET backend

Related Skills

  • umbraco-unit-testing - Add unit tests to examples

  • umbraco-mocked-backoffice - E2E testing patterns

  • umbraco-backoffice - Extension type blueprints

Quick Start

  1. Clone Umbraco source (one-time setup)

git clone https://github.com/umbraco/Umbraco-CMS cd Umbraco-CMS/src/Umbraco.Web.UI.Client npm install

  1. Create your extension folder

my-extension/ ├── index.ts # REQUIRED - exports manifests └── my-element.ts # Your element(s)

  1. Create index.ts (exports manifests)

import './my-element.js';

export const manifests = [ { type: 'dashboard', alias: 'My.Dashboard', name: 'My Dashboard', element: 'my-element', meta: { label: 'My Dashboard', pathname: 'my-dashboard' }, conditions: [{ alias: 'Umb.Condition.SectionAlias', match: 'Umb.Section.Content' }] } ];

  1. Create your element

// my-element.ts import { LitElement, html, customElement } from '@umbraco-cms/backoffice/external/lit';

@customElement('my-element') export class MyElement extends LitElement { render() { return html<uui-box headline="Hello">It works!</uui-box>; } }

  1. Run it

cd Umbraco-CMS/src/Umbraco.Web.UI.Client VITE_EXTERNAL_EXTENSION=/full/path/to/my-extension npm run dev:external

Open http://localhost:5173

  • your extension appears in the Content section.

How It Works

The Umbraco source (Umbraco-CMS/src/Umbraco.Web.UI.Client ) provides two ways to load extensions:

  1. Internal Examples (npm run example )

Examples placed in the examples/ folder inside the Umbraco source.

cd Umbraco-CMS/src/Umbraco.Web.UI.Client npm run example

Select from list of examples

How it works: Sets VITE_EXAMPLE_PATH and imports ./examples/{name}/index.ts

  1. External Extensions (npm run dev:external )

Extensions from any location on your filesystem - perfect for developing packages.

cd Umbraco-CMS/src/Umbraco.Web.UI.Client VITE_EXTERNAL_EXTENSION=/path/to/your/extension npm run dev:external

How it works:

  • Sets VITE_UMBRACO_USE_MSW=on (mocked APIs)

  • Creates @external-extension alias pointing to your extension path

  • Imports @external-extension/index.ts and registers exports with umbExtensionsRegistry

  • Resolves @umbraco-cms/backoffice/* imports from the main project (avoids duplicate element registrations)

Extension Loading (index.ts)

// From Umbraco-CMS/src/Umbraco.Web.UI.Client/index.ts if (import.meta.env.VITE_EXTERNAL_EXTENSION) { const js = await import('@external-extension/index.ts'); if (js) { Object.keys(js).forEach((key) => { const value = js[key]; if (Array.isArray(value)) { umbExtensionsRegistry.registerMany(value); } else if (typeof value === 'object') { umbExtensionsRegistry.register(value); } }); } }

Key point: Your index.ts must export manifests (arrays or objects) that get registered automatically.

Setup

Prerequisites

Clone and set up the Umbraco source:

git clone https://github.com/umbraco/Umbraco-CMS cd Umbraco-CMS/src/Umbraco.Web.UI.Client npm install

Extension Structure

Your extension needs this minimal structure:

my-extension/ ├── index.ts # Exports manifests array (REQUIRED) ├── my-element.ts # Your element(s) ├── my-context.ts # Context (if needed) ├── package.json # Optional - for IDE support and tests ├── tsconfig.json # Optional - for IDE support └── README.md # Documentation

Required: index.ts

Your index.ts must export manifests that will be registered:

import './my-dashboard.element.js';

export const manifests = [ { type: 'dashboard', alias: 'My.Dashboard', name: 'My Dashboard', element: 'my-dashboard', weight: 100, meta: { label: 'My Dashboard', pathname: 'my-dashboard' }, conditions: [ { alias: 'Umb.Condition.SectionAlias', match: 'Umb.Section.Content' } ] } ];

Optional: package.json (for IDE support)

{ "name": "my-extension", "type": "module", "devDependencies": { "@umbraco-cms/backoffice": "^17.0.0", "typescript": "~5.8.0" } }

Important: The @umbraco-cms/backoffice dependency is only for IDE TypeScript support. At runtime, imports are resolved from the main Umbraco project.

Running Your Extension

Start the mocked backoffice

cd /path/to/Umbraco-CMS/src/Umbraco.Web.UI.Client VITE_EXTERNAL_EXTENSION=/absolute/path/to/my-extension npm run dev:external

Open in browser

Navigate to http://localhost:5173

  • your extension is loaded automatically.

Hot reload

Changes to your extension files trigger hot reload - no restart needed.

Patterns

Basic Element

// my-dashboard.element.ts import { LitElement, html, css, customElement } from '@umbraco-cms/backoffice/external/lit';

@customElement('my-dashboard') export class MyDashboardElement extends LitElement { static override styles = css :host { display: block; padding: var(--uui-size-layout-1); } ;

override render() { return html <uui-box headline="My Extension"> <p>Running in the mocked backoffice!</p> </uui-box> ; } }

declare global { interface HTMLElementTagNameMap { 'my-dashboard': MyDashboardElement; } }

Element with Context

import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; import { EXAMPLE_MY_CONTEXT } from './my-context.js';

@customElement('example-my-feature-view') export class ExampleMyFeatureViewElement extends UmbLitElement { @state() private _value?: string;

constructor() { super(); this.consumeContext(EXAMPLE_MY_CONTEXT, (context) => { this.observe(context.value, (value) => { this._value = value; }); }); }

override render() { return html <uui-box headline="My Feature Example"> <p>Current value: ${this._value ?? 'Loading...'}</p> </uui-box> ; } }

export default ExampleMyFeatureViewElement;

declare global { interface HTMLElementTagNameMap { 'example-my-feature-view': ExampleMyFeatureViewElement; } }

Context

import { UmbContextToken } from '@umbraco-cms/backoffice/context-api'; import { UmbContextBase } from '@umbraco-cms/backoffice/class-api'; import { UmbStringState } from '@umbraco-cms/backoffice/observable-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api';

export class ExampleMyContext extends UmbContextBase { #value = new UmbStringState('initial'); readonly value = this.#value.asObservable();

constructor(host: UmbControllerHost) { super(host, EXAMPLE_MY_CONTEXT); }

setValue(value: string) { this.#value.setValue(value); }

getValue() { return this.#value.getValue(); }

public override destroy(): void { this.#value.destroy(); super.destroy(); } }

export const EXAMPLE_MY_CONTEXT = new UmbContextToken<ExampleMyContext>( 'ExampleMyContext' );

export { ExampleMyContext as api };

Adding Tests

Unit Tests

Add unit tests using @open-wc/testing . See umbraco-unit-testing skill for full setup.

npm install --save-dev @open-wc/testing @web/test-runner @web/test-runner-playwright

E2E Tests (Playwright)

Add E2E tests that run against the mocked backoffice. See umbraco-mocked-backoffice skill for patterns.

npm install --save-dev @playwright/test npx playwright install chromium

Examples

Reference Example

Location: ./examples/workspace-feature-toggle/

A complete standalone example demonstrating:

  • Workspace context with UmbArrayState

  • Workspace view consuming context

  • Workspace action executing context methods

  • Workspace footer app showing summary

  • 38 unit tests + 13 E2E tests

cd examples/workspace-feature-toggle npm install npm test # Unit tests npm run test:e2e # E2E tests (requires mocked backoffice running)

Official Umbraco Examples

Location: Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/

27 official examples covering all extension types. Run any example:

cd Umbraco-CMS/src/Umbraco.Web.UI.Client npm run example

Select from list

Naming Conventions

Item Convention Example

Directory kebab-case describing feature workspace-context-counter

Alias prefix example.

example.workspaceView.counter

Element prefix example-

example-counter-view

Context token EXAMPLE_

  • SCREAMING_CASE EXAMPLE_COUNTER_CONTEXT

Troubleshooting

Extension not appearing

  • Check index.ts exports a manifests array

  • Verify the path in VITE_EXTERNAL_EXTENSION is absolute

  • Check browser console for 📦 Loading external extension from: message

  • Ensure condition matches the section you're viewing

Import errors

Imports should use @umbraco-cms/backoffice/* . The Vite plugin resolves these from the main project.

"CustomElementRegistry" already defined

Your extension's node_modules is being used instead of the main project's. The external-extension-resolver plugin should handle this, but ensure:

  • You're using npm run dev:external

  • Imports use @umbraco-cms/backoffice/* not relative paths to node_modules

Changes not hot reloading

Ensure the file is within the path specified by VITE_EXTERNAL_EXTENSION . Only files in that directory tree are watched.

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

umbraco-backoffice

No summary provided by upstream source.

Repository SourceNeeds Review
General

umbraco-dashboard

No summary provided by upstream source.

Repository SourceNeeds Review
General

umbraco-quickstart

No summary provided by upstream source.

Repository SourceNeeds Review