How to Add JavaScript and CSS to Gutenberg Blocks the Right Way in Plugins and Themes

icon-256x256While working on my Gutenberg Editor Development Course I had a simple question early on: “How do I enqueue my block JavaScript and CSS to work with the Gutenberg Editor?

The short answer is there are two ways:

  • enqueue_block_editor_assets – For enqueueing JavaScript and CSS in the admin editor only.
  • enqueue_block_assets – Enqueues on both the frontend of the site and in the admin editor (unless !is_admin() is used then it just enqueues on the frontend only).

Enqueueing Block JavaScript the Right Way

In general, you will want to load your main block JavaScript using enqueue_block_editor_assets since your main block JavaScript code needs to execute inside the editor.

Once a block is saved as content, the editor JavaScript is no longer needed, so most JavaScript for building blocks only needs to execute in the editor.

On occasion your block may require JavaScript to run properly on the frontend.  For example, if you were building a slideshow or a form or some other element that needed frontend interaction.  In this case, you would break out that functionality from your main block JavaScript and load it separately using enqueue_block_assets.

Enqueuing Block CSS the Right Way

The general principal for styling blocks in the new WordPress editor is to make them look the same in the editor as they do on the frontend.  To accomplish this, we enqueue our main block styles using enqueue_block_assets.

There are some instances where you need to style blocks in the editor different from the frontend.  Some reasons for this are to help give users visual cues for what they can edit or there may be controls in the editor that need styling and do no appear on the frontend.  If there are ever styles you want applied only in the editor, you can break these into a separate CSS file and load it using enqueue_block_editor_assets.

On the chance that you have styles that should only be applied to the frontend and never loaded in the editor, you can load them using enqueue_block_assets and wrap your wp_enqueue_style call inside of a !is_admin() conditional statement.

Example of Enqueueing Block JavaScript and CSS in a Plugin

This example below would go in a main plugin file that needs to load blocks.  See how both enqueue_block_assets and enqueue_block_editor_assets are used.


<?php
/**
* Enqueue block editor JavaScript and CSS
*/
function jsforwpblocks_editor_scripts() {
// Make paths variables so we don't write em twice 😉
$blockPath = '/assets/js/blocks.js';
$editorStylePath = '/assets/css/blocks.editor.css';
// Enqueue the bundled block JS file
wp_enqueue_script(
'jsforwp-blocks-js',
plugins_url( $blockPath, __FILE__ ),
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-i18n' ],
filemtime( plugin_dir_path( __FILE__ ) . $blockPath )
);
// Enqueue optional editor only styles
wp_enqueue_style(
'jsforwp-blocks-editor-css',
plugins_url($editorStylePath, __FILE__),
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-i18n' ],
filemtime( plugin_dir_path( __FILE__ ) . $editorStylePath )
);
}
// Hook scripts function into block editor hook
add_action( 'enqueue_block_editor_assets', 'jsforwpblocks_editor_scripts' );
/**
* Enqueue block editor JavaScript and CSS
*/
function jsforwpblocks_scripts() {
// Make paths variables so we don't write em twice 😉
$sharedBlockPath = '/assets/js/blocks.shared.js';
$stylePath = '/assets/css/blocks.style.css';
$frontendStylePath = '/assets/css/blocks.frontend.css';
// Enqueue frontend and editor JS
wp_enqueue_script(
'jsforwp-blocks-frontend-js',
plugins_url( $sharedBlockPath, __FILE__ ),
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-i18n' ],
filemtime( plugin_dir_path( __FILE__ ) . $sharedBlockPath )
);
// Enqueue frontend and editor block styles
wp_enqueue_style(
'jsforwp-blocks-css',
plugins_url($stylePath, __FILE__),
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-i18n' ],
filemtime( plugin_dir_path( __FILE__ ) . $stylePath )
);
// Enqueue frontend only CSS
if( !is_admin() ) {
wp_enqueue_style(
'jsforwp-blocks-frontend-css',
plugins_url($frontendStylePath, __FILE__),
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-i18n' ],
filemtime( plugin_dir_path( __FILE__ ) . $frontendStylePath )
);
}
}
// Hook scripts function into block editor hook
add_action( 'enqueue_block_assets', 'jsforwpblocks_scripts' );

