umbraco-routing
Umbraco Routing
What is it?
Routing in Umbraco's backoffice enables navigation between sections, dashboards, and workspaces using pathname-based URLs. Sections serve as primary organizational dividers with entry points via section views, dashboards, or custom elements. Custom routing can be built using umb-router-slot with route definitions that support parameters and redirects.
Documentation
Always fetch the latest docs before implementing:
- Main docs: https://docs.umbraco.com/umbraco-cms/customizing/foundation/routes
- Sections: https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/sections/section
- Dashboards: https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types/dashboard
- Foundation: https://docs.umbraco.com/umbraco-cms/customizing/foundation
Reference Example
The Umbraco source includes a working example:
Location: /Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/modal-routed/
This example demonstrates routed modals with URL-based navigation and deep-linking support. Study this for complex routing patterns.
Workflow
- Fetch docs - Use WebFetch on the URLs above
- Ask questions - Custom routes? Section navigation? Parameters needed?
- Generate code - Implement routing based on latest docs
- Explain - Show what was created and how navigation works
Minimal Examples
Section with Pathname
{
"type": "section",
"alias": "My.Section",
"name": "My Section",
"meta": {
"label": "My Section",
"pathname": "my-section"
}
}
URL: /section/my-section
Dashboard with Pathname
{
"type": "dashboard",
"alias": "My.Dashboard",
"name": "My Dashboard",
"meta": {
"label": "Welcome",
"pathname": "welcome-dashboard"
},
"conditions": [
{
"alias": "Umb.Condition.SectionAlias",
"match": "Umb.Section.Content"
}
]
}
URL: /section/content/dashboard/welcome-dashboard
Custom Router with Routes
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbRoute } from '@umbraco-cms/backoffice/router';
@customElement('my-routed-element')
export class MyRoutedElement extends UmbLitElement {
@state()
private _routes: UmbRoute[] = [
{
path: 'person/:personId',
component: () => import('./person.element.js'),
setup: (_component, info) => {
console.log('personId:', info.match.params.personId);
},
},
{
path: 'people',
component: () => import('./people.element.js'),
},
{
path: '',
redirectTo: 'people',
},
];
render() {
return html`
<umb-router-slot .routes=${this._routes}></umb-router-slot>
`;
}
}
Route with Parameters
{
path: 'edit/:id',
component: () => import('./edit.element.js'),
setup: (component, info) => {
const id = info.match.params.id;
component.itemId = id;
},
}
Route with Redirect
{
path: '',
redirectTo: 'overview',
}
Multiple Routes Example
@state()
private _routes: UmbRoute[] = [
{
path: 'overview',
component: () => import('./overview.element.js'),
},
{
path: 'settings',
component: () => import('./settings.element.js'),
},
{
path: 'item/:id',
component: () => import('./item-detail.element.js'),
setup: (component, info) => {
component.itemId = info.match.params.id;
},
},
{
path: '',
redirectTo: 'overview',
},
];
Navigation Links
render() {
return html`
<nav>
<a href="/section/my-section/overview">Overview</a>
<a href="/section/my-section/settings">Settings</a>
<a href="/section/my-section/item/123">Item 123</a>
</nav>
<umb-router-slot .routes=${this._routes}></umb-router-slot>
`;
}
Section View with Pathname
{
"type": "sectionView",
"alias": "My.SectionView",
"name": "My Section View",
"element": "/App_Plugins/MyExtension/section-view.js",
"meta": {
"label": "Organization",
"pathname": "organization",
"icon": "icon-users"
},
"conditions": [
{
"alias": "Umb.Condition.SectionAlias",
"match": "My.Section"
}
]
}
URL: /section/my-section/organization
Nested Routes
// Parent element
@state()
private _routes: UmbRoute[] = [
{
path: 'admin',
component: () => import('./admin-layout.element.js'),
},
{
path: 'users',
component: () => import('./users-layout.element.js'),
},
];
// Admin layout element can have its own nested routes
@state()
private _adminRoutes: UmbRoute[] = [
{
path: 'dashboard',
component: () => import('./admin-dashboard.element.js'),
},
{
path: 'settings',
component: () => import('./admin-settings.element.js'),
},
];
Route Setup Function
{
path: 'edit/:documentId',
component: () => import('./document-editor.element.js'),
setup: (component, info) => {
// Access route parameters
const documentId = info.match.params.documentId;
// Pass to component
component.documentId = documentId;
// Can also access query params, etc.
console.log('Route info:', info);
},
}
Key Concepts
pathname: URL segment for sections/dashboards/views
umb-router-slot: Component that renders matched route
UmbRoute: Route definition with path, component, setup
Route Order: First match wins - order matters!
Parameters: Use :paramName in path (e.g., item/:id)
Redirects: Use redirectTo to redirect to another path
setup Function: Called when route matches, receives component and route info
URL Structure:
- Section:
/section/my-section - Dashboard:
/section/content/dashboard/welcome - Section View:
/section/my-section/organization - Custom:
/section/my-section/people/person/123
Entry Points:
- Section Views (with tabs/icons)
- Dashboards (with tabs/icons)
- Workspaces (entity editing)
- Custom Elements (full control)
That's it! Always fetch fresh docs, keep examples minimal, generate complete working code.