diff --git a/examples/modal-routed/dashboard.element.ts b/examples/modal-routed/dashboard.element.ts
new file mode 100644
index 0000000000..967a4a7a88
--- /dev/null
+++ b/examples/modal-routed/dashboard.element.ts
@@ -0,0 +1,47 @@
+import { css, html, LitElement, customElement, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
+import type { UmbRoute } from '@umbraco-cms/backoffice/router';
+
+@customElement('umb-dashboard')
+export class UmbDashboardElement extends UmbElementMixin(LitElement) {
+ @state()
+ private _routes: UmbRoute[] = [
+ {
+ path: `/tab1`,
+ component: () => import('./tabs/tab1.element.js'),
+ },
+ {
+ path: `/tab2`,
+ component: () => import('./tabs/tab2.element.js'),
+ },
+ {
+ path: '',
+ redirectTo: 'tab1',
+ },
+ ];
+
+ override render() {
+ return html`
+
+ `;
+ }
+
+ static override styles = [UmbTextStyles, css``];
+}
+
+export default UmbDashboardElement;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-dashboard': UmbDashboardElement;
+ }
+}
diff --git a/examples/modal-routed/dashboard2.element.ts b/examples/modal-routed/dashboard2.element.ts
new file mode 100644
index 0000000000..2a3f02e7bf
--- /dev/null
+++ b/examples/modal-routed/dashboard2.element.ts
@@ -0,0 +1,34 @@
+import { css, html, LitElement, customElement } from '@umbraco-cms/backoffice/external/lit';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
+
+@customElement('umb-dashboard2')
+export class UmbDashboard2Element extends UmbElementMixin(LitElement) {
+ constructor() {
+ super();
+ }
+
+ override render() {
+ return html`
+
+
Link to modal route
+
+ This page only shows how to link to the routed modal that is placed on a tab on the "Modal Dashboard".
+ Clicking this link will not load the slots inside the modal, however, going to the "Modal Dashboard", clicking
+ on tab 2 and opening the modal from there will work.
+
+
Open Modal Route
+
+ `;
+ }
+
+ static override styles = [UmbTextStyles, css``];
+}
+
+export default UmbDashboard2Element;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-dashboard2': UmbDashboard2Element;
+ }
+}
diff --git a/examples/modal-routed/index.ts b/examples/modal-routed/index.ts
new file mode 100644
index 0000000000..5aca09fe79
--- /dev/null
+++ b/examples/modal-routed/index.ts
@@ -0,0 +1,44 @@
+import type { ManifestDashboard, ManifestModal } from '@umbraco-cms/backoffice/extension-registry';
+
+// const section : ManifestSection = {
+// type: "section",
+// alias: 'demo.section',
+// name: "Demo Section",
+// meta: {
+// label: "Demo",
+// pathname: "demo"
+// }
+// }
+
+const dashboard: ManifestDashboard = {
+ type: 'dashboard',
+ name: 'Example Modal Dashboard',
+ alias: 'example.dashboard.dataset',
+ element: () => import('./dashboard.element.js'),
+ weight: 15000,
+ meta: {
+ label: 'Modal Dashboard',
+ pathname: 'example',
+ },
+};
+
+const dashboard2: ManifestDashboard = {
+ type: 'dashboard',
+ name: 'Example Modal Dashboard2',
+ alias: 'example.dashboard.dataset2',
+ element: () => import('./dashboard2.element.js'),
+ weight: 15001,
+ meta: {
+ label: 'Link Dashboard',
+ pathname: 'example-2',
+ },
+};
+
+const modal: ManifestModal = {
+ type: 'modal',
+ name: 'Example Modal',
+ alias: 'example.routed.modal',
+ element: () => import('./modal/example-modal.element.js'),
+};
+
+export const manifests = [dashboard, dashboard2, modal];
diff --git a/examples/modal-routed/modal/example-modal-token.ts b/examples/modal-routed/modal/example-modal-token.ts
new file mode 100644
index 0000000000..1755a7ef3a
--- /dev/null
+++ b/examples/modal-routed/modal/example-modal-token.ts
@@ -0,0 +1,13 @@
+import { UmbModalToken } from '@umbraco-cms/backoffice/modal';
+
+export type Data = object;
+export type ModalValue = object;
+
+export const EXAMPLE_ROUTED_MODAL = new UmbModalToken(
+ 'example.routed.modal', // this needs to match the alias of the modal registered in manifest.ts
+ {
+ modal: {
+ type: 'dialog',
+ },
+ },
+);
diff --git a/examples/modal-routed/modal/example-modal.element.ts b/examples/modal-routed/modal/example-modal.element.ts
new file mode 100644
index 0000000000..e1f0f5bdd4
--- /dev/null
+++ b/examples/modal-routed/modal/example-modal.element.ts
@@ -0,0 +1,43 @@
+import { css, html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
+import type { UmbRoute } from '@umbraco-cms/backoffice/router';
+
+@customElement('umb-example-modal')
+export class UmbExampleModal extends UmbModalBaseElement {
+ @state()
+ private _routes: UmbRoute[] = [
+ {
+ path: `modalOverview`,
+ component: () => import('./steps/example-modal-step1.element.js'),
+ },
+ {
+ path: `details`,
+ component: () => import('./steps/example-modal-step2.element.js'),
+ },
+ {
+ path: '',
+ redirectTo: 'modalOverview',
+ },
+ ];
+
+ override render() {
+ return html`
+
+ umb-example modal element
+
+
+
+ `;
+ }
+
+ static override styles = [UmbTextStyles, css``];
+}
+
+export default UmbExampleModal;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-example-modal': UmbExampleModal;
+ }
+}
diff --git a/examples/modal-routed/modal/steps/example-modal-step1.element.ts b/examples/modal-routed/modal/steps/example-modal-step1.element.ts
new file mode 100644
index 0000000000..9098546e6a
--- /dev/null
+++ b/examples/modal-routed/modal/steps/example-modal-step1.element.ts
@@ -0,0 +1,20 @@
+import { css, html, customElement } from '@umbraco-cms/backoffice/external/lit';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
+
+@customElement('umb-example-modal-step1')
+export class UmbExampleModalStep1 extends UmbModalBaseElement {
+ override render() {
+ return html` example modal step1
`;
+ }
+
+ static override styles = [UmbTextStyles, css``];
+}
+
+export default UmbExampleModalStep1;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-example-modal-step1': UmbExampleModalStep1;
+ }
+}
diff --git a/examples/modal-routed/modal/steps/example-modal-step2.element.ts b/examples/modal-routed/modal/steps/example-modal-step2.element.ts
new file mode 100644
index 0000000000..ea5c711b25
--- /dev/null
+++ b/examples/modal-routed/modal/steps/example-modal-step2.element.ts
@@ -0,0 +1,20 @@
+import { html, customElement } from '@umbraco-cms/backoffice/external/lit';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { UmbModalBaseElement } from '@umbraco-cms/backoffice/modal';
+
+@customElement('umb-example-modal-step2')
+export class UmbExampleModalStep2 extends UmbModalBaseElement {
+ override render() {
+ return html` example modal step2
`;
+ }
+
+ static override styles = [UmbTextStyles];
+}
+
+export default UmbExampleModalStep2;
+
+declare global {
+ interface HTMLElementTagNameMap {
+ 'umb-example-modal-step2': UmbExampleModalStep2;
+ }
+}
diff --git a/examples/modal-routed/tabs/tab1.element.ts b/examples/modal-routed/tabs/tab1.element.ts
new file mode 100644
index 0000000000..463b31824e
--- /dev/null
+++ b/examples/modal-routed/tabs/tab1.element.ts
@@ -0,0 +1,31 @@
+import { css, html, LitElement, customElement, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
+
+@customElement('umb-dashboard-tab1')
+export class UmbDashboardTab1Element extends UmbElementMixin(LitElement) {
+ @state()
+ _editLinkPath?: string;
+
+ constructor() {
+ super();
+ }
+
+ override render() {
+ return html`
+
+
tab 1
+
+ `;
+ }
+
+ static override styles = [UmbTextStyles, css``];
+}
+
+export default UmbDashboardTab1Element;
+
+declare global {
+ interface UmbDashboardTab1Element {
+ 'umb-dashboard-tab1': UmbDashboardTab1Element;
+ }
+}
diff --git a/examples/modal-routed/tabs/tab2.element.ts b/examples/modal-routed/tabs/tab2.element.ts
new file mode 100644
index 0000000000..66346df3de
--- /dev/null
+++ b/examples/modal-routed/tabs/tab2.element.ts
@@ -0,0 +1,55 @@
+import { EXAMPLE_ROUTED_MODAL } from '../modal/example-modal-token.js';
+import { css, html, LitElement, customElement, state } from '@umbraco-cms/backoffice/external/lit';
+import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
+import { UmbElementMixin } from '@umbraco-cms/backoffice/element-api';
+import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router';
+
+@customElement('umb-dashboard-tab2')
+export class UmbDashboardTab2Element extends UmbElementMixin(LitElement) {
+ #workspaceModal?: UmbModalRouteRegistrationController<
+ typeof EXAMPLE_ROUTED_MODAL.DATA,
+ typeof EXAMPLE_ROUTED_MODAL.VALUE
+ >;
+
+ @state()
+ _editLinkPath?: string;
+
+ constructor() {
+ super();
+
+ // Using workspace modal context
+ this.#workspaceModal?.destroy();
+ this.#workspaceModal = new UmbModalRouteRegistrationController(this, EXAMPLE_ROUTED_MODAL)
+ .addAdditionalPath('view/:entityKey')
+ .onSetup(() => {
+ return {
+ data: {},
+ value: {},
+ };
+ })
+ .observeRouteBuilder((routeBuilder) => {
+ this._editLinkPath = routeBuilder({ entityKey: 'abc123' });
+ });
+ }
+
+ override render() {
+ return html`
+
+
tab 2
+
This element hosts the UmbModalRouteRegistrationController
+
+
Open modal
+
+ `;
+ }
+
+ static override styles = [UmbTextStyles, css``];
+}
+
+export default UmbDashboardTab2Element;
+
+declare global {
+ interface UmbDashboardTab2Element {
+ 'umb-dashboard-tab2': UmbDashboardTab2Element;
+ }
+}
diff --git a/src/external/router-slot/router-slot.ts b/src/external/router-slot/router-slot.ts
index 06fddd335b..b93152ba63 100644
--- a/src/external/router-slot/router-slot.ts
+++ b/src/external/router-slot/router-slot.ts
@@ -162,9 +162,11 @@ export class RouterSlot extends HTMLElement implements IRouter
this._setParent(null);
}
}
- if (this.parent && this.parent.match !== null && this.match === null) {
+ if (this.parent) {
requestAnimationFrame(() => {
- this.render();
+ if (this.parent && this.parent.match !== null && this.match === null) {
+ this.render();
+ }
});
}
}
diff --git a/src/packages/core/router/route.context.ts b/src/packages/core/router/route.context.ts
index 7fda170903..f8f15291d4 100644
--- a/src/packages/core/router/route.context.ts
+++ b/src/packages/core/router/route.context.ts
@@ -123,7 +123,7 @@ export class UmbRouteContext extends UmbContextBase {
if (this.#activeModalPath) {
// If if there is a modal using the old path.
const activeModal = this.#modalRegistrations.find((registration) => {
- return registration.generateModalPath() === this.#activeModalPath;
+ return '/' + registration.generateModalPath() === this.#activeModalPath;
});
if (activeModal) {
this.#modalContext?.close(activeModal.key);
diff --git a/src/packages/core/router/router-slot.element.ts b/src/packages/core/router/router-slot.element.ts
index 6b45549d73..a78f0e2ac6 100644
--- a/src/packages/core/router/router-slot.element.ts
+++ b/src/packages/core/router/router-slot.element.ts
@@ -94,9 +94,7 @@ export class UmbRouterSlotElement extends UmbLitElement {
protected override firstUpdated(_changedProperties: PropertyValueMap | Map): void {
super.firstUpdated(_changedProperties);
- this._routerPath = this._constructAbsoluteRouterPath();
- this.#routeContext._internal_routerGotBasePath(this._routerPath);
- this.dispatchEvent(new UmbRouterSlotInitEvent());
+ this._updateRouterPath();
}
protected _updateRouterPath() {
@@ -124,7 +122,7 @@ export class UmbRouterSlotElement extends UmbLitElement {
this.dispatchEvent(new UmbRouterSlotChangeEvent());
}
} else if (event.detail.slot === this.#modalRouter) {
- const newActiveModalLocalPath = this.#modalRouter.match?.fragments.consumed ?? '';
+ const newActiveModalLocalPath = this.#modalRouter.match?.route.path ?? '';
this.#routeContext._internal_modalRouterChanged(newActiveModalLocalPath);
}
};