Some notes on the example above:

  • We have a file /assets/js/blocks.js with our main block JS code.  This is being loaded with enqueue_block_editor_assets into the editor.
  • We have a file /assets/css/blocks.editor.css with our editor only styles.  This is also being loaded in the same function call as our JavaScript, which hooks into enqueue_block_editor_assets.
  • Then we have a file /assets/js/blocks.shared.js with additional JS code that needs to be loaded on the frontend and backend.  This is being loaded with enqueue_block_assets into the editor and frontend.  Note, you may or may not need JavaScript loaded on the frontend depending on the type of blocks you build.
  • We also have /assets/css/blocks.styles.css, which is our main CSS file.  This will load on the front and backend since we have it hooked into enqueue_block_assets.
  • The final file /assets/css/blocks.frontend.css is wrapped inside of the !is_admin() conditional statement so it will not load in the editor as is usually the case with enqueue_block_assets. Note, you probably don’t need a frontend only stylesheet.  It is also recommended to use editor only styles to override shared frontend/editor styles rather than this approach demonstrated here for example purposes.

This should cover the basic use cases you will have for loading block JavaScript and CSS into your plugins.  Let me know if I missed something you find useful!

Example of Enqueueing Block CSS in a Theme

In general, you should NOT build blocks inside of themes.  Custom blocks should generally be built inside of plugins.  However, it is perfectly acceptable for themes to customize block styles, both in the editor and on the frontend.

The example below shows how to load CSS in your themes to override default block styles.  This code would go inside of  or be included into a theme’s functions.php file.


<?php
/**
* Enqueue block editor CSS
*/
function jsforwpblocks_editor_scripts() {
// Make paths variables so we don't write em twice 😉
$editorStylePath = '/assets/css/blocks.editor.css';
// Enqueue optional editor only styles
wp_enqueue_style(
'jsforwp-blocks-editor-css',
get_stylesheet_directory_uri() . $editorStylePath,
['wp-blocks'],
filemtime( get_template_directory() . $editorStylePath )
);
}
// Hook scripts function into block editor hook
add_action( 'enqueue_block_editor_assets', 'jsforwpblocks_editor_scripts' );
/**
* Enqueue block editor CSS
*/
function jsforwpblocks_scripts() {
// Make paths variables so we don't write em twice 😉
$stylePath = '/assets/css/blocks.style.css';
$frontendStylePath = '/assets/css/blocks.frontend.css';
// Enqueue frontend and editor block styles
wp_enqueue_style(
'jsforwp-blocks-css',
get_stylesheet_directory_uri() . $stylePath,
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-i18n' ],
filemtime( get_template_directory() . $stylePath )
);
// Enqueue frontend only CSS
if( !is_admin() ) {
wp_enqueue_style(
'jsforwp-blocks-frontend-css',
get_stylesheet_directory_uri() . $frontendStylePath,
[ 'wp-blocks', 'wp-element', 'wp-components', 'wp-i18n' ],
filemtime( get_template_directory() . $frontendStylePath )
);
}
}
// Hook scripts function into block editor hook
add_action( 'enqueue_block_assets', 'jsforwpblocks_scripts' );

Some notes on the code above:

  • We are not including any block JavaScript since that should generally go in a plugin.
  • We have a file /assets/css/blocks.editor.css with our editor only styles.  This is being loaded using enqueue_block_editor_assets.  Note, there is a chance you may not need editor only CSS.
  • We also have /assets/css/blocks.styles.css, which is our main CSS file.  This will load on the front and backend since we have it hooked into enqueue_block_assets.
  • The final file /assets/css/blocks.frontend.css is wrapped inside of the !is_admin() conditional statement so it will not load in the editor as is usually the case with enqueue_block_assets. Note, you will likely not need a frontend only stylesheet.  It is also recommended to use editor only styles to override shared frontend/editor styles rather than this approach demonstrated here for example purposes.

A Note on File Organization and Compilation

The examples above show including only a few final JavaScript and CSS files all within ‘/assets/js’ and ‘/assets/css’.  It is likely that you will break your JavaScript and CSS into smaller files and compile them using a tool like webpack.

If you bundle your final JS and CSS into a different directory structure than the ‘/assets/js’ and ‘/assets/css’ structure used above, you may need to make some changes to the examples.  Same goes for how you name your files.

The examples above do not offer insight into how you should organize your modular JS and CSS or how you would setup a tool like webpack to handle compiling it all.  I do have some thoughts on these matters and you can see my course below or wait for upcoming blog posts on these topics.  However, in general, try to follow modern best practices.

To Learn More About Developing with the New WordPress Editor

If you would like to learn more about developing blocks with WordPress, please check out my course Gutenberg Development.

One thought on “How to Add JavaScript and CSS to Gutenberg Blocks the Right Way in Plugins and Themes

Leave a comment