Customize the admin UI with swappable pages and layout slots. Use when replacing built-in pages (dashboard, list, edit, view), injecting content into layout slots (header, footer, sidebar, before/after), or registering per-collection overrides.
BY DonaldMurilloUPDATED Oct 30, 2026
INTENDED FOR◈OpenClawInstall in a listed agent.
instructions.md
---
name: admin-customize-3b19e80abd18
description: Customize the admin UI with swappable pages and layout slots. Use when replacing built-in pages (dashboard, list, edit, view), injecting content into layout slots (header, footer, sidebar, before/after), or registering per-collection overrides.
argument-hint: <page-override|slot|per-collection>
---
# Admin Customization — Swappable Pages & Layout Slots
Guide for customizing the Momentum CMS admin UI via page replacements and layout slot injection.
## Arguments
- `$ARGUMENTS` - What to customize: `page-override`, `slot`, or `per-collection`
## Two Registration Methods
### 1. Config-level (momentum.config.ts)
Registered in the server config. The code generator emits these as loader functions in the browser-safe generated config. This is the recommended approach — single source of truth.
### 2. Provider-level (app.config.ts)
Registered via Angular DI providers. Useful for app-specific customizations that don't belong in the server config, or for login page slots (which render outside the admin shell).
## Swappable Pages (Full Replacement)
### Available Page Keys
| Key | Built-in Page |
| ----------------- | --------------- |
| `dashboard` | Dashboard |
| `login` | Login |
| `media` | Media Library |
| `collection-list` | Collection List |
| `collection-edit` | Collection Edit |
| `collection-view` | Collection View |
| `global-edit` | Global Edit |
### Config-level (momentum.config.ts)
```typescript
import { defineMomentumConfig } from '@momentumcms/core';
export default defineMomentumConfig({
// ...
admin: {
basePath: '/admin',
components: {
dashboard: () => import('./app/custom-dashboard.component').then((m) => m.CustomDashboard),
},
},
});
```
### Provider-level (app.config.ts)
```typescript
import { provideAdminComponent } from '@momentumcms/admin';
export const appConfig: ApplicationConfig = {
providers: [
provideAdminComponent('dashboard', () =>
import('./custom-dashboard.component').then((m) => m.CustomDashboard),
),
],
};
```
### Per-Collection Page Overrides
Override pages for a specific collection only. Other collections keep the default.
#### Config-level (on the collection definition)
```typescript
const collections = baseCollections.map((c) => {
if (c.slug === 'articles') {
return {
...c,
admin: {
...c.admin,
components: {
list: () =>
import('./app/custom-articles-list.component').then(
(m) => m.CustomArticlesListComponent,
),
},
},
};
}
return c;
});
```
#### Provider-level
```typescript
provideAdminComponent('collections/articles/list', () =>
import('./custom-articles-list.component').then((m) => m.CustomArticlesList),
);
```
### Resolution Chain
For collection pages, the resolver checks in order:
1. Per-collection override (`collections/{slug}/{type}`)
2. Global override (`collection-list`)
3. Built-in default
## Layout Slots (Additive Injection)
Slots inject content around existing pages without replacing them. Multiple components can be registered for the same slot.
### Available Slots
#### Shell Slots (visible on all authenticated pages)
| Slot Key | Position |
| ----------------- | ------------------------------- |
| `shell:header` | Top of main content area |
| `shell:footer` | Bottom of main content area |
| `shell:nav-start` | After Dashboard link in sidebar |
| `shell:nav-end` | After plugin routes in sidebar |
#### Page Slots
| Slot Key | Position |
| -------------------------------------- | ------------------------ |
| `dashboard:before/after` | Around dashboard content |
| `collection-list:before/after` | Around list tables |
| `collection-edit:before/after/sidebar` | Around edit forms |
| `collection-view:before/after` | Around view pages |
| `login:before/after` | Around login form |
### Config-level (momentum.config.ts — admin.components)
Config-level slots use camelCase keys that map to slot positions:
| Config Key | Slot Position |
| ------------------ | ------------------ |
| `beforeNavigation` | `shell:nav-start` |
| `afterNavigation` | `shell:nav-end` |
| `header` | `shell:header` |
| `footer` | `shell:footer` |
| `beforeDashboard` | `dashboard:before` |
| `afterDashboard` | `dashboard:after` |
| `beforeLogin` | `login:before` |
| `afterLogin` | `login:after` |
```typescript
admin: {
components: {
beforeDashboard: () =>
import('./app/announcement-banner.component').then((m) => m.AnnouncementBanner),
footer: () =>
import('./app/custom-footer.component').then((m) => m.CustomFooter),
},
},
```
### Config-level (per-collection slots)
```typescript
// In the collection definition:
admin: {
components: {
beforeList: () => import('./articles-filter.component').then((m) => m.ArticlesFilter),
editSidebar: () => import('./meta-panel.component').then((m) => m.MetaPanel),
beforeView: () => import('./status-badge.component').then((m) => m.StatusBadge),
},
},
```
Per-collection config keys: `beforeList`, `afterList`, `beforeEdit`, `afterEdit`, `editSidebar`, `beforeView`, `afterView`.
### Provider-level (app.config.ts)
```typescript
import { provideAdminSlot } from '@momentumcms/admin';
providers: [
// Global slot (all pages)
provideAdminSlot('shell:header', () =>
import('./env-banner.component').then((m) => m.EnvBanner),
),
// Per-collection slot
provideAdminSlot('collection-list:before:articles', () =>
import('./articles-filter.component').then((m) => m.ArticlesFilter),
),
],
```
### Per-Collection Slot Merging
When viewing a collection page, both global and per-collection slot components render (global first, then per-collection).
## Component Conventions
Custom components receive context via Angular inputs:
```typescript
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import type { CollectionConfig } from '@momentumcms/core';
@Component({
selector: 'app-custom-slot',
host: { class: 'block' },
template: `
<div class="p-4 bg-mcms-muted rounded-lg">
@if (collection(); as col) {
<p>Collection: {{ col.slug }}</p>
}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomSlotComponent {
readonly collection = input<CollectionConfig>();
readonly entityId = input<string>();
}
```
## After Making Changes
1. If you modified `momentum.config.ts`, regenerate the browser-safe config:
```bash
nx run <app>:generate # or npm run generate in generated apps
```
2. The generated config at `src/generated/momentum.config.ts` will include the component loaders with correct import paths.
3. Provider-level changes in `app.config.ts` take effect immediately (no generation needed).
## Plugin Registration
Plugins can declare admin component overrides:
```typescript
const myPlugin: MomentumPlugin = {
name: 'my-plugin',
adminComponents: {
beforeDashboard: () => import('./plugin-banner').then((m) => m.PluginBanner),
header: () => import('./custom-header').then((m) => m.CustomHeader),
},
};
```
## Exports from @momentumcms/admin
```typescript
import {
provideAdminComponent, // Register page override via DI
provideAdminSlot, // Register slot component via DI
} from '@momentumcms/admin';
```
## Related Files
- `libs/core/src/lib/config.ts` — `AdminComponentsConfig` (global slots/pages)
- `libs/core/src/lib/collections/collection.types.ts` — `CollectionAdminComponentsConfig` (per-collection)
- `libs/admin/src/lib/services/admin-component-registry.service.ts` — Page resolver registry
- `libs/admin/src/lib/services/admin-slot-registry.service.ts` — Slot registry
- `libs/admin/src/lib/services/provide-admin-components.ts` — Provider functions
- `libs/admin/src/lib/components/admin-page-resolver/` — Route-level page resolver
- `libs/admin/src/lib/components/admin-slot-outlet/` — Slot rendering component
- `docs/admin/customization.md` — User-facing documentation
---
name: admin-customize-3b19e80abd18
description: Customize the admin UI with swappable pages and layout slots. Use when replacing built-in pages (dashboard, list, edit, view), injecting content into layout slots (header, footer, sidebar, before/after), or registering per-collection overrides.
argument-hint: <page-override|slot|per-collection>
---
# Admin Customization — Swappable Pages & Layout Slots
Guide for customizing the Momentum CMS admin UI via page replacements and layout slot injection.
## Arguments
- `$ARGUMENTS` - What to customize: `page-override`, `slot`, or `per-collection`
## Two Registration Methods
### 1. Config-level (momentum.config.ts)
Registered in the server config. The code generator emits these as loader functions in the browser-safe generated config. This is the recommended approach — single source of truth.
### 2. Provider-level (app.config.ts)
Registered via Angular DI providers. Useful for app-specific customizations that don't belong in the server config, or for login page slots (which render outside the admin shell).
## Swappable Pages (Full Replacement)
### Available Page Keys
| Key | Built-in Page |
| ----------------- | --------------- |
| `dashboard` | Dashboard |
| `login` | Login |
| `media` | Media Library |
| `collection-list` | Collection List |
| `collection-edit` | Collection Edit |
| `collection-view` | Collection View |
| `global-edit` | Global Edit |
### Config-level (momentum.config.ts)
```typescript
import { defineMomentumConfig } from '@momentumcms/core';
export default defineMomentumConfig({
// ...
admin: {
basePath: '/admin',
components: {
dashboard: () => import('./app/custom-dashboard.component').then((m) => m.CustomDashboard),
},
},
});
```
### Provider-level (app.config.ts)
```typescript
import { provideAdminComponent } from '@momentumcms/admin';
export const appConfig: ApplicationConfig = {
providers: [
provideAdminComponent('dashboard', () =>
import('./custom-dashboard.component').then((m) => m.CustomDashboard),
),
],
};
```
### Per-Collection Page Overrides
Override pages for a specific collection only. Other collections keep the default.
#### Config-level (on the collection definition)
```typescript
const collections = baseCollections.map((c) => {
if (c.slug === 'articles') {
return {
...c,
admin: {
...c.admin,
components: {
list: () =>
import('./app/custom-articles-list.component').then(
(m) => m.CustomArticlesListComponent,
),
},
},
};
}
return c;
});
```
#### Provider-level
```typescript
provideAdminComponent('collections/articles/list', () =>
import('./custom-articles-list.component').then((m) => m.CustomArticlesList),
);
```
### Resolution Chain
For collection pages, the resolver checks in order:
1. Per-collection override (`collections/{slug}/{type}`)
2. Global override (`collection-list`)
3. Built-in default
## Layout Slots (Additive Injection)
Slots inject content around existing pages without replacing them. Multiple components can be registered for the same slot.
### Available Slots
#### Shell Slots (visible on all authenticated pages)
| Slot Key | Position |
| ----------------- | ------------------------------- |
| `shell:header` | Top of main content area |
| `shell:footer` | Bottom of main content area |
| `shell:nav-start` | After Dashboard link in sidebar |
| `shell:nav-end` | After plugin routes in sidebar |
#### Page Slots
| Slot Key | Position |
| -------------------------------------- | ------------------------ |
| `dashboard:before/after` | Around dashboard content |
| `collection-list:before/after` | Around list tables |
| `collection-edit:before/after/sidebar` | Around edit forms |
| `collection-view:before/after` | Around view pages |
| `login:before/after` | Around login form |
### Config-level (momentum.config.ts — admin.components)
Config-level slots use camelCase keys that map to slot positions:
| Config Key | Slot Position |
| ------------------ | ------------------ |
| `beforeNavigation` | `shell:nav-start` |
| `afterNavigation` | `shell:nav-end` |
| `header` | `shell:header` |
| `footer` | `shell:footer` |
| `beforeDashboard` | `dashboard:before` |
| `afterDashboard` | `dashboard:after` |
| `beforeLogin` | `login:before` |
| `afterLogin` | `login:after` |
```typescript
admin: {
components: {
beforeDashboard: () =>
import('./app/announcement-banner.component').then((m) => m.AnnouncementBanner),
footer: () =>
import('./app/custom-footer.component').then((m) => m.CustomFooter),
},
},
```
### Config-level (per-collection slots)
```typescript
// In the collection definition:
admin: {
components: {
beforeList: () => import('./articles-filter.component').then((m) => m.ArticlesFilter),
editSidebar: () => import('./meta-panel.component').then((m) => m.MetaPanel),
beforeView: () => import('./status-badge.component').then((m) => m.StatusBadge),
},
},
```
Per-collection config keys: `beforeList`, `afterList`, `beforeEdit`, `afterEdit`, `editSidebar`, `beforeView`, `afterView`.
### Provider-level (app.config.ts)
```typescript
import { provideAdminSlot } from '@momentumcms/admin';
providers: [
// Global slot (all pages)
provideAdminSlot('shell:header', () =>
import('./env-banner.component').then((m) => m.EnvBanner),
),
// Per-collection slot
provideAdminSlot('collection-list:before:articles', () =>
import('./articles-filter.component').then((m) => m.ArticlesFilter),
),
],
```
### Per-Collection Slot Merging
When viewing a collection page, both global and per-collection slot components render (global first, then per-collection).
## Component Conventions
Custom components receive context via Angular inputs:
```typescript
import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import type { CollectionConfig } from '@momentumcms/core';
@Component({
selector: 'app-custom-slot',
host: { class: 'block' },
template: `
<div class="p-4 bg-mcms-muted rounded-lg">
@if (collection(); as col) {
<p>Collection: {{ col.slug }}</p>
}
</div>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomSlotComponent {
readonly collection = input<CollectionConfig>();
readonly entityId = input<string>();
}
```
## After Making Changes
1. If you modified `momentum.config.ts`, regenerate the browser-safe config:
```bash
nx run <app>:generate # or npm run generate in generated apps
```
2. The generated config at `src/generated/momentum.config.ts` will include the component loaders with correct import paths.
3. Provider-level changes in `app.config.ts` take effect immediately (no generation needed).
## Plugin Registration
Plugins can declare admin component overrides:
```typescript
const myPlugin: MomentumPlugin = {
name: 'my-plugin',
adminComponents: {
beforeDashboard: () => import('./plugin-banner').then((m) => m.PluginBanner),
header: () => import('./custom-header').then((m) => m.CustomHeader),
},
};
```
## Exports from @momentumcms/admin
```typescript
import {
provideAdminComponent, // Register page override via DI
provideAdminSlot, // Register slot component via DI
} from '@momentumcms/admin';
```
## Related Files
- `libs/core/src/lib/config.ts` — `AdminComponentsConfig` (global slots/pages)
- `libs/core/src/lib/collections/collection.types.ts` — `CollectionAdminComponentsConfig` (per-collection)
- `libs/admin/src/lib/services/admin-component-registry.service.ts` — Page resolver registry
- `libs/admin/src/lib/services/admin-slot-registry.service.ts` — Slot registry
- `libs/admin/src/lib/services/provide-admin-components.ts` — Provider functions
- `libs/admin/src/lib/components/admin-page-resolver/` — Route-level page resolver
- `libs/admin/src/lib/components/admin-slot-outlet/` — Slot rendering component
- `docs/admin/customization.md` — User-facing documentation
COMPATIBILITY & REFERENCES
Platform guidance
Imported from the listed AgentSkill.sh category. Complete supplied package files and notices are retained. Required external tools and credentials are not installed. No bundled code was executed during import. Individual agent task behavior has not been tested.
Creates comprehensive frontend UI/UX designs including user interfaces, design systems, component libraries, responsive layouts, and accessibility implementations. Produces wireframes, mockups, design specifications, and implementation guidelines. Use when designing user interfaces, creating desi...
Expert in building scalable design systems with Atomic Design, design tokens, and theming infrastructure. Use when creating component libraries, implementing dark mode, or establishing typography and color systems. Covers multi-brand support, Storybook-driven development, and accessibility-first ...
Use when implementing Liquid Glass effects, reviewing UI for Liquid Glass adoption, debugging visual artifacts, optimizing performance, or requesting expert review of Liquid Glass implementation - provides comprehensive design principles, API patterns, and troubleshooting guidance from WWDC 2025....