Block Styles
Block styles provide visual variations that users can apply from the block toolbar.
Defining Styles in block.json
{
"styles": [
{
"name": "default",
"label": "Default",
"isDefault": true
},
{
"name": "outlined",
"label": "Outlined"
},
{
"name": "shadow",
"label": "Shadow"
}
]
}
Style Properties
| Property | Type | Description |
|---|---|---|
name |
string | CSS class suffix (required) |
label |
string | Display name (required) |
isDefault |
boolean | Applied by default |
How Styles Work
When a user selects a style, WordPress adds a class to the block:
is-style-{style-name}
For a style named outlined:
<div class="wp-block-my-plugin-card is-style-outlined">
...
</div>
CSS for Block Styles
Style your variations in CSS:
/* Default style (no class needed, but can target explicitly) */
.wp-block-my-plugin-card,
.wp-block-my-plugin-card.is-style-default {
border: 1px solid #ddd;
padding: 20px;
}
/* Outlined style */
.wp-block-my-plugin-card.is-style-outlined {
border: 2px solid currentColor;
background: transparent;
}
/* Shadow style */
.wp-block-my-plugin-card.is-style-shadow {
border: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
Editor Preview Styles
Ensure styles work in the editor by including them in style.css (loads in both editor and frontend) or by adding styles to editorStyle.
JavaScript Registration
For more control, register styles in JavaScript:
import { registerBlockStyle } from '@wordpress/blocks';
registerBlockStyle( 'core/quote', {
name: 'fancy',
label: 'Fancy',
} );
registerBlockStyle( 'core/quote', {
name: 'modern',
label: 'Modern',
isDefault: true,
} );
Registering Styles for Core Blocks
Add styles to core blocks:
import { registerBlockStyle } from '@wordpress/blocks';
wp.domReady( () => {
// Add styles to core/button
registerBlockStyle( 'core/button', {
name: 'gradient',
label: 'Gradient',
} );
// Add styles to core/image
registerBlockStyle( 'core/image', {
name: 'rounded',
label: 'Rounded Corners',
} );
registerBlockStyle( 'core/image', {
name: 'polaroid',
label: 'Polaroid',
} );
} );
CSS for core block styles:
/* Gradient button */
.wp-block-button.is-style-gradient .wp-block-button__link {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
}
/* Rounded image */
.wp-block-image.is-style-rounded img {
border-radius: 16px;
}
/* Polaroid image */
.wp-block-image.is-style-polaroid {
background: white;
padding: 12px 12px 40px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
Unregistering Styles
Remove existing styles:
import { unregisterBlockStyle } from '@wordpress/blocks';
wp.domReady( () => {
// Remove the "plain" style from core/quote
unregisterBlockStyle( 'core/quote', 'plain' );
// Remove default style from core/image
unregisterBlockStyle( 'core/image', 'default' );
} );
PHP Registration
Register styles from PHP:
add_action( 'init', function() {
register_block_style(
'core/paragraph',
[
'name' => 'highlight',
'label' => __( 'Highlight', 'my-plugin' ),
]
);
register_block_style(
'core/paragraph',
[
'name' => 'large-text',
'label' => __( 'Large Text', 'my-plugin' ),
'is_default' => false,
'style_handle' => 'my-plugin-block-styles', // Optional: associated stylesheet
]
);
} );
With inline styles:
register_block_style(
'core/paragraph',
[
'name' => 'fancy',
'label' => __( 'Fancy', 'my-plugin' ),
'inline_style' => '.is-style-fancy {
font-family: Georgia, serif;
font-style: italic;
border-left: 4px solid currentColor;
padding-left: 1em;
}',
]
);
Unregistering Styles in PHP
add_action( 'init', function() {
unregister_block_style( 'core/quote', 'plain' );
} );
Note: Must run after the style is registered (priority matters).
Style Variations via theme.json
Define styles in theme.json for theme-specific variations:
{
"version": 2,
"styles": {
"blocks": {
"core/button": {
"variations": {
"outline": {
"border": {
"width": "2px",
"style": "solid",
"color": "currentColor"
},
"color": {
"background": "transparent"
}
}
}
}
}
}
}
Conditional Style Registration
Register styles based on context:
add_action( 'init', function() {
// Only for themes that support custom styles
if ( current_theme_supports( 'custom-block-styles' ) ) {
register_block_style( 'core/group', [
'name' => 'boxed',
'label' => __( 'Boxed', 'my-plugin' ),
] );
}
} );
Style-Specific Attributes
Some styles might need attribute changes. Handle in edit component:
import { useEffect } from '@wordpress/element';
export default function Edit( { attributes, setAttributes } ) {
const { className } = attributes;
// Adjust attributes based on style
useEffect( () => {
if ( className?.includes( 'is-style-compact' ) ) {
setAttributes( { padding: 'small' } );
}
}, [ className ] );
// ...
}
Complete Example: Card Block with Styles
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "my-plugin/card",
"title": "Card",
"category": "design",
"styles": [
{
"name": "default",
"label": "Default",
"isDefault": true
},
{
"name": "bordered",
"label": "Bordered"
},
{
"name": "elevated",
"label": "Elevated"
},
{
"name": "filled",
"label": "Filled"
}
],
"style": "file:./style.css",
"editorScript": "file:./index.js"
}
/* style.css */
/* Base styles for all cards */
.wp-block-my-plugin-card {
padding: 24px;
border-radius: 8px;
}
/* Default style */
.wp-block-my-plugin-card.is-style-default {
background: #ffffff;
border: 1px solid #e2e8f0;
}
/* Bordered style */
.wp-block-my-plugin-card.is-style-bordered {
background: transparent;
border: 2px solid currentColor;
}
/* Elevated style */
.wp-block-my-plugin-card.is-style-elevated {
background: #ffffff;
border: none;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
/* Filled style */
.wp-block-my-plugin-card.is-style-filled {
background: #f1f5f9;
border: none;
}
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.wp-block-my-plugin-card.is-style-default {
background: #1e293b;
border-color: #334155;
}
.wp-block-my-plugin-card.is-style-elevated {
background: #1e293b;
box-shadow:
0 4px 6px -1px rgba(0, 0, 0, 0.3),
0 2px 4px -1px rgba(0, 0, 0, 0.2);
}
.wp-block-my-plugin-card.is-style-filled {
background: #334155;
}
}
Programmatic Style Detection
Check active style in PHP:
function render_my_block( $attributes, $content, $block ) {
$class_name = $attributes['className'] ?? '';
// Check for specific style
if ( str_contains( $class_name, 'is-style-elevated' ) ) {
// Add extra markup for elevated style
}
return $content;
}
In JavaScript:
export default function Edit( { attributes } ) {
const { className } = attributes;
const isElevated = className?.includes( 'is-style-elevated' );
const isBordered = className?.includes( 'is-style-bordered' );
return (
<div { ...useBlockProps() }>
{ isElevated && <div className="shadow-overlay" /> }
{/* ... */}
</div>
);
}
Style Previews
Styles appear in the Styles panel with previews. The preview uses your block’s example:
{
"example": {
"attributes": {
"title": "Card Title",
"content": "Preview content for the card."
}
},
"styles": [
{ "name": "default", "label": "Default", "isDefault": true },
{ "name": "bordered", "label": "Bordered" }
]
}
Best Practices
-
Consistent naming: Use descriptive, lowercase names with hyphens.
-
Always include default: Mark one style as
isDefault: true. -
Base styles first: Write base styles that apply to all variations.
-
Use specificity wisely:
.block.is-style-nameis usually enough. -
Support dark mode: Consider color scheme preferences.
-
Test in editor: Ensure styles render correctly in the block editor.
-
Keep it visual: Styles should create visible differences.
-
Limit options: 3-5 styles is usually plenty.