Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PC×
Skip to content
World desk13 min

How to Style Block Variations in Gutenberg (theme.json, PHP, CSS, and WordPress 6.6+)

A practical guide to styling Gutenberg block style variations: use the registered slug under theme.json, register custom styles in PHP, add scoped CSS, use version 3 nested rules, and fix common failures.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For a visual alternative to a Gutenberg block, use a block style variation: register a style slug, then define it at styles.blocks.{block}.variations in theme.json. WordPress adds the wrapper class .is-style-{slug}. If you need different attributes, an InnerBlocks template, or another insertion setup, use a JavaScript block variation instead.

First, identify which kind of variation you need

Gutenberg uses “variation” for two related but different features. A block style variation changes presentation after a block has been inserted. A JavaScript block variation changes how the block is configured or inserted. Confusing them is the most common reason a theme.json rule appears to do nothing.

As an Amazon Associate I earn from qualifying purchases.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Need Use What WordPress changes
Different border, color, spacing, typography, shadow, or other visual treatment Block style variation Adds an .is-style-{name} class to the block wrapper and applies style rules
Different default attributes when inserted JavaScript block variation Changes the block’s setup, attributes, inserter presentation, or transformation behavior
Different InnerBlocks template or nested content structure JavaScript block variation Inserts a predefined structure rather than only changing appearance
The same named visual treatment on several block types Style variation partial Uses a shared file in the theme’s /styles directory with a blockTypes array

The WordPress Theme Handbook describes block styles as CSS classes added to the wrapping element. That makes them ideal for design changes that can be expressed with supported theme.json settings or CSS. If the request changes what the block contains or how it is inserted, use the JavaScript route instead.

Before writing JSON, identify the block’s actual name, such as core/button or core/pullquote, and the style’s machine slug. The label shown in the editor can be translated or changed without changing the slug. Look for the slug in the block’s block.json registration or in the name passed to register_block_style(). Treat that value as an API identifier: it is reused in theme.json, in saved markup, and in the generated wrapper class.

Check your WordPress and theme.json versions

Core block style variations became configurable through theme.json and the Styles interface in WordPress 6.2. Version 3 of theme.json, introduced with WordPress 6.6, adds more useful variation-level capabilities, including nested element and nested block styling, custom CSS, responsive rules, and supported pseudo-selectors.

Environment What you can rely on Practical implication
WordPress 6.2 and later Core block style variations can be customized in theme.json Use styles.blocks.{block}.variations for registered styles
WordPress 6.6 and later with theme.json version 3 Variation-level nested elements, nested blocks, custom CSS, responsive rules, and supported pseudo-selectors Target links and child blocks without broad global selectors
Older WordPress with the Gutenberg plugin providing the feature Some version 3 behavior may be available through the plugin Test in the exact WordPress/plugin combination you support; do not assume every site has the same parser

Set the schema in your editor or theme file when you want validation and autocomplete. The official schema URL is https://schemas.wp.org/trunk/theme.json. A version 3 file starts like this:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3
}

Version numbers are not merely documentation. A site can have a version 3 example in a theme while running a WordPress release that does not understand every property. Match the theme’s declared version, the WordPress core version, and any Gutenberg plugin version in your support matrix, then test the oldest combination you intend to ship.

Style an existing core variation with theme.json

Use this path when the block style is already registered by WordPress or by another component. The key is the style slug, not the human-readable label shown in the editor. For a button’s registered outline style, the relevant path is styles.blocks.core/button.variations.outline.

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "styles": {
    "blocks": {
      "core/button": {
        "variations": {
          "outline": {
            "border": {
              "color": "currentColor",
              "style": "solid",
              "width": "3px"
            },
            "shadow": "var:preset|shadow|outlined",
            "spacing": {
              "padding": {
                "top": "0.5rem",
                "bottom": "0.5rem",
                "left": "1.5rem",
                "right": "1.5rem"
              }
            }
          }
        }
      }
    }
  }
}

