Building Gutenberg blocks that editors cannot break
Constrained controls, sensible defaults, locking and validation: how we design custom blocks that keep the brand intact after handover.

The measure of a custom Gutenberg block is not how impressive it looks in the demo. It is what the page looks like six months after launch, when three different people have edited it under deadline. Blocks that offer every option end up producing pages nobody designed. Blocks that are too rigid get replaced with workarounds. The goal is a middle path: blocks that make the right choice easy and the wrong choice unavailable. Here is how we get there.
Design the options before the code
Every block starts as a short specification agreed with the designer and a representative editor, not as code. For each block we write down:
- What content it holds and which fields are required.
- Which visual variations are genuinely needed, usually two to four, not a free-form set of controls.
- What the block should look like with too little content, too much content and no image.
- Where it may be used: any page, only in certain templates, or only inside specific patterns.
Most block problems we see in audits trace back to skipping this step. A developer exposes a color picker, a padding control and a font size selector because the tools make it easy, and a year later the site has seventeen shades of blue.
Constrain choices with theme.json and block supports
WordPress now gives fine-grained control over what editors can change. We use it aggressively:
- Disable custom values. Custom colors, gradients, font sizes and arbitrary spacing are turned off globally in theme.json. Editors pick from the design system's presets.
- Enable supports selectively. In each block's block.json, we opt in only to the supports that make sense. A testimonial block might allow alignment and a background preset but not typography controls.
- Use block styles for variations. Instead of a stack of toggles, a block offers named styles such as "Default," "Highlighted" and "Compact," each a tested combination.
- Restrict inner blocks. Container blocks declare exactly which blocks may be placed inside, and in what order when order matters.
A trimmed block.json for a feature card shows the idea:
{
"name": "acme/feature-card",
"supports": {
"align": false,
"color": { "background": true, "text": false },
"spacing": false,
"typography": false
},
"styles": [
{ "name": "default", "label": "Default", "isDefault": true },
{ "name": "highlighted", "label": "Highlighted" }
]
}
Every control you add to a block is a promise that every combination of it will look good. Make fewer promises.
Restricting the block inserter matters too. Out of the box, editors see dozens of core blocks, many of which do not fit the design system. We hide the ones that do not belong, such as verse or legacy widget blocks, and surface custom blocks and patterns first, so the easiest thing to insert is also the right thing.
Defaults, placeholders and empty states
Editors often insert a block, fill in half of it and move on. The block has to handle that gracefully. We give every field a helpful placeholder that explains what belongs there, not lorem ipsum. Required fields show an inline notice in the editor if left empty, and the front end hides empty elements rather than rendering blank boxes or broken image frames.
Character guidance helps more than hard limits. A headline field that shows "Aim for under 60 characters" and a subtle counter nudges editors toward copy that fits the design, without blocking them when a longer headline is genuinely needed. For images, we set aspect ratios and focal point controls so any uploaded photo crops sensibly.
Locking and patterns
Individual blocks are only half the system. Most layouts are combinations of blocks, and that is where patterns and locking come in. We ship patterns for every recurring section and lock their structure where the layout matters, so an editor can change the text and images in a pricing section but cannot delete a column or drag the call to action above the headline.
Locking should be selective. Over-locking frustrates editors and pushes them toward workarounds, such as building pages from raw paragraph and image blocks. We typically lock structure in templates and brand-critical patterns, and leave general content areas open. We also restrict which roles can unlock blocks, so an experienced site administrator can still make structural changes deliberately.
Testing and migration
Blocks live in content for years, which makes changes to them riskier than changes to a template. When a block's saved markup changes, older content can show the dreaded "This block contains unexpected or invalid content" message. We protect against that in three ways:
- Prefer dynamic blocks for anything likely to change, rendering output on the server so the saved content is just attributes.
- Write deprecations for static blocks whenever the save output changes, and test them against real content exported from production.
- Run automated tests that insert each block with typical, minimal and extreme content and check that it renders without errors or layout overflow.
Before handover, we run a short session where editors try to break the blocks. They usually find one or two edge cases we missed, and fixing them before launch costs far less than fixing them after.
This is the core of our Gutenberg block development practice, and it works best when blocks are part of a coherent custom theme. For larger organizations, we build the block library on top of a shared set of design system tokens so the website stays consistent with product and marketing materials.
Give your editors better blocks
If your editors are fighting the page layout or your pages have drifted from the design, send us a few examples. We will review them and reply within 24 hours with a fixed-price quote for a block library your team can use with confidence.



