Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4eead9d
Add Table Collection View docs and TOC
madsrasmussen May 6, 2026
e7b1dee
change custom view implementation from table to a simpler example
madsrasmussen May 6, 2026
f43a2dd
Update table.md
madsrasmussen May 6, 2026
357dcd5
Add Collection docs and update collections overview
madsrasmussen May 7, 2026
56aa805
Update README.md
madsrasmussen May 7, 2026
14f4080
Update README.md
madsrasmussen May 7, 2026
5cd77b4
Add UmbCollectionItemModel to docs
madsrasmussen May 7, 2026
c218b96
remove redundant information
madsrasmussen May 7, 2026
be68979
remove redundant information
madsrasmussen May 7, 2026
05a0f57
Update table.md
madsrasmussen May 7, 2026
52ea400
Clarify collection-view docs and model refs
madsrasmussen May 7, 2026
4223956
change flow
madsrasmussen May 7, 2026
5f55cfc
Split collection view into view and item elements
madsrasmussen May 7, 2026
6fef695
Add select-only mode for collection items
madsrasmussen May 7, 2026
d2d080c
Update README.md
madsrasmussen May 7, 2026
8fd6643
Merge branch 'main' into v17/feature/table-kind-collection-view
madsrasmussen May 12, 2026
845135e
Merge branch 'main' into v17/feature/table-kind-collection-view
madsrasmussen May 12, 2026
2b8c4f4
Create collection.md
madsrasmussen May 12, 2026
9fb7621
move to new location
madsrasmussen May 12, 2026
7f969d1
Update SUMMARY.md
madsrasmussen May 12, 2026
9c926c7
Update SUMMARY.md
madsrasmussen May 12, 2026
4a2bf24
Remove Collection Action link from README
madsrasmussen May 12, 2026
4f388c8
Fix relative link to Fetching Data README
madsrasmussen May 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions 17/umbraco-cms/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,9 @@
* [Workspace Footer Apps](extend-your-project/backoffice-extensions/extending-overview/extension-types/workspaces/workspace-footer-apps.md)
* [Workspace Views](extend-your-project/backoffice-extensions/extending-overview/extension-types/workspaces/workspace-views.md)
* [Collections](extend-your-project/backoffice-extensions/extending-overview/extension-types/collections/README.md)
* [Collection](extend-your-project/backoffice-extensions/extending-overview/extension-types/collections/collection.md)
* [Collection View](extend-your-project/backoffice-extensions/extending-overview/extension-types/collections/collection-view/README.md)
* [Table View](extend-your-project/backoffice-extensions/extending-overview/extension-types/collections/collection-view/table.md)
* [Card View](extend-your-project/backoffice-extensions/extending-overview/extension-types/collections/collection-view/card.md)
* [Reference View](extend-your-project/backoffice-extensions/extending-overview/extension-types/collections/collection-view/reference.md)
* [Custom View](extend-your-project/backoffice-extensions/extending-overview/extension-types/collections/collection-view/custom.md)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
---
description: >-
An overview of the available extension types related to collections.
Learn how to register a Collection extension, connect it to a Collection Repository and configure Collection Views to display entity lists.
---

# Extension Types: Collections
# Collections

A Collection is an extension that fetches and exposes a list of entities in the Umbraco backoffice. It connects a **Collection Repository**, for fetching data, and one or more **Collection Views** (the display layer).

The Collection itself does not render anything. It manages pagination, filtering, and selection state — the Collection Views decide how items are presented.

## How the parts relate

| Part | Role |
|---|---|
| **Collection** | Registers the extension and points to a repository alias |
| **Collection Repository** | Fetches and returns items |
| **Collection View** | Bound to the collection via its alias; renders the items |

## Articles