How to apply the rule

  1. Open the active block theme’s theme.json.
  2. Confirm the block name, such as core/button, and the exact registered style slug, such as outline.
  3. Add the slug under styles.blocks, then place supported settings inside that variation object.
  4. Save the file and open the editor’s Styles or block-style control.
  5. Select the registered style on a block and inspect the front-end markup for is-style-outline.

WordPress ignores style definitions for unregistered variations. A correctly shaped JSON object cannot create a new style by itself; registration must happen first. The block name and slug are both case-sensitive identifiers in practice, so copy them exactly rather than retyping a translated display label.

Use preset references instead of hard-coded values when possible

Preset tokens keep a variation connected to the theme’s design system. For example, var:preset|shadow|outlined references a named shadow preset, while a spacing token such as var:preset|spacing|60 follows the theme’s spacing scale. Hard-coded values such as 3px or 1.5rem are still valid when a variation needs a fixed value, but presets make later theme-wide changes easier. They also keep related style variations visually consistent when the theme’s palette, spacing scale, or shadow definitions are revised.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Register your own block style in PHP

If no suitable style is registered, create one with register_block_style(). Register it on init, give it a unique machine-readable name, and provide a translated editor label.

<?php
add_action( 'init', 'mytheme_register_block_styles' );

function mytheme_register_block_styles() {
    register_block_style( 'core/pullquote', array(
        'name'  => 'boxed',
        'label' => __( 'Boxed', 'mytheme' ),
    ) );
}

The name becomes the slug used in theme.json and in the wrapper class. In this example, WordPress uses .is-style-boxed. Keep the slug stable once content is using it; changing it later leaves existing blocks pointing at the old class.

The current function signature is register_block_style( string|string[] $block_name, array $style_properties ): bool. The style-properties array can also include inline_style, style_handle, and style_data. Those options are useful when a style needs a dedicated stylesheet or style data, but they do not remove the need to register the style itself. A registration that returns successfully still needs to be paired with a correctly named theme.json object if you want the theme’s settings system to provide the visual values.

Define the registered slug in theme.json

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "styles": {
    "blocks": {
      "core/pullquote": {
        "variations": {
          "boxed": {
            "border": {
              "color": "currentColor",
              "style": "solid",
              "width": "6px"
            },
            "spacing": {
              "padding": {
                "top": "var:preset|spacing|60",
                "bottom": "var:preset|spacing|60",
                "left": "var:preset|spacing|60",
                "right": "var:preset|spacing|60"
              }
            }
          }
        }
      }
    }
  }
}

Registration and styling are separate steps: PHP makes boxed an available style; theme.json supplies the design values. If either the block name or slug differs by one character, the style will not receive the intended rules. The translated label affects what users see in the picker, but never use that label as the variation key.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use CSS for design details theme.json cannot express

Not every selector or effect has a corresponding supported setting. Keep the style registration in place, then target the wrapper class in CSS:

.wp-block-pullquote.is-style-boxed {
  position: relative;
  overflow: hidden;
}

.wp-block-pullquote.is-style-boxed::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 0.35rem;
  background: currentColor;
}

Load that stylesheet through the theme’s normal style-loading mechanism or through the style registration options. A style that appears in the editor but not on the front end usually indicates that the CSS was never enqueued for front-end requests, was attached to the wrong handle, or was overridden by a more specific rule. Check the rendered page source and network requests, not only the editor canvas.

Prefer theme.json for properties it supports, because WordPress can generate the corresponding editor and front-end styles consistently. Use a narrowly scoped .is-style-{slug} selector for the remainder. Avoid a global selector such as every .wp-block-pullquote; it would affect the block’s default style as well as the variation. Keep pseudo-elements, complex descendant selectors, transitions, and other exceptional effects in the smallest stylesheet possible so the variation remains easy to override and maintain.

Take advantage of theme.json version 3 for nested content

Version 3 lets a variation describe parts inside the block instead of relying only on the outer wrapper. This is useful for blocks that contain links, headings, buttons, or other nested blocks. The exact properties still have to be supported by the block and the theme.json schema.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "styles": {
    "blocks": {
      "core/post-terms": {
        "variations": {
          "compact": {
            "elements": {
              "link": {
                "typography": {
                  "textDecoration": "none"
                }
              }
            },
            "css": "& a:hover { text-decoration: underline; }"
          }
        }
      }
    }
  }
}

