block.json

A reference to block.json parameters in WordPress

The block.json file is needed to simplify the creation and registration of blocks in WordPress.

It describes the block in JSON format and is used both on the server (php) and in the block editor (js) — that is, one file is responsible for everything.

In the official documentation there is a full list of all block.json properties.

Documentation for theme.json.

See also:

  • register_block_type_from_metadata() — block registration.

  • The parameters in block.json [official docs] (developer.wordpress.org).

  • What is block.json (developer.wordpress.org)
  • Use register_block_type() to register a block.

  • Use registerBlockType() to register blocks via JS.

Example block.json:

{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "my-plugin/notice",
  "title": "Notice",
  "description": "Shows warning, error or success notices...",
  "icon": "star",
  "category": "text",
  "keywords": [ "alert", "message" ],
  "textdomain": "my-plugin",

  "parent": [ "core/group" ],

  "render": "file:./render.php",

  "script": "file:./script.js",
  "style": [ "file:./style.css", "example-shared-style" ],
  "editorScript": "file:./index.js",
  "editorStyle": "file:./index.css",
  "viewScript": [ "file:./view.js", "example-shared-view-script" ],
  "viewStyle": [ "file:./view.css", "example-view-style" ],

  "attributes": {
	"message": {
	  "type": "string",
	  "source": "html",
	  "selector": ".message"
	}
  },

  "supports": {
	"align": true
  },

  "styles": [
	{ "name": "default", "label": "Default", "isDefault": true },
	{ "name": "other", "label": "Other" }
  ],

  "providesContext": {
	"my-plugin/message": "message"
  },

  "usesContext": [ "groupId" ],

  "selectors": {
	"root": ".wp-block-my-plugin-notice"
  },

  "example": {
	"attributes": {
	  "message": "This is a notice!"
	}
  },

  "variations": [
	{
	  "name": "example",
	  "title": "Example",
	  "attributes": {
		"message": "This is an example!"
	  }
	}
  ]
}

Parameters

Core parameters:

  • apiVersion — API version used by the block. Usually you should specify the latest.
  • name — Unique block name with namespace (for example, my-plugin/my-custom-block).
  • title — Block title displayed in the inserter.
  • category — Category in which the block will be shown in the inserter. Common categories: text, media, design, widgets, theme.
  • icon — Block icon in the inserter (may be a Dashicons slug or SVG).
  • description — Short description of the block (more details than the title).
  • keywords — Array of keywords to help find the block via search.
  • textdomain — Text domain for translating the block.

Input/output and styling files for the block:

  • script — JS file(s) for front-end and editor.
  • style — CSS file(s) for front-end and editor.
  • editorScript — JS file(s) only for the block editor.
  • editorStyle — CSS file(s) only for the editor.
  • viewScript — JS file(s), only for front-end.
  • viewScriptModule — ES module only on the front-end.
  • viewStyle — CSS file(s) only on the front-end.

Property render
In WP 6.1, the property render appeared, which specifies the path to a PHP template for dynamic rendering of the block on the front end.

Contents:
$schema(string)
JSON schema URI to help IDE. Usually: https://schemas.wp.org/trunk/block.json.
Default: —
apiVersion(int) (required)
API version used by the block. It is recommended to specify the latest. For example 3.
name(string) (required)
Unique block name namespace/block-name.
title(string) (required)
Block title displayed in the inserter.
icon(string)
Block icon in the inserter (may be a Dashicons slug or SVG).
Default: —
category(string)
Inserter category: text, media, design, widgets, theme, embed or custom.
Category in which the block will be shown in the inserter.
Common categories: text, media, design, widgets, theme.
Default: —
description(string)

Short description of the block (more details than the title).

Shown in the Block panel (in the right sidebar in the block editor) when the block is selected. Appears under the block title and helps the user understand the purpose in more detail.

Default: —

keywords(array)
Array of keywords to help find the block via search.
Default: —
textdomain(string)
Text domain for translating the block.
Default: —
script(string|array)
style(string|array)
editorScript(string|array)
editorStyle(string|array)
viewScript(string|array)
viewScriptModule(string|array)
viewStyle(string|array)

