Skip to content
Daniel Shaw · WordPress Developer Wellington, New Zealand

Precision layout with the Columns block

Predefined layouts in the Columns block have been around for a long time now, first shipped in the Gutenberg plugin back in June 2019. This genuinely helpful feature is a prime example of how the block editor can improve user experience when composing content in a CMS like WordPress: potentially dull and technically challenging decision-making for the user is solved by a visual prompt and a single click. Unfortunately, some of these layouts are not precisely defined for the front-end.

Here, I’ll be demonstrating a solution to achieve more intentional column layout patterns, using the Block Variations API available since WordPress 5.4. This approach will allow you to add predefined patterns to the Columns block, specific to your project requirements.

The Columns block layout picker

The default patterns offered for the Columns block are common, highly reusable container types for page content. Three of the current offered options are layouts with irregular column widths:

  • 70/30
  • 30/70
  • 25/50/25

These labels roughly correspond to container ratios of 2:1, 1:2, and 1:2:1, respectively.

Building a layout system to account for multiple possible configurations of sibling and nested content is prone to alignment errors, even when taking a defensive approach to CSS. If you’re anything like me, you appreciate having a reference grid as an aid to visually reveal errors that can easily slip into a build.

For example, choosing the 70/30 pattern results in a column layout that feels off when compared against a reference grid:

The native 70/30 pattern

Primary pain points to address

  • Layout pattern has inline styles applied
  • Block stylesheet applies an arbitrary margin
  • Pattern label is not representative of actual outcome

Layout pattern has inline styles applied

<div class="wp-block-columns"> <div class="wp-block-column" style="flex-basis:66.66%"> </div> <div class="wp-block-column" style="flex-basis:33.33%"> </div> </div>

While the label says 70/30, the style declarations flex-basis: 66.66% and flex-basis: 33.33% are automatically applied inline to the wide and slim columns, respectively.

Block stylesheet applies an arbitrary margin

.wp-block-column:not(:first-child) { margin-left: 32px; }

margin-left: 32px is applied to each .wp-block-column, excluding the first instance. This presumes you’re not already opting to dequeue the stylesheet shipped with the block editor for front-end display.

Pattern label is not descriptive of end result

70/30 simply doesn’t match the actual values applied to each column width.

The goal

Ultimately, the columns are not aligned to the visual grid I’m using. Here’s the ideal outcome in this instance:

A Columns block using a custom 2:1 pattern aligns perfectly to this project’s grid.

Setting up a custom columns variation

Unregister the default pattern

First, let’s unregister the default 70/30 pattern before adding our own custom one:

/* Unregister native pattern. */ wp.blocks.unregisterBlockVariation( 'core/columns', 'two-columns-two-thirds-one-third' );

A simple way to find a block variation’s registered name (and an excuse to go digging in the latest version of the block editor) is in the Gutenberg plugin repository. For this example, the name can be sourced from gutenberg/packages/block-library/src/columns/variations.js.

Register a custom pattern

It’s a case of simple configuration from here:

/* Register custom pattern. */ wp.blocks.registerBlockVariation( 'core/columns', { name: 'chthonic-columns-two-third-one-third', title: '66 / 33', icon: iconColumnsTwoThirdOneThird, innerBlocks: [ [ 'core/column', { className: 'is-two-third' } ], [ 'core/column', { className: 'is-one-third' } ], ], scope: [ 'block' ], });

A breakdown of what’s happening here:

  • The Block Variations API is called via the function registerBlockVariation.
  • Two parameters are required: the name of the block the variation applies to—core/columns—followed by a settings object
  • name is a unique name for the variation
  • title is the label displayed in the editor UI
  • icon is a graphic representative of the variation displayed in the editor UI
  • innerBlocks defines the composition of the variation
  • A scope of 'block' ensures the variation only appears in the Columns block layout picker

A unique CSS class has also been added to each column via the settings object for each core/column block used.

Set up a custom icon

In this example I’m creating a variation with a suitable icon already available but this won’t always be the case. Adding a custom icon can be achieved as follows:

/* Set up custom icon. */ const el = wp.element.createElement; const SVG = wp.primitives.SVG; const iconColumnsTwoThirdOneThird = el( SVG, { width: 48, height: 48, viewBox: '0 0 48 48' }, el('path', { fillRule: 'evenodd', clipRule: 'evenodd', d: 'M39 12C40.1046 12 41 12.8954 41 14V34C41 35.1046 40.1046 36 39 36H9C7.89543 36 7 35.1046 7 34V14C7 12.8954 7.89543 12 9 12H39ZM39 34V14H30V34H39ZM28 34H9V14H28V34Z', }) );

A new block variation

That’s it! The resulting markup for this example looks like this:

<div class="wp-block-columns"> <div class="wp-block-column is-two-third"> </div> <div class="wp-block-column is-one-third"> </div> </div>

At this point the block variation appears as an option in the Columns block layout picker and is ready to receive CSS specific to your project.

All together now

wp.domReady( () => { /* Unregister native pattern. */ wp.blocks.unregisterBlockVariation( 'core/columns', 'two-columns-two-thirds-one-third' ); /* Register custom pattern. */ wp.blocks.registerBlockVariation( 'core/columns', { name: 'chthonic-columns-two-third-one-third', title: '66 / 33', icon: iconColumnsTwoThirdOneThird, innerBlocks: [ [ 'core/column', { className: 'is-two-third' } ], [ 'core/column', { className: 'is-one-third' } ], ], scope: [ 'block' ], }); /* Set up custom icon. */ const el = wp.element.createElement; const SVG = wp.primitives.SVG; const iconColumnsTwoThirdOneThird = el( SVG, { width: 48, height: 48, viewBox: '0 0 48 48' }, el('path', { fillRule: 'evenodd', clipRule: 'evenodd', d: 'M39 12C40.1046 12 41 12.8954 41 14V34C41 35.1046 40.1046 36 39 36H9C7.89543 36 7 35.1046 7 34V14C7 12.8954 7.89543 12 9 12H39ZM39 34V14H30V34H39ZM28 34H9V14H28V34Z', }) ); });

Some context for doing this

It’s important to stress this isn’t some kind of futile attempt to achieve pixel perfection. This is purely about ensuring predictable and intentional container structures.

The issue described here is also likely not considered to be an issue at all by anyone working from a CMS-first perspective. Following along with the Gutenberg project, it’s often felt to me as though conversations there consider all content design to be solved prior to actual content being involved. This perspective helps with understanding how some of the more opinionated presentation rules have made their way into the stylesheet shipped with the block editor. I personally work content-first, looking for a solution suggested by the content itself (so, a lot of scrubbing the browser width with bare-naked HTML is required to work out ideal structures).