Here, elements.link scopes the typography rule to links exposed by the block, while variation-level css handles a hover selector. For a child block, use the variation’s blocks scope where supported instead of writing a broad descendant selector that could catch unrelated content. Responsive declarations and pseudo-selectors are likewise subject to the properties and parser supported by the WordPress version in use.

Validate nested rules in the target editor

  • Confirm the site is actually parsing theme.json version 3.
  • Check that the target element or child block is part of that block’s supported style schema.
  • Inspect both editor and front-end markup; generated selectors may differ from the selectors you would write by hand.
  • Keep a fallback class-based rule for designs that must work on older WordPress versions.

A nested rule can be syntactically valid yet have no visible effect when the block does not expose that element, when the variation slug is wrong, or when another selector wins in the cascade. Verify one concern at a time: first the wrapper class, then the generated nested selector, then the computed property.

Share one style across several block types

When the same named treatment belongs on multiple block types, create a block-style variation partial in the theme’s /styles directory. Its blockTypes array identifies the blocks that should receive the style. This avoids maintaining separate copies of the same design definition.

{
  "$schema": "https://schemas.wp.org/trunk/theme.json",
  "version": 3,
  "title": "Accent frame",
  "slug": "accent-frame",
  "blockTypes": [
    "core/group",
    "core/quote"
  ],
  "styles": {
    "border": {
      "style": "solid",
      "width": "2px",
      "color": "currentColor"
    },
    "spacing": {
      "padding": "var:preset|spacing|40"
    }
  }
}

Use this pattern when the visual language is intentionally shared. If each block needs different spacing, child selectors, or semantics, separate registrations and per-block variation rules are clearer and less likely to produce unexpected results. Keep the shared slug meaningful across every listed block, and test each block because their markup and supported style properties can differ even when the visual treatment is conceptually the same.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why a variation style does nothing: diagnosis and fixes

Symptom Likely cause Fix
The style is absent from the block-style picker The style was never registered, or the registration runs too late Register it on init with register_block_style(), or verify that the block’s block.json declares the style
theme.json parses but no visual change appears The variation key does not match the registered slug Use the machine name, not the translated label; check spelling and capitalization
A JavaScript variation is being styled under variations The two variation systems were mixed Register a block style for visual changes, or put structural behavior in the JavaScript variation definition
It works in the editor but not on the front end The stylesheet is not loaded on front-end requests, or its handle is incorrect Inspect the page source and network requests; enqueue the stylesheet correctly or move supported properties into theme.json
Only a nested link or child block is wrong A broad selector targets the wrong descendant Use version 3 elements or blocks scope where available, or qualify the selector with the variation wrapper
Version 3 syntax is ignored The site is running an older WordPress parser or an older theme.json version Run WordPress 6.6 or later for the documented version 3 features, or provide an older-version fallback
Styles are overridden unexpectedly Theme, plugin, or editor CSS has greater specificity or loads later Inspect computed styles, narrow the selector to .is-style-{slug}, and avoid unnecessary !important

When debugging, start with the smallest observable fact: does the editor show the style, does saved markup contain the expected is-style- class, and does the front-end response contain the corresponding CSS? This sequence separates registration, serialization, and stylesheet-loading problems instead of treating every failure as a JSON problem.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

A reliable implementation workflow

  1. Describe the requested change. If it is only visual, choose a block style. If it changes attributes, insertion, or nested structure, choose JavaScript.
  2. Find or choose the slug. Check the block’s registered styles or your own register_block_style() call. Treat the slug as an API identifier.
  3. Register before styling. A theme.json variation object cannot create an unregistered style.
  4. Start with supported settings. Put borders, spacing, color, typography, and shadows in theme.json, using presets where appropriate.
  5. Add scoped CSS only for the remainder. Use .is-style-{slug} and keep nested selectors local.
  6. Test both rendering contexts. Apply the style in the editor, save a post, view the front end, and inspect the generated wrapper class.
  7. Test the minimum supported version. Version 3 examples require WordPress 6.6 or the corresponding Gutenberg feature set; older installations need compatible syntax or a fallback stylesheet.
  8. Check accessibility. Verify color contrast, visible focus indicators, hover-only cues, readable spacing, and behavior at narrow widths. A style variation should not make content harder to perceive or operate.

