---
title: "Render containers"
manual: "Headless Content Blocks"
version: "main"
permalink: "https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:render-containers@main"
source: "Howto/RenderContainers.rst"
rendered: "2026-09-22T01:10:25+00:00"
---

# Render containers {#render-containers}

This guide shows how to output EXT:container (b13/container) elements with this extension — the container's columns as JSON alongside or inside the container's own `data`.

## Prerequisites {#prerequisites}

-   EXT:container installed (`composer require b13/container`)
-   Container Content Types defined (e.g. the `b13_2_columns_container` used below, with child columns `colPos` 201 and 202)

`b13/container` is a *suggested* dependency — the extension works without it; the `nb-container-json` processor only loads when EXT:container is present.

## TypoScript setup {#typoscript-setup}

### Variant 1: `left`/`right` parallel to `data` {#variant-1-left-right-parallel-to-data}

```typoscript
lib.content.select.where = colPos NOT IN (201, 202)

tt_content.b13_2_columns_container =< lib.contentElement
tt_content.b13_2_columns_container {
    fields {
        left = TEXT
        left {
            dataProcessing {
                10 = nb-container-json
                10 {
                    colPos = 201
                    as = left
                }
            }
        }
        right = TEXT
        right {
            dataProcessing {
                10 = nb-container-json
                10 {
                    colPos = 202
                    as = right
                }
            }
        }
    }
}
```

Result: the container element carries `left`/`right` next to `data`:

```json
{
    "id": 5,
    "type": "b13_2_columns_container",
    "colPos": 0,
    "left": [ { "id": 6, "type": "vendor_text", "data": { "...": "..." } } ],
    "right": [ { "id": 7, "type": "vendor_image", "data": { "...": "..." } } ]
}
```

### Variant 2: `left`/`right` inside `data` {#variant-2-left-right-inside-data}

```typoscript
lib.content.select.where = colPos NOT IN (201, 202)

tt_content.b13_2_columns_container.fields.data.dataProcessing.10 {
    dataProcessing {
        10 = nb-container-json
        10 {
            colPos = 201
            as = left
        }

        20 = nb-container-json
        20 {
            colPos = 202
            as = right
        }
    }
}
```

This is the sub data processor pattern from [Add sub data processors](https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:add-sub-data-processors@main) — the columns land as keys inside `data`.

## How it works {#how-it-works}

`nb-container-json` (`ContainerJsonDataProcessor`) fetches the container's children for the given `colPos` via b13/container's `ContainerProcessor` and renders each child through the same conversion as `nb-content-blocks-json` — field identifiers as keys, same [JSON contract](https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:json-contract@main).

Both variants are covered end-to-end by `Tests/Functional/Frontend/ContentBlocksJsonResponseTest.php`.

## Container as Content Block (variant 2): keep your own fields {#container-as-content-block-variant-2-keep-your-own-fields}

When the container itself is a Content Block (variant 2), do **not** register it with `Registry::configureContainer()`: b13/container would overwrite the `types[<cType>]['showitem']` of the Content Block, and the resolved record (and thereby `data`) would lose the Content Block's own fields. Write the `containerConfiguration` directly into TCA instead — this keeps the Content Block's showitem while b13/container still recognizes the container:

```php
$configuration = new \B13\Container\Tca\ContainerConfiguration(
    'vendor_mycontainer',
    'My Container',
    '',
    [[['name' => 'main', 'colPos' => 201]]]
);
$GLOBALS['TCA']['tt_content']['containerConfiguration']['vendor_mycontainer']
    = $configuration->toArray();
```

## The `colPos` exclusion matters {#the-colpos-exclusion-matters}

`lib.content.select.where = colPos NOT IN (201, 202)` keeps the container children out of the regular page content query. Without it, children appear twice: once in the page's content array and once in their column.

## Options {#options}

The processor accepts `colPos` (container column to fetch, required) and `as` (key of the children array). Children are rendered through their own `tt_content.<CType>` mapping, so their conversion options ([processor options](https://docs.typo3.org/permalink/netzbewegung/nb-headless-content-blocks:processor-options@main) like `options.processing` or `options.dateTimeFormat`) are configured there, not on `nb-container-json`.

If the container cannot be built (e.g. the record is hidden), `as` is an empty list. Children without a `renderedContent` key — e.g. with b13's `skipRenderingChildContent` and no substitute data processor — become `null` entries.