Files (scripts and styles) that handle the block's functionality:

  • script — JS file(s) for front-end and editor.
  • style — CSS file(s) for front-end and editor.
  • editorScript — JS file(s) only for the block editor.
  • editorStyle — CSS file(s) only for the editor.
  • viewScript — JS file(s), only for front-end.
  • viewScriptModule — ES module only on the front-end.
  • viewStyle — CSS file(s) only on the front-end.

For all these parameters you can specify:

  • Path to file (with file: prefix),
  • Handle of the script/style registered via wp_register_script()/wp_register_style(),
  • An array of these options.

Default: —

render(string) (WP 6.1)

Specifies the path to a PHP template for dynamic rendering of the block on the front end.

Used if when registering the block in register_block_type() the $render_callback parameter is not provided.

Default: —

attributes(object)

Attributes (parameters, properties) of the block.

Keys-attributes → object with properties:

  • type (string/array of strings)
    Data type (null|boolean|object|array|string|rich-text|integer|number).

  • enum (array)
    Fixed set of values.

  • source (string)
    Source (attribute|text|rich-text|html|raw|query|meta).

  • selector (string)
    CSS selector for extraction.

  • attribute (string)
    HTML attribute name when source=attribute.

  • query (object)
    Schema for selecting an array from markup.

  • meta (string)
    Post-meta key (deprecated approach).

  • role (string)
    content or local.

  • default (any)
    Default value.

Default: —

blockHooks(object)
Auto-insertion next to other blocks: key namespace/blockbefore|after|firstChild|lastChild.
Default: —
parent(array)

Restricts usage of the block — it becomes available only inside specified parent blocks.

If you set parent, the block disappears from the general inserter and will be available only in places where the parent block allows InnerBlocks.

Values are specified as namespace/block.

You can list several parents.

Example:

{
  "name": "my-plugin/child",
  "title": "Child block",
  "apiVersion": 3,
  "parent": [ "core/columns", "core/group" ]
}

In this example the block my-plugin/child can be added only inside core/columns or core/group, but not on its own.

This is convenient for “connected” blocks — for example:

  • “List Item” can be inserted only inside “List”.
  • “Add to Cart” — only inside “Product”.

Default: —

ancestor(array)

List of parent blocks inside which this block may be used.

"ancestor": [ "core/group", "core/columns" ]
  • Outside these parent blocks, it cannot be inserted.
  • This is a kind of “inverse” variant of the allowedBlocks parameter, which defines which child blocks can be inserted inside the current one.

Example:

{
  "name": "myplugin/child-block",
  "title": "Child Block",
  "category": "widgets",
  "ancestor": [ "core/group" ]
}

Such a block can be inserted only inside core/group.

Default: —

allowedBlocks(array) (WP 6.5)

Whitelist of blocks that can be nested inside the current block.

For example: ["core/paragraph", "core/image"]

The parameter controls direct children. That is, if for the current block it is allowed to nest only, for example, core/group, then inside core/group you can nest what is allowed for core/group.

This parameter is especially useful for controlling structure — for example, a list block may allow only list items, a columns block — only columns, etc.

If you need to dynamically restrict nested blocks, use the InnerBlocks component's allowedBlocks property in JavaScript, for example:

<InnerBlocks allowedBlocks={ attributes.allowedBlocks } />

But if the list is static, it is better to specify it directly in block.json.

Default: —

providesContext(object)
Exported context: key of context → the block attribute name.
Default: —
usesContext(array)

Allows a block to declare which values from the context it wants to inherit from parent blocks.

Context in Gutenberg is a mechanism to pass data downward through the block tree without explicitly passing via attributes.

How it works

  • The parent block specifies in providesContext which values it “gives” to children.
  • The child in usesContext lists the names of these values so they can be used inside edit/save functions.
  • In the editor, a React component of such a block will receive these data in props.context.

Example

{
  "name": "my-plugin/child-block",
  "title": "Child Block",
  "apiVersion": 3,
  "usesContext": [ "postId", "postType" ]
}

In the JS component:

const MyChildBlock = ( props ) => {
	const { context } = props;

	return <div>Post ID: { context.postId }, Type: { context.postType }</div>;
};

