The block wrapper

Every block in the Block Editor is contained within an HTML wrapper, which must have specific attributes to function correctly both in the Editor and on the front end. As developers, we can directly manipulate this markup, and WordPress offers tools like useBlockProps() to modify the attributes added to a block’s wrapper.

Ensuring proper attributes to the block wrapper is especially important when using custom styling or features like block supports.

A block in WordPress can be defined with three distinct types of markup, each serving a unique role:

  • Editor Markup: This is the visual representation of the block within the Block Editor. It’s defined using an Edit React component when the block is registered on the client side via registerBlockType.
  • Save Markup: This markup is what gets saved to the database when the block’s content is saved. It’s specified through a save function, also provided to registerBlockType during block registration. If the block doesn’t utilize dynamic rendering, this saved markup is what will be displayed on the front end.
  • Dynamic Render Markup: When a block’s content needs to be generated dynamically, this markup comes into play. It’s defined server-side, either through a render_callback function in register_block_type or a render.php file specified in block.json. If present, this markup overrides any saved markup and is used for the block’s front-end display.

For both the Edit component and the save function, it’s important to use a wrapper element that’s a standard DOM element (like a <div>) or a React component that passes all additional props to native DOM elements. Using React Fragments (<Fragment>) or the <ServerSideRender> component won’t work for these wrappers.

Editor markup

The useBlockProps() hook, provided by the @wordpress/block-editor package, is used to define the outer markup of a block in the Edit component.

This hook simplifies several tasks, including:

  • Assigning a unique id to the block’s HTML structure.
  • Adding various accessibility and data- attributes for enhanced functionality and information.
  • Incorporating classes and inline styles that reflect the block’s custom settings. By default, this includes:
    • The wp-block class for general block styling.
    • A block-specific class that combines the block’s namespace and name, ensuring unique and targeted styling capabilities.

In the following example, the Editor markup of the block is defined in the Edit component using the useBlockProps() hook.

const Edit = () => <p { ...useBlockProps() }>Hello World - Block Editor</p>;

registerBlockType( ..., {
    edit: Edit
} );

See the full block example of the code above.

The markup of the block in the Block Editor could look like this, where the classes and attributes are applied automatically:

<p
    tabindex="0"
    id="block-4462939a-b918-44bb-9b7c-35a0db5ab8fe"
    role="document"
    aria-label="Block: Minimal Gutenberg Block ca6eda"
    data-block="4462939a-b918-44bb-9b7c-35a0db5ab8fe"
    data-type="block-development-examples/minimal-block-ca6eda"
    data-title="Minimal Gutenberg Block ca6eda"
    class="
        block-editor-block-list__block
        wp-block
        is-selected
        wp-block-block-development-examples-minimal-block-ca6eda
    "
>Hello World - Block Editor</p>

In a block’s Edit component, use the useBlockProps() hook to include additional classes and attributes by passing them as arguments. (See example)

When you enable features using the supports property, any corresponding classes or attributes are included in the object returned by useBlockProps automatically.

Save markup

When saving the markup in the database, it’s important to add the props returned by useBlockProps.save() to the wrapper element of your block. useBlockProps.save() ensures that the block class name is rendered correctly in addition to any HTML attributes injected by the block supports API.

Consider the following code that registers a block in the client. Notice how it defines the markup that should be used when editing the block and when the block is saved in the database.

const Edit = () => <p { ...useBlockProps() }>Hello World - Block Editor</p>;
const save = () => <p { ...useBlockProps.save() }>Hello World - Frontend</p>;

registerBlockType( ..., {
    edit: Edit,
    save,
} );

See the full block example of the code above.

The markup of the block on the front end could look like this, where the class is applied automatically:

<p class="wp-block-block-development-examples-minimal-block-ca6eda">Hello World – Frontend</p>

If you want to add any additional classes or attributes to the save function of the block, they should be passed as an argument of useBlockProps.save(). (See example)

When you add supports for any feature, the proper classes get added to the object returned by the useBlockProps.save() hook. Text and background color classes have been added to the Paragraph block in the example below.

<p class="
    wp-block-block-development-examples-block-supports-6aa4dd
    has-accent-4-color
    has-contrast-background-color
    has-text-color
    has-background
">Hello World</p>

The example block that generated this HTML is available in the Block Development Examples repository.

Dynamic render markup

In dynamic blocks, where the font-end markup is rendered server-side, you can utilize the get_block_wrapper_attributes() function to output the necessary classes and attributes just like you would use useBlockProps.save() in the save function. (See example)

<p <?php echo get_block_wrapper_attributes(); ?>>
    <?php esc_html_e( 'Block with Dynamic Rendering – hello!!!', 'block-development-examples' ); ?>
</p>