---
title: "Collections: an ordered list of Blocks"
description: "The collection Block type: its items and stored query, the node view with reorder and „Aus Abfrage füllen“, the block action that adds a Block, and the Markdown export."
canonical_url: "https://skaile-ai.github.io/forge-editor/guides/collections"
---
# Collections: an ordered list of Blocks

> The collection Block type: its items and stored query, the node view with reorder and „Aus Abfrage füllen“, the block action that adds a Block, and the Markdown export.

A **collection** is a [Typed block](https://skaile-ai.github.io/forge-editor/guides/composites) of the Block type `collection` that lists other Blocks, in an order the user sets. It points at its Blocks and holds none of them: removing an entry, or the collection, never touches the Block. A reading list, the Blocks of a chapter that live in several Documents, or the hits of a [query](https://skaile-ai.github.io/forge-editor/guides/query) a person curated are collections.

`defaultBlockTypes(t)` lists the type (label „Sammlung“ / "Collection", icon `i-lucide-list-checks`, capabilities `container` with `'all'`, the colour basket, `properties` and `export`), so a host that spreads the built-in list has it.

## What a collection stores

Two [Block properties](https://skaile-ai.github.io/forge-editor/guides/block-properties) in the Typed block's `meta`:

<table>
<thead>
  <tr>
    <th>
      Key
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Meaning
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        items
      </code>
    </td>
    
    <td>
      <code>
        reference-list
      </code>
    </td>
    
    <td>
      the entries, in order: <code>
        BlockAddress[]
      </code>
      
       (<code>
        { documentId, blockId }
      </code>
      
      ; <code>
        documentId
      </code>
      
       <code>
        ''
      </code>
      
       is a Block of this Document)
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        query
      </code>
    </td>
    
    <td>
      <code>
        text
      </code>
      
      , hidden
    </td>
    
    <td>
      an optional <code>
        DataQuery
      </code>
      
       as JSON text, for „Aus Abfrage füllen“; the properties form never shows it
    </td>
  </tr>
</tbody>
</table>

The framework-free functions in `@skaile/forge-editor/composites` read and build these values:

```ts
import { collectionItemsOf, collectionQueryOf, withCollectionItems } from '@skaile/forge-editor/composites'

collectionItemsOf(node)          // BlockAddress[]; entries that are no valid address are dropped
collectionQueryOf(node)          // DataQuery | null; null for no query, bad JSON or a query that names no Block type
withCollectionItems(node, items) // a copy of node's meta with `items` as its list; an empty list removes the key
```

`collectionQueryOf` checks only the shape (`v: 1`, a `blocks` source that names a Block type). Which fields exist is the job of `validateQuery`; the route answers `422` with the issues when the stored query is wrong.

Write the list through `setBlockProperty` (or `setCollectionItems(editor, blockId, items)`, which does that): it writes the one key, so two collaborators who edit different keys of the same block keep both changes.

## The view

Both bindings supply a node view for the collection (`CompositeNodeViews.collection`): the usual Typed block view with the entries below its content.

- Every entry is a reference pill with the title of its Block (an entry whose Block is gone shows „Block gelöscht“). A click reveals the Block in the open Document, or opens it in its own Document through the host's `openBlock`.
- Move up, move down and remove buttons appear beside an entry while the editor is editable.
- „Aus Abfrage füllen“ shows when the collection has a stored query and `backend.index.query` exists. It runs the query, appends the hits that are not listed yet in the order of the answer, and tells the user how many it added (a collection never lists itself). A failed query leaves the list as it is and says why.

The view is `features/composites/collection-model.ts` (`collectionViewOf`, `moveCollectionItem`, `removeCollectionItem`, `fillCollectionFromQuery`), shared by `CollectionView.vue` and `CollectionView.tsx`. A binding that renders no live content leaves `collection` out of `nodeViews`; the collection then renders as any Typed block and its entries stay in `meta.items`.

Both bindings pass `typedBlockViewOptions` (`@skaile/forge-editor/composites`) to the renderer of `typedBlock` and `collection`, so a block whose Block type changes gets the view of its new type. A host that builds its own `nodeViews` does the same:

```ts
compositeNodes({
  typedBlock: VueNodeViewRenderer(CompositeView, typedBlockViewOptions),
  collection: VueNodeViewRenderer(CollectionView, typedBlockViewOptions),
  reference: VueNodeViewRenderer(ReferenceView),
})
```

## Add a Block from anywhere

The block action `collection-add` („Zu Sammlung hinzufügen“, Ability `composite.meta`) is on every Typed block. Its menu lists the collections of the open Document by title (one that holds the Block already is disabled; the action is hidden when the Document has no other collection), and choosing one appends the Block's address.

## Markdown export

The Markdown form of a collection lists its entries as reference lines, one chip per paragraph, in the stored order:

```md
# Lesestoff

[@3f0c…]

[@doc-9#a41b…]
```

An entry in another Document carries the Document first (`[@<documentId>#<blockId>]`), the same form as a [reference chip](https://skaile-ai.github.io/forge-editor/guides/composites). `documentCompositeMarkdown`, `headingsMarkdown` and the `markdown` render target all go through `compositeChromeBlocks`, which appends `collectionItemBlocks(schema, node)` for a collection. The meta line leaves out hidden properties (the stored query) and `reference-list` properties, so neither shows as `[object Object]`.


## Sitemap

See the full [sitemap](https://skaile-ai.github.io/forge-editor/sitemap.md) for all pages.