Where it is used

  • Comment blocks (core/comment-*) get data about the current comment from core/comment-template.
  • Blocks inside the Query Loop use queryId, postId and other parameters to display data for a specific post.

Features

  • Works only with context that was previously declared through providesContext by ancestors.
  • Values are available only within the block tree — you cannot “pull” context from a completely different place.
  • If the parent does not provide the required context, the value in props.context will be undefined.

Default: —

version(string)

Block version (for example, 1.0.3). This is a purely informational field.

  • It is not displayed anywhere in the editor UI.
  • Used by WordPress internally, mainly for caching and invalidating assets (block scripts and styles).
  • If a version is specified — it is added as a query string (?ver=1.0.3) when enqueuing block CSS/JS.
  • If not specified — WordPress will automatically substitute the version of WordPress itself.

Default: —

__experimental(string/boolean)

Experimental flag.

This refers to parameters that begin with the prefix __experimental. Behavior and the key itself may change without preserving backward compatibility.

Such parameters are practically not documented. If possible, better not to use.

The list of all experimental properties found in WP core 6.9 from the wp-includes/blocks folder:

supports

	__experimentalOnEnter: true        // core/group
	__experimentalOnMerge: true        // core/group
	__experimentalSettings: true       // core/group
	__experimentalSlashInserter: true  // core/navigation-link
	__experimentalToolbar: false       // core/page-list-item
	__experimentalSelector: "p",       // core/paragraph
	__unstablePasteTextInline: true,   // core/paragraph

	__experimentalBorder: {
		__experimentalSkipSerialization: true
		radius: true
		color: true
		width: true
		style: true
		__experimentalDefaultControls: {
			radius: true
			color: true
			style: true
			width: true
		}
	}

	__experimentalExposeControlsToChildren: true

	spacing
		__experimentalSkipSerialization: [ "blockGap" ]
		__experimentalDefaultControls: {
			margin: false
			padding: false
			blockGap: true
		}
		blockGap
			__experimentalDefault: "2em"

	typography
		__experimentalFontFamily: true
		__experimentalFontWeight: true
		__experimentalFontStyle: true
		__experimentalTextTransform: true
		__experimentalTextDecoration: true
		__experimentalLetterSpacing: true
		__experimentalWritingMode: true
		__experimentalDefaultControls: {
			fontSize: true
			__experimentalFontFamily: true,
			__experimentalFontStyle: true,
			__experimentalFontWeight: true
		}
		__experimentalSkipSerialization: [
			"fontSize",
			"lineHeight",
			"fontFamily",
			"fontWeight",
			"fontStyle",
			"textTransform",
			"textDecoration",
			"letterSpacing"
		]

	color
		__experimentalDuotone: "img"   ||   "> .wp-block-cover__image-background, > .wp-block-cover__video-background"
		__experimentalSkipSerialization: true   ||   [ "text", "background" ]    ||     [ "gradients" ]
		__experimentalSelector: "table, th"
		__experimentalDefaultControls: {
			"background": true
			"text": true
			"link": true
		}

	shadow:
		__experimentalSkipSerialization: true
supports(object)
Enabling editor capabilities and styles. Connects UI and extends style/attributes.
Default: —
supports.anchor(boolean)

Includes the HTML ANCHOR control in Advanced. Usually this anchor is used as an id="" attribute of the tag, which is preserved in content when the block is saved.

"supports": {
  "anchor": true,
}

If this parameter is enabled for a custom block whose HTML is not saved in content, you also need to specify anchor as an attribute of the block so that it is saved in the block's JSON data:

"attributes": {
  "anchor": { "type": "string" },
}

Then in the block render file you can obtain this attribute as usual:

$attributes['anchor']

Default: false

supports.align(boolean/array)

Alignment controls (wide|full|left|center|right). Controls block alignment in the editor.

Default: false

Possible values:

  • false — alignment is disabled (default).
  • true — all alignment options allowed by the theme: wide|full|left|center|right.
  • ["left","center","right"] — explicitly listed allowable options.
  • ["wide","full"] — allow only wide and full.

Example:

{
  "name": "my-plugin/banner",
  "title": "Banner",
  "supports": {
	"align": [ "left", "center", "right" ]
  }
}

In the editor the block will have alignment buttons, but wide and full will not be available.

align takes precedence over alignWide. So if align = ["wide","full"] and alignWide = false, the buttons will still work.

supports.alignWide(boolean)

Controls support for wide alignment for the block.

Default: true

If the theme enables wide and full alignment support [add_theme_support( 'align-wide' )], the editor will show the buttons:

To disable this capability for a specific block, set:

{
	"supports": {
	  "alignWide": false
	}
}

Then even if the theme supports it, the block cannot use alignwide (wide width).

Example: Keep only standard alignments

{
  "name": "my-plugin/custom-block",
  "title": "Custom Block",
  "supports": {
	"align": [ "left", "right", "center" ],
	"alignWide": false
  }
}
  • align controls the presence of alignment buttons: left, right, center, wide, full.
  • alignWide — a separate flag to prohibit wide width for the block, even if the theme supports it.
supports.ariaLabel(boolean)

Allows the aria-label attribute for the block, but without a separate UI field.

  • If true → Gutenberg will add support for aria-label to the block. The attribute can be set manually (for example via setAttribute or in save), but there will be no separate UI field for it.

  • If false (default) → the block does not support aria-label.

Used for accessibility: you can add a textual description of the block for screen readers without loading the editor UI.

Default: false

supports.className(boolean)
Enable the wrapper class .wp-block-*.
Default: true
supports.color(object)
Support for color properties.
Default: —
supports.color.background(boolean)
UI for background color, adds backgroundColor and style.
Default: true
supports.color.gradients(boolean)
UI for gradients, adds gradient and style.
Default: false

UI for link color. Enables/disables the link color picker panel.

Used for any blocks that contain text with potential <a> inside:

  • paragraph
  • heading
  • group
  • columns
  • custom blocks with their own richText fields

If enabled, Gutenberg begins applying a CSS custom property to the block:
--wp--style--color--link

And this color affects only the <a> inside the block, not the regular text.

Default: false

supports.color.text(boolean)
UI for text color, adds textColor and style.
Default: true
supports.color.heading(boolean)
UI for heading color, adds style.
Default: false
supports.color.button(boolean)
UI for button colors, adds style.
Default: false
supports.color.enableContrastChecker(boolean)
Show contrast checker widget.
Default: true
supports.customClassName(boolean)
Custom class field in Advanced.
Default: true
supports.dimensions(object)
Support for dimensions.
Default: —
supports.dimensions.aspectRatio(boolean)
UI for aspect ratio.
Default: false
supports.dimensions.minHeight(boolean)
UI for minimum height.
Default: false
supports.filter(object)
Support for CSS filters.
Default: —
supports.filter.duotone(boolean)
Duotone filter.
Default: false
supports.background(object)
Support for background properties.
Default: —
supports.background.backgroundImage(boolean)
UI for background image.
Default: false
supports.background.backgroundSize(boolean)
UI for background size/position/repeat.
Default: false
supports.html(boolean)

Allow editing the block HTML.

Default: true

supports.inserter(boolean)
Show block in the UI (inserter, transforms, Style Book).
Default: true
supports.renaming(boolean)
Allow user to rename the block.
Default: true
supports.layout(boolean|object)
Layout support for containers. true is equivalent to default.type: flow.
Default: false
supports.layout.default(object)
Default values for the chosen layout type.
Default: —
supports.layout.default.type(string)
Layout type: constrained|grid|flex.
Default: —
supports.layout.default.contentSize(string)
Content width of children.
Default: —
supports.layout.default.wideSize(string)
Width for alignwide children.
Default: —
supports.layout.default.justifyContent(string)
Alignment: right|center|space-between|left|stretch.
Default: —
supports.layout.default.orientation(string)
Orientation: horizontal|vertical.
Default: —
supports.layout.default.flexWrap(string)
Wrap: wrap|nowrap.
Default: —
supports.layout.default.verticalAlignment(string)
Vertical alignment: top|center|bottom|space-between|stretch.
Default: —
supports.layout.default.minimumColumnWidth(string)
Min. column width.
Default: —
supports.layout.default.columnCount(int)
Number of columns.
Default: —
supports.layout.allowSwitching(boolean)