Document the slug, registration location, supported WordPress version, and any required stylesheet handle alongside the implementation. That small record prevents a later developer from deleting a seemingly unused PHP registration or renaming a slug that existing content still references.

Choosing between theme.json and CSS

Use theme.json when the property is part of the supported design system and should be available consistently in the editor and on the front end. Use CSS when the design requires pseudo-elements, complex selectors, transitions, or another effect that the current schema cannot represent. The most maintainable implementation often combines both: registration in PHP, design tokens and standard properties in theme.json, and a small, scoped stylesheet for the exceptional selectors.

The decisive test is not whether a rule can be forced into JSON. It is whether the style remains discoverable, survives editor-to-front-end rendering, and leaves structural behavior in the feature designed to control it. Register the correct style slug, target it under styles.blocks.{block}.variations, and reserve JavaScript variations for changes to the block’s setup.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

What is the difference between a block style variation and a JavaScript block variation?

A block style variation is a visual choice. WordPress adds an .is-style-{slug} class to the block wrapper, and you style that class with theme.json or CSS. A JavaScript block variation changes insertion behavior, attributes, transforms, or an InnerBlocks template. Use the JavaScript feature when the block’s setup or structure must change.

Why does my variation style in theme.json do nothing?

The most common cause is an unregistered style or a key that does not match its registered slug. Confirm the block name and machine slug in block.json or register_block_style(). WordPress ignores style definitions for unregistered variations, even when the JSON is valid.

Can theme.json create a brand-new block style without PHP?

No. The variation must already be registered by WordPress, a block’s block.json, or register_block_style(). After registration, define the same slug under styles.blocks.{block}.variations.

Where should I put custom CSS for a style variation?

Keep registration in place and scope rules to the wrapper, for example .wp-block-pullquote.is-style-boxed. Load the stylesheet through the theme’s normal mechanism or the style registration options. Use theme.json for supported properties and CSS for selectors or effects the schema cannot express.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

How do I style a link or child block inside a variation?

With theme.json version 3 on WordPress 6.6 or later, use the variation’s elements scope for exposed elements such as links and blocks scope for supported child blocks. Variation-level css can handle supported custom selectors, including pseudo-selectors. Verify the block exposes the target and inspect generated markup.

Why does the style work in the editor but not on the front end?

The front end may not be loading the stylesheet, the registered handle may be wrong, or another rule may override it. Inspect page source, network requests, and computed styles. Moving supported declarations into theme.json lets WordPress generate editor and front-end styles consistently.

Can one named style apply to several block types?

Yes. Put a style variation partial in the theme’s /styles directory and list the target blocks in its blockTypes array. Use this only when the visual treatment is intentionally shared; block-specific spacing or nested selectors are usually clearer in separate rules.

Which WordPress versions support variation styling in theme.json?

WordPress 6.2 introduced customization of core block style variations through theme.json and the Styles interface. WordPress 6.6 with theme.json version 3 adds variation-level nested elements, nested blocks, custom CSS, responsive rules, and supported pseudo-selectors. Older sites need compatible syntax or a fallback stylesheet, and Gutenberg plugin behavior must be tested in the exact version you support.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Should I use presets or fixed CSS values?

Use preset references such as var:preset|spacing|60 and var:preset|shadow|outlined when the value belongs to the theme’s design system. Fixed values remain appropriate for a deliberate one-off measurement, but presets make coordinated theme-wide changes easier.

The Bottom Line

Choose a block style variation for presentation, register its slug, and style that slug under styles.blocks.{block}.variations. Use presets and supported version 3 scopes where possible, add narrowly scoped .is-style-{slug} CSS for the rest, and verify both editor and front-end output. If the change affects attributes, insertion, or nested structure, implement a JavaScript block variation instead.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.