Report 26: Plugins & Editors Comparison (v8 vs v17)¶
Generated: 2026-02-27 | Scope: All v8 App_Plugins property editors vs v17 TypeScript/Lit editors
1. Overview: AngularJS to TypeScript/Lit Migration¶
v8 Architecture (Umbraco 8 - AngularJS)¶
Each v8 property editor was a standalone plugin directory under App_Plugins/ containing:
App_Plugins/psHeading/
package.manifest <-- Plugin registration (JSON)
propertyeditor.controller.js <-- AngularJS controller
propertyeditor.html <-- AngularJS template (HTML with ng-* directives)
propertyeditor.styles.css <-- Component styles
img/ <-- Icon images
The package.manifest file declared the editor alias, JS/CSS files, and view path. The AngularJS controller registered on the "umbraco" module:
v17 Architecture (Umbraco 17 - TypeScript/Lit Web Components)¶
All custom editors are in a single project (Progress.CustomPropertyEditors) and bundled by Vite into a single index.js entry point:
Progress.CustomPropertyEditors/
src/
index.ts <-- Single entry point, imports all manifests
psHeading/
manifest.ts <-- Editor registration (TypeScript)
heading-editor.ts <-- Lit Web Component
psCalculators/
manifest.ts
calculators-editor.ts
calculators-modal.element.ts
...27 more editors...
vite.config.ts <-- Build config
package.json <-- npm dependencies
--> Builds to --> www/App_Plugins/Progress/index.js (single bundle)
Each editor is a Lit Web Component class extending UmbElementMixin(LitElement):
@customElement('heading-editor')
export default class HeadingEditorElement
extends UmbElementMixin(LitElement)
implements UmbPropertyEditorUiElement { ... }
Key differences¶
| Aspect | v8 (AngularJS) | v17 (TypeScript/Lit) |
|---|---|---|
| Framework | AngularJS 1.x | Lit 3.x Web Components |
| Language | JavaScript | TypeScript |
| Registration | package.manifest (JSON) |
manifest.ts (TypeScript) |
| Module system | Angular DI + angular.module() |
ES modules + UmbElementMixin |
| Build tool | None (raw files served) | Vite (tree-shaking, code splitting) |
| Output | Per-plugin directory | Single bundled index.js |
| Styling | External CSS file | css tagged template literal (scoped) |
| Template | External HTML file | html tagged template literal (inline) |
| Value binding | $scope.model.value |
@property() value + UmbChangeEvent |
| Dialogs/Modals | Umbraco dialogService + editorService |
UmbModalManagerContext + custom modal elements |
| Schema | Implicit (value type in manifest) | Explicit propertyEditorSchemaAlias |
2. Side-by-Side: psHeading Editor¶
v8: AngularJS Property Editor¶
Directory: psCreditUnion/Progress.Web/App_Plugins/psHeading/
package.manifest:
{
"javascript": ["~/App_Plugins/psHeading/propertyeditor.controller.js"],
"css": ["~/App_Plugins/psHeading/propertyeditor.styles.css"],
"propertyEditors": [{
"alias": "ps.headingWeight",
"name": "Heading Weight",
"editor": {
"view": "~/App_Plugins/psHeading/propertyeditor.html",
"hideLabel": false,
"valueType": "STRING"
}
}]
}
propertyeditor.controller.js:
function headingWeightEditorController($scope) {
$scope.model.options = [
{ alias: "h1", name: "h1" },
{ alias: "h2", name: "h2" },
{ alias: "h3", name: "h3" },
{ alias: "h4", name: "h4" },
{ alias: "h5", name: "h5" },
{ alias: "h6", name: "h6" }
];
$scope.model.value = $scope.model.value || $scope.model.options[0].alias;
}
angular.module("umbraco").controller("psHeading", headingWeightEditorController);
v17: TypeScript/Lit Web Component¶
Directory: Progress.CustomPropertyEditors/src/psHeading/
manifest.ts:
import { ManifestPropertyEditorUi } from '@umbraco-cms/backoffice/property-editor';
const propertyEditorUi: ManifestPropertyEditorUi = {
type: "propertyEditorUi",
alias: "ps.headingWeight",
name: "Heading Weight",
element: () => import('./heading-editor'),
elementName: "heading-editor",
meta: {
label: "Heading Weight",
propertyEditorSchemaAlias: "Umbraco.Plain.String",
icon: "icon-heading",
group: "Progress"
}
};
export const manifests = [propertyEditorUi];
heading-editor.ts:
import { LitElement, html, css, customElement, property, state }
from '@umbraco-cms/backoffice/external/lit';
import type { UmbPropertyEditorUiElement }
from '@umbraco-cms/backoffice/extension-registry';
import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
interface HeadingOption { alias: string; name: string; fontSize: string; }
@customElement('heading-editor')
export default class HeadingEditorElement
extends UmbElementMixin(LitElement)
implements UmbPropertyEditorUiElement {
@property({ type: String }) value = '';
@state() private _options: HeadingOption[] = [
{ alias: 'h1', name: 'H1', fontSize: '24px' },
{ alias: 'h2', name: 'H2', fontSize: '20px' },
{ alias: 'h3', name: 'H3', fontSize: '18px' },
{ alias: 'h4', name: 'H4', fontSize: '16px' },
{ alias: 'h5', name: 'H5', fontSize: '14px' },
{ alias: 'h6', name: 'H6', fontSize: '12px' }
];
static styles = css`
.heading-container { display: flex; gap: 10px; flex-wrap: wrap; }
.heading-item { border: 1px solid #e9e9eb; width: 60px; height: 60px;
cursor: pointer; border-radius: 10px; font-weight: bold; }
.heading-item--selected { border: 2px solid #2e3192; transform: scale(1.1); }
`;
private _selectOption(alias: string): void {
this.value = alias;
this.dispatchEvent(new UmbChangeEvent());
}
render() {
return html`<div class="heading-container">
${this._options.map(o => html`
<span class="heading-item ${this.value === o.alias ? 'heading-item--selected' : ''}"
style="font-size: ${o.fontSize}"
@click="${() => this._selectOption(o.alias)}">
${o.name}
</span>`)}
</div>`;
}
}
Comparison¶
| Aspect | v8 | v17 |
|---|---|---|
| Files | 4 (manifest + JS + HTML + CSS) | 2 (manifest.ts + editor.ts) |
| Lines of code | ~40 (controller + HTML + CSS) | ~95 (single file, includes styles + template) |
| Type safety | None | Full TypeScript types + interfaces |
| Styles | External CSS (global scope) | Shadow DOM scoped CSS |
| Value change | $scope.model.value = ... |
this.value = ...; dispatchEvent(new UmbChangeEvent()) |
| Lazy loading | No (all JS loaded upfront) | Yes (element: () => import()) |
| Schema binding | "valueType": "STRING" |
propertyEditorSchemaAlias: "Umbraco.Plain.String" |
3. Complete Mapping Table: v8 App_Plugins --> v17 Editors¶
3.1 Custom Property Editors (migrated 1:1)¶
| v8 App_Plugins Directory | v17 Source Directory | v17 Built Files | Notes |
|---|---|---|---|
psHeading/ |
psHeading/ |
heading-editor-*.js |
Heading weight picker (H1-H6) |
psCalculators/ |
psCalculators/ |
calculators-editor-*.js + calculators-modal.element-*.js |
Calculator config picker with modal |
psLoanBoxes/ |
psLoanBoxes/ |
loan-boxes-editor-*.js + loan-boxes-modal.element-*.js |
Loan box config with modal |
psNews/ |
psNews/ |
news-editor-*.js + news-modal.element-*.js |
News layout picker with modal |
psPosition/ |
psPosition/ |
position-editor-*.js |
Position/alignment picker |
psTestimonial/ |
psTestimonial/ |
testimonial-editor-*.js |
Testimonial layout picker |
psFaqAccordion/ |
psFaqAccordion/ |
faq-accordion-editor-*.js |
FAQ/accordion config |
psServices/ |
psServices/ |
services-editor-*.js |
Services layout picker |
psServicesImage/ |
psServicesImage/ |
services-image-editor-*.js |
Services image layout picker |
psSubMenu/ |
psSubMenu/ |
sub-menu-editor-*.js |
Sub-menu config |
psGlobalAddress/ |
psGlobalAddress/ |
global-address-editor-*.js |
Address display config |
psGlobalGoogleMap/ |
psGlobalGoogleMap/ |
global-google-map-editor-*.js |
Google Maps embed config |
psGlobalLeafLetMap/ |
psGlobalLeafLetMap/ |
global-leaflet-map-editor-*.js |
Leaflet map config |
psSocialFooter/ |
psSocialFooter/ |
social-footer-editor-*.js |
Social media footer links |
psStickySocial/ |
psStickySocial/ |
sticky-social-editor-*.js |
Sticky social sidebar config |
psTextStringDefaultValue/ |
psTextStringDefaultValue/ |
text-string-default-value-*.js |
Textfield with default value |
psTextAreaDefaultValue/ |
psTextAreaDefaultValue/ |
text-area-default-value-*.js |
Textarea with default value |
psDataProtectionDPO/ |
psDataProtectionDPO/ |
data-protection-dpo-editor-*.js |
Data protection officer editor |
psDataProtectionName/ |
psDataProtectionName/ |
data-protection-name-editor-*.js |
Data protection name editor |
psDataProtectionSpecificStatements/ |
psDataProtectionSpecificStatements/ |
data-protection-specific-statements-editor-*.js |
GDPR specific statements |
psDataProtectionSummaryTable/ |
psDataProtectionSummaryTable/ |
data-protection-summary-table-editor-*.js |
GDPR summary table |
psDataProtectionWeAre/ |
psDataProtectionWeAre/ |
data-protection-we-are-editor-*.js |
Data protection "We Are" section |
psReleaseNotes/ |
psReleaseNotes/ |
release-notes-editor-*.js |
Release notes display |
psTweaks/ |
psTweaks/ |
tweaks-editor-*.js |
CSS/JS tweaks editor |
FaIconpicker/ |
psFaIconPicker/ |
fa-icon-picker-editor-*.js + fa-icon-picker-modal.element-*.js |
Font Awesome icon picker with modal |
GridSettingsMarginEditor/ |
GridSettingsMarginEditor/ |
margin-editor-*.js |
Grid margin settings |
GridSettingsPaddingEditor/ |
GridSettingsPaddingEditor/ |
padding-editor-*.js |
Grid padding settings |
3.2 New Editors in v17 (no v8 equivalent)¶
| v17 Source Directory | v17 Built Files | Notes |
|---|---|---|
psOpeningSoon/ |
via OpeningSoonValueConverter.cs |
Opening hours editor (v8 used OpeningSoon/ plugin but now has server-side converter too) |
psWelcomeDashboard/ |
dashboard manifest | Custom welcome dashboard (replaces CustomWelcomeDashboard/ AngularJS) |
psEmbeddedMedia/ |
embedded media editor | Embedded media picker (new in v17) |
3.3 v8 Plugins Removed / Not Migrated¶
| v8 App_Plugins Directory | Reason for Removal |
|---|---|
2FactorAuthentication/ |
Replaced by TwoFactorProviders/ (native v17 approach in www/App_Plugins/) |
CDFHealthCheck/ |
CDF-specific; not needed in v17 |
ColorPickerU8/ |
Replaced by Umbraco.ColorPicker.EyeDropper (built-in v17) |
CustomWelcomeDashboard/ |
Replaced by psWelcomeDashboard/ TypeScript editor |
Dawoe.OEmbedPickerPropertyEditor/ |
Replaced by built-in Umbraco.MediaPicker3 |
DiploGodMode/ |
Third-party dev tool; not needed in production |
DocTypeGridEditor/ |
Grid system replaced by BlockGrid (native v17) |
ListViewNews/ |
v17 list views are configured in backoffice, no plugin needed |
ListViewTestimonals/ |
Same as above |
MeganavV8/ |
Third-party mega-nav; navigation rebuilt in v17 templates |
Mw.UmbForms.Rte/ |
Forms RTE extension; v17 Forms handles this natively |
NestingContently/ |
Nested Content helper; replaced by BlockList (native v17) |
OpeningSoon/ |
Functionality preserved; server-side OpeningSoonValueConverter.cs + psOpeningSoon/ editor |
Our.Umbraco.Matryoshka/ |
Nested content helper; not needed with BlockGrid |
UmbracoForms/ |
Umbraco Forms now ships as a NuGet package, not App_Plugin |
blocks/ |
Block editors now part of core Umbraco |
psReset2FA/ |
Replaced by reset-2fa-editor-*.js in the Progress bundle |
uSync8/ |
uSync now ships as NuGet package |
uSyncExpansions/ |
uSync expansion; NuGet-based in v17 |
uSyncExporter/ |
uSync exporter; NuGet-based in v17 |
uSyncHistory/ |
uSync history; NuGet-based in v17 |
uSyncPacker/ |
uSync packer; NuGet-based in v17 |
uSyncPeopleEdition/ |
uSync people; NuGet-based in v17 |
uSyncPublisher/ |
uSync publisher; NuGet-based in v17 |
uSyncSnapshots/ |
uSync snapshots; NuGet-based in v17 |
3.4 Non-editor Plugins in v17 (new approach)¶
| v17 App_Plugins Directory | Purpose | Notes |
|---|---|---|
Progress/ |
Main bundle output | Contains index.js + all editor bundles + images |
RemoveDashboards/ |
Remove built-in dashboards | Client-side JS approach (replaces v8 RemoveDashBoard.cs composer) |
TwoFactorProviders/ |
2FA login provider | Replaces v8 2FactorAuthentication/ |
Vokseverk.ColorSelector/ |
Color selector | Third-party; replaces ColorPickerU8/ |
4. Render Views Migration¶
The v8 Grid system used DocTypeGridEditor render views -- Razor .cshtml files inside App_Plugins/ that rendered grid content inline. In v17, the BlockGrid system uses BlockGrid component views in Views/Partials/blockgrid/Components/.
v8 Render Views in App_Plugins¶
| v8 Render View | v8 Path | v17 BlockGrid Component | v17 Path |
|---|---|---|---|
DocTypeGridEditor.cshtml |
DocTypeGridEditor/Render/ |
N/A -- entire Grid framework replaced | Views/Partials/blockgrid/ |
DocTypeGridEditorPreviewer.cshtml |
DocTypeGridEditor/Render/ |
Block preview handled by Umbraco native | -- |
psDataProtectionDPO.cshtml |
psDataProtectionDPO/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
DataProtectionName.cshtml |
psDataProtectionName/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
psDataProtectionSpecificStatements.cshtml |
psDataProtectionSpecificStatements/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
DataProtectionSummaryTable.cshtml |
psDataProtectionSummaryTable/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
DataProtectionWeAre.cshtml |
psDataProtectionWeAre/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
faq.cshtml |
psFaqAccordion/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
LargeGoogleMap.cshtml |
psGlobalGoogleMap/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
LargeLeafLetMap.cshtml |
psGlobalLeafLetMap/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
services.cshtml |
psServices/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
services.cshtml |
psServicesImage/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
socialFooter.cshtml |
psSocialFooter/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
stickysocial.cshtml |
psStickySocial/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
subMenu.cshtml |
psSubMenu/Editors/RenderViews/ |
BlockGrid component view | Views/Partials/blockgrid/Components/ |
HtmlTable.cshtml |
UmbracoForms/RazorTemplates/ |
Umbraco Forms package handles this | -- |
Architectural change¶
In v8, render views lived alongside the editor plugin in App_Plugins/ and were invoked by the DocTypeGridEditor framework. In v17, the separation is clean:
- Editor UI (backoffice):
Progress.CustomPropertyEditors/src/--> TypeScript/Lit -->App_Plugins/Progress/index.js - Render views (frontend):
Views/Partials/blockgrid/Components/--> Razor.cshtmlfiles
This means the App_Plugins/ directory in v17 contains only editor code (JS bundles, package manifests, images). All rendering is done by standard Razor views in the Views/ directory.
5. What Was Removed / Consolidated¶
5.1 Third-party plugins replaced by NuGet packages¶
The following v8 App_Plugins/ directories were third-party packages that now install via NuGet and do not need manual App_Plugins/ directories:
uSync8/,uSyncExpansions/,uSyncExporter/,uSyncHistory/,uSyncPacker/,uSyncPeopleEdition/,uSyncPublisher/,uSyncSnapshots/(8 directories --> 1 NuGet:uSync)UmbracoForms/(1 directory --> NuGet:Umbraco.Forms)
5.2 Plugins replaced by built-in Umbraco v17 features¶
DocTypeGridEditor/--> BlockGrid (native)NestingContently/--> BlockList (native)Our.Umbraco.Matryoshka/--> BlockList nesting (native)blocks/--> Block editors (native)Dawoe.OEmbedPickerPropertyEditor/--> MediaPicker3 (native)ColorPickerU8/-->Umbraco.ColorPicker.EyeDropper(native)ListViewNews/,ListViewTestimonals/--> Backoffice list view config (native)
5.3 Development/admin tools removed¶
DiploGodMode/-- development-only tool, not needed in productionCDFHealthCheck/-- CDF-specific health check
5.4 Consolidation metrics¶
| Metric | v8 | v17 |
|---|---|---|
| Total App_Plugins directories | 51 | 4 |
| Custom editor directories | 27 | 31 (in src/) |
| Third-party plugin directories | 16 | 0 (all NuGet) |
| Infrastructure directories | 8 (uSync) | 0 (NuGet) |
| Build output files | ~120 individual files | 1 index.js + ~60 code-split chunks |
| Editor registration | 27 package.manifest JSON files |
1 index.ts entry point |
6. Summary¶
The v8-to-v17 property editor migration represents a complete rewrite from AngularJS to TypeScript/Lit:
- All 27 custom editors were migrated 1:1 with identical aliases (e.g.,
ps.headingWeight) to maintain backward compatibility with existing content - 16 render views moved from
App_Plugins/toViews/Partials/blockgrid/Components/ - 24 third-party/infrastructure plugins were eliminated (replaced by NuGet packages or built-in features)
- 4 new editors were added in v17 (
psOpeningSoon,psWelcomeDashboard,psEmbeddedMedia,psReset2FA) - The build pipeline changed from no-build (raw JS served directly) to Vite bundling with tree-shaking, code splitting, and source maps
- The total
App_Plugins/footprint went from 51 directories to 4 directories