Switcher for layout types.
Default: false

supports.layout.allowEditing (boolean)

Show layout controls in the sidebar.
Default: true
supports.layout.allowInheriting(boolean)
Only for flow: show “Inner blocks use content width”.
Default: true
supports.layout.allowSizingOnChildren(boolean)
Only for flex: Fit/Fill/Fixed on children.
Default: false
supports.layout.allowVerticalAlignment(boolean)

Adds vertical alignment controls. Only for flex.

"layout": {
  "default": { "type": "flex" },
  "allowVerticalAlignment": true
},

Default: true

supports.layout.allowJustification(boolean)
flex and constrained: Justify controls.
Default: true
supports.layout.allowOrientation(boolean)
Only for flex: orientation control.
Default: true
supports.layout.allowCustomContentAndWideSize(boolean)
Only for constrained: custom content/wide size.
Default: true
supports.multiple(boolean)
Allow multiple instances of a block in a post.
Default: true
supports.reusable(boolean)
Allow conversion to reusable block.
Default: true
supports.lock(boolean)
Allow user to change the lock state.
Default: true
supports.position(object)
Positioning support.
Default: —
supports.position.sticky(boolean)
Sticky position relative to the parent.
Default: false
supports.spacing(object)
Spacing support.
Default: —
supports.spacing.margin(boolean/array)
UI for margin. Array: sides top|right|left|bottom or axes vertical|horizontal.
Default: —
supports.spacing.padding(boolean/array)
UI for padding. Array: sides or axes.
Default: —
supports.shadow(boolean/object)
Shadow support (box-shadow).
Default: false
supports.typography(object)
Typography support.
Default: —
supports.typography.fontSize(boolean)
UI for font-size, adds fontSize and style.
Default: false
supports.typography.lineHeight(boolean)
UI for line-height, stored in style.
Default: false
supports.typography.textAlign(boolean/array)
Text alignment toolbar (left|center|right).
Default: false
supports.interactivity(boolean/object)
Using Interactivity API.
Default: false (if boolean)
supports.interactivity.clientNavigation(boolean)
Compatibility with client navigation IA.
Default: false
supports.interactivity.interactive(boolean)
Are there IA directives.
Default: false
supports.splitting(boolean)
Enable split on Enter/paste.
Default: false
supports.__experimentalOnEnter

Handling Enter inside the block (exit/split container, not exact).

Where it occurs: core/group, core/columns

Meaning (not exact): enables special handling of Enter — the editor decides what to do when Enter is pressed in the last RichText inside the block (for example, exit the container and create a new core/paragraph after the block).

Example:

  • In a container block (conditional my-plugin/container) you can set:
    "supports": { "__experimentalOnEnter": true }, so pressing Enter in the end of the last paragraph moves the cursor outside the container and creates a new core/paragraph.

Default: false

supports.__experimentalOnMerge

Logic for merging the block with neighbors on Backspace/Delete (not exact).

Where it occurs: core/group

Meaning (not exact): enables custom behavior when blocks are merged — typically when the cursor is at the start of the block and the user presses Backspace/Delete, the editor tries to merge the block with the previous one. For containers this flag allows them to intercept the event and, for example, move the neighboring block inside/outside the container instead of the standard delete/merge.

Example:

  • For a custom wrapper block you can enable:
    "supports": { "__experimentalOnMerge": true }, so that Backspace at the start of the block does not delete the previous paragraph but moves it inside the container.

Default: false

supports.__experimentalSettings

Internal Gutenberg flag to enable additional block settings/panels (not exact).

Where it occurs: in some core blocks, for example core/group.

Meaning (not exact): A service property that marks a block as using additional editor capabilities (settings panels, options, UI). The exact set of effects is not documented and can vary between Gutenberg versions. It is recommended not to use in custom blocks unless necessary, as the API is unstable and geared toward core needs (not exact).

Example:

  • In some core blocks you can see:
    "supports": { "__experimentalSettings": true }, which enables extended panels in the inspector (the exact panels vary by version, not exact).