* [Collection](collection.md)
* [Collection View](collection-view/README.md)
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Before creating a Collection View, make sure you are familiar with the [Extensio

There are a couple of built-in Collection Views Kinds available in Umbraco, each suited for different display needs. You can also create custom Collection Views if the built-in options do not meet your requirements.

- **[Table View](table.md)**: Displays entities in a table layout with configurable columns.
- **[Card View](card.md)**: Displays entities as cards in a grid layout, suitable for visual content.
- **[Reference View](reference.md)**: Displays entities in a list-style layout.
- **[Custom View](custom.md)**: Create your own Collection View from scratch to meet specific requirements.
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,9 @@

When you want to display entities as cards within a collection, use the Card Collection View Kind. This will render a card-style grid layout. Each card renders a default layout with the entity's name and icon. You can further customize the card layout by registering a custom card collection item as needed.

The default Collection Item Model used in a Card Collection View is based on the following interface:
The Card Collection View renders items produced by a [Collection](../collection.md). The collection is responsible for fetching items through its [Collection Repository](../collection.md#collection-repository).

```typescript
export interface UmbCollectionItemModel {
unique: string;
entityType: string;
name?: string;
icon?: string;
}
```
Each card renders fields from your collection item model. For details on defining and extending the item model, see [Collection](../collection.md#item-model).

Register the Card Collection View in the extension registry with the kind set to "card":

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,26 @@

When the existing Collection View kinds do not meet your requirements, you can create a custom Collection View from scratch.

A Custom Collection View renders items produced by a [Collection](../collection.md). The collection is responsible for fetching items through its [Collection Repository](../collection.md#collection-repository).

## Manifest

{% code title="umbraco-package.json" %}
```json
{
"type": "collectionView",
"alias": "My.CollectionView.Alias",
"name": "My Collection View",
"alias": "My.CollectionView.Custom",
"name": "My Custom Collection View",
"element": "/App_Plugins/my-collection-view/my-collection-view.js",
"meta": {
"label": "Table",
"label": "My View",
"icon": "icon-list",
"pathName": "table"
"pathName": "my-view"
},
"conditions": [
{
"alias": "Umb.Condition.CollectionAlias",
"match": "Umb.Collection.Document" // Collection alias to display this collection view for
"match": "My.Collection" // Collection alias to display this collection view for
}
]
}
Expand All @@ -28,127 +30,133 @@ When the existing Collection View kinds do not meet your requirements, you can c

## Implementation

Implement your Collection View as a Lit element that extends `UmbLitElement`.
This defines how a list of entities is rendered in your collection.
Implement the Collection View as a Lit element that extends `UmbCollectionViewElementBase`. The base class provides the collection items via `_items`, handles selection state, and exposes helper methods such as `_isSelectableItem` and `_isSelectedItem`. Override `render()` to define how the collection is displayed.

Split the view into two elements: a view element that handles the layout and delegates item rendering to a dedicated item element.

{% code title="my-collection-view.ts" %}
```typescript
import { css, customElement, html, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UMB_DOCUMENT_COLLECTION_CONTEXT } from '@umbraco-cms/backoffice/document';
import type { UmbDocumentCollectionItemModel } from '@umbraco-cms/backoffice/document';
import type { UmbCollectionColumnConfiguration } from '@umbraco-cms/backoffice/collection';
import { customElement, html, nothing } from '@umbraco-cms/backoffice/external/lit';
import { UmbCollectionViewElementBase } from '@umbraco-cms/backoffice/collection';
import type { UmbCollectionItemModel } from '@umbraco-cms/backoffice/collection';
import './my-collection-view-item.element.js';

@customElement('my-document-table-collection-view')
export class MyDocumentTableCollectionViewElement extends UmbLitElement {
@customElement('my-collection-view')
export class MyCollectionViewElement extends UmbCollectionViewElementBase {

@state() private _columns: Array<{ name: string; alias: string; align?: string }> = [];
@state() private _items?: Array<UmbDocumentCollectionItemModel> = [];

constructor() {
super();
override render() {
if (this._loading) return nothing;
return html`
<div>
${this._items.map((item) => this.#renderItem(item))}
</div>
`;
}

this.consumeContext(UMB_DOCUMENT_COLLECTION_CONTEXT, (collectionContext) => {
collectionContext?.setupView(this);
#renderItem(item: UmbCollectionItemModel) {
return html`
<my-collection-view-item
.item=${item}
.href=${item.unique ? this._itemHrefs.get(item.unique) : undefined}
?selectable=${this._isSelectableItem(item)}
?selected=${this._isSelectedItem(item.unique)}
?selectOnly=${this._selectOnly}
@selected=${() => this._selectItem(item.unique)}
@deselected=${() => this._deselectItem(item.unique)}>
</my-collection-view-item>
`;
}
}

this.observe(collectionContext?.userDefinedProperties, (props) => {
this.#createColumns(props);
});
export { MyCollectionViewElement as element };

this.observe(collectionContext?.items, (items) => {
this._items = items;
});
});
declare global {
interface HTMLElementTagNameMap {
'my-collection-view': MyCollectionViewElement;
}
}
```
{% endcode %}

The item element receives the item model as a property and dispatches `UmbSelectedEvent` and `UmbDeselectedEvent` when the user interacts with the selection control. The base class on the parent view handles these events automatically.

{% code title="my-collection-view-item.element.ts" %}
```typescript
import { UmbDeselectedEvent, UmbSelectedEvent } from '@umbraco-cms/backoffice/event';
import { customElement, html, nothing, property } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import { UmbEntityContext } from '@umbraco-cms/backoffice/entity';
import type { UmbCollectionItemModel } from '@umbraco-cms/backoffice/collection';

@customElement('my-collection-view-item')
export class MyCollectionViewItemElement extends UmbLitElement {

#item?: UmbCollectionItemModel;
#entityContext?: UmbEntityContext;

#createColumns(userProps: Array<UmbCollectionColumnConfiguration> = []) {
const baseCols = [
{ name: 'Name', alias: 'name' },
{ name: 'State', alias: 'state' },
];
const userCols = userProps.map((p) => ({
name: p.nameTemplate ?? p.alias,
alias: p.alias,
}));
this._columns = [...baseCols, ...userCols, { name: '', alias: 'entityActions', align: 'right' }];
@property({ type: Object })
get item(): UmbCollectionItemModel | undefined {
return this.#item;
}
set item(value: UmbCollectionItemModel | undefined) {
const oldValue = this.#item;
this.#item = value;
if (value) {
this.#entityContext = new UmbEntityContext(this);
this.#entityContext.setEntityType(value.entityType);
this.#entityContext.setUnique(value.unique);
} else {
this.#entityContext?.destroy();
this.#entityContext = undefined;
}
this.requestUpdate('item', oldValue);
}

@property({ type: Boolean })
selectable = false;

@property({ type: Boolean })
selected = false;

@property({ type: Boolean })
selectOnly = false;

@property({ type: String })
href?: string;

override render() {
if (this._items === undefined) return html`<p>Not found...</p>`;
if (!this.item) return nothing;

return html`
<table>
<thead>
<tr>
${this._columns.map((col) => html`<th style="text-align:${col.align ?? 'left'}">${col.name}</th>`)}
</tr>
</thead>
<tbody>
${this._items.map(
(item) => html`
<tr>
${this._columns.map((col) => {
switch (col.alias) {
case 'name':
return html`<td><a href="#">${item.name}</a></td>`;
case 'state':
return html`<td>${item.state}</td>`;
case 'sortOrder':
return html`<td>${item.sortOrder}</td>`;
case 'updateDate':
return html`<td>${item.updateDate}</td>`
case 'creator':
return html`<td>${item.creator}</td>`;
case 'entityActions':
return html`<td style="text-align:right;">⋮</td>`;
default:
const val = item.values.find((v) => v.alias === col.alias)?.value ?? '';
return html`<td>${val}</td>`;
}
})}
</tr>
`
)}
</tbody>
</table>
<div>
${this.selectable
? html`<input
type="checkbox"
.checked=${this.selected}
@change=${() => this.selected ? this.#onDeselected() : this.#onSelected()}/>`
: nothing}
${this.href && !this.selectOnly
? html`<a href=${this.href}>${this.item.name}</a>`
: html`<span>${this.item.name}</span>`}
<umb-entity-actions-bundle></umb-entity-actions-bundle>
Comment thread
AndyButland marked this conversation as resolved.
</div>
`;
}

static override styles = css`
:host {
display: block;
width: 100%;
overflow-x: auto;
font-family: sans-serif;
}
table {
width: 100%;
border-collapse: collapse;
}
th,
td {
padding: 6px 10px;
border: 1px solid #ddd;
white-space: nowrap;
}
th {
background: #f8f8f8;
font-weight: 600;
}
a {
color: var(--uui-color-interactive, #0366d6);
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
`;
}
#onSelected() {
if (!this.item) return;
this.dispatchEvent(new UmbSelectedEvent(this.item.unique));
}

export default MyDocumentTableCollectionViewElement;
#onDeselected() {
if (!this.item) return;
this.dispatchEvent(new UmbDeselectedEvent(this.item.unique));
}
}

declare global {
interface HTMLElementTagNameMap {
'my-document-table-collection-view': MyDocumentTableCollectionViewElement;
'my-collection-view-item': MyCollectionViewItemElement;
}
}
```
Expand All @@ -159,7 +167,7 @@ declare global {
Use the `match` property in your manifest to target a specific collection type.

| **Match Value** | **Description** |
|------------------|-----------------|
|---|---|
| `Umb.Collection.Document` | Targets the **Document** collection (content items). |
| `Umb.Collection.Media` | Targets the **Media** collection (images, videos, files). |
| `Umb.Collection.Member` | Targets the **Member** collection. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,9 @@

When you want to display entities as a list of references within a collection, use the Reference Collection View Kind. This will render a basic list layout. Each item renders a default layout with the entity's name and icon. You can further customize the item layout by registering a custom Ref Collection Item when needed.

The default Collection Item Model used in a Reference Collection View is based on the following interface:
The Reference Collection View renders items produced by a [Collection](../collection.md). The collection is responsible for fetching items through its [Collection Repository](../collection.md#collection-repository).

```typescript
export interface UmbCollectionItemModel {
unique: string;
entityType: string;
name?: string;
icon?: string;
}
```
Each item renders fields from your collection item model. For details on defining and extending the item model, see [Collection](../collection.md#item-model).

Register the Reference Collection View in the extension registry with the kind set to "ref":

Expand Down
Loading
Loading