Strapi Column Control

Strapi Column Control

By Brain Station 23

Column Control adds flexible layouts to Strapi 5 dynamic zones. It lets editors control how content is arranged and create custom page layouts.

Latest version

v1.0.4

released August 13, 2026

npm install strapi-column-control

Strapi Column Control

Column layouts for Strapi 5 Dynamic Zones — container → row → columns — without replacing your existing components. Map column_class on the frontend with any CSS library, framework, or custom grid.

npm · GitHub · Changelog

Requires Strapi 5 (@strapi/strapi ^5.43) and Node.js 20–26.

npm install strapi-column-control

What it does

Editors add a Column control block to a Dynamic Zone. Each column has a nested blocks zone where they stack the same components you already use (headlines, buttons, images, custom types).

Article dynamic_zone
 └── Column control              layout (container, row, columns)
      ├── Column 1 (span 6)
      │    └── blocks[]          your components, in order
      └── Column 2 (span 6)
           └── blocks[]          same allow-list as the parent zone
  • column_class is a numeric span (for example 6). Your frontend maps it to Bootstrap, Tailwind, CSS Grid, or any custom classes.
  • Spans in one row must sum to gridColumns (default 12).
  • blocks render in array order.

Install

From your Strapi 5 project root:

npm install strapi-column-control

Enable the plugin in config/plugins.ts:

export default {
  'strapi-column-control': {
    enabled: true,
    config: {
      gridColumns: 12, // max sum of column_class per row
    },
  },
};

Restart Strapi. postinstall patches Content-Type Builder so you can edit Dynamic Zones that include this plugin.

Config

KeyDefaultPurpose
gridColumns12Maximum sum of column_class in one Column control block
columnBlocksautoOptional extra UIDs for column blocks. Prefer adding types on the parent Dynamic Zone instead

Allowed content in columns

Add Column control and your block types to the parent Dynamic Zone (dynamic_zone, sections, and so on):

"components": [
  "plugin::strapi-column-control.layout.column-control",
  "atoms.button",
  "atoms.headline-text"
]

Restart Strapi. The plugin copies those UIDs into each column’s blocks zone. Editors add instances in Content Manager.

Content-Type Builder

  1. Create components as usual.
  2. Open the content type → edit the Dynamic Zone → Add components → select the new types → Finish.
  3. Click Save in the CTB top bar (not only modal Finish) and wait for Strapi to restart.

Do not edit the plugin Column component’s blocks list in CTB. That allow-list is derived from the host Dynamic Zone. Emptying it fails validation; the UI blocks editing plugin layout zones when possible.

Component UIDs

UIDRole
plugin::strapi-column-control.layout.column-controlLayout block on the host Dynamic Zone
plugin::strapi-column-control.layout.columnOne column (span + blocks)

Fields

FieldDescription
configurationContainer width, padding, gutter, reverse on mobile
columnsRepeatable columns
columns.column_classSpan units; row total ≤ gridColumns
columns.blocksNested Dynamic Zone (parent DZ types + optional columnBlocks)
columns.admin_labelPrivate Content Manager title (auto)

Example: 5 + 5 + 2 = 12 when gridColumns is 12. The REST JSON shape is stable across upgrades.

REST populate=*

Document middleware deepens shallow Dynamic Zone populate so nested columnsblocks are returned.

Mapper service

const mapper = strapi.plugin('strapi-column-control').service('mapper');

const { gridColumns } = mapper.getGridConfig();
const { valid, violations, message } = mapper.validateColumnSpans(entry.dynamic_zone);
const mapped = mapper.mapColumnControl(section); // host maps column_class to CSS
RouteAuthReturns
POST /api/strapi-column-control/mappublic{ configuration, mapped, classes, html }
GET /admin/strapi-column-control/grid-configadmin{ gridColumns }

Example API JSON

Two columns. Each blocks array can hold several components:

{
  "__component": "plugin::strapi-column-control.layout.column-control",
  "configuration": {
    "container_width": "default",
    "container_padding": "default",
    "gutter": "default",
    "reverse_on_mobile": false
  },
  "columns": [
    {
      "column_class": 6,
      "blocks": [
        {
          "__component": "atoms.headline-text",
          "title": "Welcome",
          "subtitle": "Blocks in this column stack top to bottom"
        },
        {
          "__component": "atoms.button",
          "button_text": "Get started",
          "url": "/signup"
        }
      ]
    },
    {
      "column_class": 6,
      "blocks": [
        {
          "__component": "atoms.headline-text",
          "title": "Features",
          "subtitle": "Any type allowed on the parent Dynamic Zone"
        },
        {
          "__component": "atoms.button",
          "button_text": "Learn more",
          "url": "/docs"
        }
      ]
    }
  ]
}

Upgrade

Bump the package and restart Strapi. No content migration or host-app code changes.

npm install strapi-column-control@latest

Release notes: CHANGELOG.md.

For AI agents

Machine-readable summary: llms.txt (included in the npm package).

Submit your content

Share your work with the community and get it listed in the Strapi ecosystem for everyone to discover and use.

Submit
Submit your content