Default: false

supports.__experimentalSlashInserter

Enables slash insertion (/), showing a list of blocks/commands directly in block text.

Where it occurs: text blocks (core/heading, etc.).

Goal: Makes the block participate in the slash inserter mechanic: when typing "/" in a RichText field of the block, a pop-up list of blocks and commands appears (as in a paragraph).

Useful for text blocks that should feel like a standard paragraph/heading.

Historically also used to enable auto-completion of links via [[…]], but now this behavior is mostly global.

Example:

  • For a text block my-plugin/lead-paragraph:
    "supports": { "__experimentalSlashInserter": true } — allows a user to type /image and insert core/image directly from the hint without leaving the block.

Default: false

supports.__experimentalToolbar

Controls the display of the standard block toolbar (can be hidden for internal blocks).

Meaning (not exact): controls the visibility of the standard block toolbar (the icons panel above the block) for particular “internal”/utility blocks.

For blocks such as core/page-list-item this means “do not show the block’s own toolbar, control the block via the parent (for example, core/page-list)”.

Recommendations:

  • Use only if you are creating a technical internal block that should not have its own editing interface (toolbar) directly.

Example:

  • An internal block element that is used only inside the parent block (for example, a menu item in a custom navigation block) can be declared as:
    "supports": { "__experimentalToolbar": false }, so control goes only through the parent’s toolbar.

Default: true (by meaning; core explicitly sets false for some internal blocks)

supports.__experimentalSelector

Overrides the CSS selector to which global styles (theme.json) apply to the block.

Example:

  • ".my-custom-classname"
  • "p"
  • ".wp-block-button .wp-block-button__link"

Purpose: Allows specifying an alternative CSS selector to which global styles (theme.json / Global Styles) will apply for this block.

Default: WordPress uses a selector like .wp-block-<block-name>. If the block does not use such wrapper or you need to style an inner element (for example, the <form> or <a> in a button), you can use this property.

Typical uses:

  • Block does not render the standard class .wp-block-…, but you want global styles to apply.
  • Need global styles to apply not to the wrapper-div, but to the “real” element, for example:
    • Form block: "__experimentalSelector": "form"
    • Button-link: "__experimentalSelector": ".wp-block-button .wp-block-button__link"

Features:

  • For global styles to work correctly the block must be registered via block.json through register_block_type_from_metadata(), otherwise selector information is not available to the PHP part.

  • The flag is still marked as experimental, but considered relatively mature and actively used in core blocks.

Risks:

  • Incorrectly chosen selector may affect not only the block itself but also nested elements (especially for containers like <form>).

    Example:

  • For a form block that renders only <form class="my-form">…</form> without wrapper .wp-block-*, you can specify:
    "supports": { "__experimentalSelector": "form.my-form" }, so global color/typography styles from theme.json apply to the <form> tag.

    Default: uses the standard selector .wp-block-<block-name>

supports.__unstablePasteTextInline

Special handling of pasting text as inline content without splitting into blocks (not exact).

Where it occurs: core/paragraph, core/heading and other text blocks with RichText.

Meaning (not exact):

  • Enables a special paste handling mode in RichText fields of the block:

    • paste is treated as “inline text” without breaking or creating new blocks,

    • complex pastes (multiline text, HTML) are simplified to text and pasted at the current cursor position.
  • Used by core to make such blocks behave more predictably when pasting text from clipboard (headings, paragraphs, etc.).

Status: This property is marked as __unstable, i.e., even less stable than __experimental.

In custom blocks better to enable it only if you precisely reproduce core text block behavior and are prepared for possible API changes.

Example:

  • For a custom text block based on RichText:
    "supports": { "__unstablePasteTextInline": true } — pasting from clipboard (for example Word/Google Docs) will be converted to plain text and inserted into the current block, without creating new blocks.

Default: false

supports.__experimentalExposeControlsToChildren

Shares the container block's settings panel with its child blocks.

The flag is used for container blocks with InnerBlocks (for example, button groups) so that part of the parent's settings (layout, alignment, margins, etc.) remains accessible even when an inner block is selected.

When this property is enabled the inspector can continue to show/apply some parent block controls when a child block is clicked, easing work with composite blocks.

The exact behavior and the set of “shared” controls depend on the editor version and may change.

Example:

{
	"name": "my-plugin/buttons-group",
	"supports": {
		"__experimentalExposeControlsToChildren": true,
		"spacing": {
			"blockGap": true,
			"margin": [ "top", "bottom" ]
		}
	}
}

Default: false

supports.__experimentalBorder

Enables border support for the block (color, width, style, radius) and configures visible controls.

Enabling this shows corresponding panels in the block inspector, and the chosen values go into style attributes (style.border.*) and/or CSS classes. Used by many core blocks.

Key object keys:

  • radius — enables the corner radius control.
  • color — enables border color selection.
  • width — enables border width control.
  • style — enables line style (solid, dashed, dotted, etc.).

  • __experimentalDefaultControls — object with the same keys (radius, color, width, style) that controls which controls are active by default in the UI (for example, you can enable only radius).

  • __experimentalSkipSerialization — if true, border styles will not be automatically serialized to the block wrapper element. Values will still be stored in style attributes and can be applied manually via useBorderProps in JS or get_block_wrapper_attributes() in PHP to any element.

Additionally:

  • If any of the keys (radius, color, width, style) is not specified, the corresponding control is hidden.
  • If the theme does not include support for borders/appearance tools (for example, via theme.json or add_theme_support( 'border' )), the UI may be hidden even when the block has this support enabled.
  • In newer WordPress versions this support is planned to be moved to a stable key border (without the prefix), while the old __experimentalBorder will continue to be supported for some time as an alias.

Example:

{
	"name": "my-plugin/box",
	"supports": {
		"__experimentalBorder": {
			"__experimentalSkipSerialization": true,
			"radius": true,
			"color": true,
			"width": true,
			"style": true,
			"__experimentalDefaultControls": {
				"radius": true,
				"color": true,
				"style": true,
				"width": true
			}
		}
	}
}

Default: false - Border panel is disabled and all nested properties are off as well.

selectors(object)

Allows the block to configure CSS selectors on the element that styles are generated for.

You can override CSS selectors at three levels:

  • Root
  • Feature level
  • Subfeature level

Root selector

The root selector is the block’s main CSS selector.

All blocks must have a main selector under which their style declarations will be collected. If not set, the default is .wp-block-<name>:

{
  ...
  "selectors": {
	"root": ".my-custom-block-selector"
  }
}

Feature selectors

Feature selectors relate to styles for block supports, e.g., border, color, typography, etc.

The block may want to apply styles of individual features to different elements inside it. For example, colors to the wrapper, typography to the inner heading only.

Example

    {
	  ...
	  "selectors": {
		"root": ".my-custom-block-selector",
		"color": ".my-custom-block-selector",
		"typography": ".my-custom-block-selector > h2"
	  }
	}

Subfeature selectors

These selectors relate to individual styles provided by a particular block feature, e.g., background-color.

For a subfeature you can generate styles under its own unique selector. This is especially useful when one of the subfeatures cannot be applied to the same element as other subfeatures of the same feature.

For example — text-decoration. Browsers render this property differently, making it hard to override if added to the wrapper element. Assigning a separate selector to text-decoration allows targeting exactly those elements to which it should apply.

    {
	  ...
	  "selectors": {
		"root": ".my-custom-block-selector",
		"color": ".my-custom-block-selector",
		"typography": {
		  "root": ".my-custom-block-selector > h2",
		  "text-decoration": ".my-custom-block-selector > h2 span"
		}
	  }
	}

Shorthand

Instead of specifying a selector for each subfeature, you can provide a single selector as a string for the corresponding feature. This is how it is done for color in the examples above.

Fallbacks

If a selector for a particular feature is not configured, it falls back to the block root selector. Similarly, if a subfeature does not have a custom selector, the feature parent’s selector is used, and if that is absent — the block root selector.

Rather than repeating the same selector for multiple subfeatures you can specify a common selector as the root for the parent feature, and define unique selectors only for the differing subfeatures.

Example:

    {
	  ...
	  "selectors": {
		"root": ".my-custom-block-selector",
		"color": {
		  "text": ".my-custom-block-selector p"
		},
		"typography": {
		  "root": ".my-custom-block-selector > h2",
		  "text-decoration": ".my-custom-block-selector > h2 span"
		}
	  }
	}

In the example above color.background-color is not explicitly set. Since color also does not define a root, color.background-color will be generated under the block’s root selector — .my-custom-block-selector.

For subfeatures like typography.font-size a fallback to the parent feature’s selector will be used, since it is defined — .my-custom-block-selector > h2.

Default: —

selectors.root(string)
Primary CSS class of the block, replaces .wp-block-*.
Default: —
selectors.border(string/object)
Sselectors for borders: root|color|radius|style|width.
Default: —
selectors.color(string/object)
Sselectors for color: root|text|background.
Default: —
selectors.dimensions(string/object)
Sselectors for dimensions: root|aspectRatio|minHeight.
Default: —
selectors.spacing(string/object)
Sselectors for spacing: root|blockGap|padding|margin.
Default: —
selectors.typography(string/object)
Sselectors for typography: root|fontFamily|fontSize|fontStyle|fontWeight|lineHeight|letterSpacing|textDecoration|textTransform.
Default: —
styles(array)

Allows defining alternative styles for the block.

When a user selects a particular style, a CSS class is-style-{name} is added to the block wrapper, which can be styled in CSS.

Each object inside the array describes a separate style and can contain:

  • name(string, required)
    Unique machine name of the style (used in the CSS class).

  • label(string, required)
    Readable style name displayed in the UI. Can be localized.

  • isDefault(boolean)
    If true, the style will be selected by default.
    Default: false

Also these style variations can be configured in the style editor in the admin:

Example:

{
  "styles": [
	{ "name": "default", "label": "Default", "isDefault": true },
	{ "name": "outline", "label": "Outline" },
	{ "name": "fancy",   "label": "Fancy Style" }
  ]
}

As a result, selecting the outline style gives the block the class:

<div class="wp-block-my-block is-style-outline"></div>

Usage:

  • The theme or plugin should define CSS for the corresponding classes.
  • Useful for quick style switching (for example, filled vs outlined buttons).

You can register styles for core blocks as well by adding your own variants:

Via PHP:

register_block_style( 'core/image', [
	'name'         => 'outline',
	'label'        => 'Outline',
	'inline_style' => <<<'CSS'
		.wp-block-image.is-style-shadowed img {
			box-shadow: 0 8px 24px rgba(0,0,0,.2);
		}
		CSS,
] );

Via JS:

// In your editor.js loaded only in the editor.
wp.domReady( () => {
	wp.blocks.registerBlockStyle( 'core/paragraph', {
		name: 'outline',
		label: 'Outline'
	} );

	// Remove built-in style:
	// wp.blocks.unregisterBlockStyle( 'core/image', 'rounded' );
} );

Default: — (empty array)

example(object)
Preview data for Inspector Help.
Default: —
example.viewportWidth(int)
Width of the preview iframe.
Default: 1200
example.attributes(object)
Attributes for the preview.
Default: —
example.innerBlocks(array)
Child blocks for the preview.
Default: —
variations(string/array)
Block variations. Path to PHP returning an array, or an array of objects.
Default: —
variations[].name(string) (required)
Machine-readable variation name.
Default: —
variations[].title(string) (required)
Variation title.
Default: —
variations[].description(string)
Variation description.
Default: —
variations[].category(string)
Variation category.
Default: —
variations[].icon(string)
Variation icon.
Default: —
variations[].isDefault(boolean)
Set variation as default.
Default: false
variations[].attributes(object)
Override attributes.
Default: —
variations[].innerBlocks(array)
Initial configuration of nested blocks.
Default: —
variations[].example(object)
Preview data for variation.
Default: —
variations[].scope(array)
Where the variation is available: inserter|block|transform.
Default: ["inserter","block"]
variations[].keywords(array)
Keywords for searching variation.
Default: —
variations[].isActive(array)
List of attributes to compare variation activity.
Default: —