Picture this: you’re happily writing code for that block that you’ve been dreaming about building for a while. Almost all the elements and settings are in their place. You’re near the finish line and ready to put this thing out into the world.
But there’s one thing missing: you need an extra color setting.
You’ve already implemented the standard text, background, and link colors that WordPress offers block developers out of the box. But your block is special. It needs at least one more color so that your users can enjoy the ultimate customizability that you envisioned when you set out on this journey.
But there’s a catch: WordPress doesn’t have a simple method of just configuring a color attribute that will magically work for your block (it’d be cool if it did). You’ve suddenly got to code all of that.
This is a tutorial that gives you a solution on adding custom color options to your blocks.
Table of Contents
Some things to know up front
This is an advanced tutorial, so I’m making some assumptions about your knowledge level. This is necessary to keep this article down to a somewhat reasonable word count.
In particular, I’m making two major assumptions:
- You already know how to build custom blocks from scratch and work with the
@wordpress/scripts
package. - You’re comfortable enough to take what you learn from this guide and extend it for custom use cases.
If you’re not quite there yet and need further help, hop over to the Block Editor Handbook and get started with some of its available guides. When you feel like you’re ready for this tutorial, it will still be here waiting for you.
You can view the example block I built to write this tutorial in its GitHub repository. I will not explain each detail of this—remember, I’m assuming some prior knowledge. But the code is available for you to use however you want.
I’m putting this in a big ol’ alert box to make sure you read it, so please don’t skip this part.
The code in this tutorial uses experimental features in WordPress. This absolutely means they can—and probably will—break at some point. If you don’t like living life on the bleeding edge, this is probably not the tutorial for you. But if you’re anything like me and enjoy fixing broken things, just remember that you are ultimately responsible for updating your plugins, themes, or sites if you decide to use this in production and it stops working down the road.
Building a list block with colored markers
In the following sections, you will learn how to add add a custom marker color option for a block that outputs a basic HTML list like this:
Undoubtedly, you’ll want to apply this to your own block that you’re building, so feel free to pick out the bits you need as you read along. But it’s also a good exercise to follow along with the steps and build this simpler block.
Setting up your block plugin
In this tutorial, the examples will be shown within a static block, but you can also apply them to a dynamic block. It follows the standard file and folder naming conventions that you will get from the @wordpress/create-block
or @wordpress/scripts
packages.
The file structure of your plugin should be:
build/
- WordPress will output the compiled files to this folder.
src/
block.json
edit.js
index.js
save.js
style.scss
index.php
To get started, add your Plugin File Header and register the block using the register_block_type()
function on the init
hook:
<?php
/**
* Plugin Name: List Block With Marker Colors
* Plugin URI: https://developer.wordpress.org/news/
* Description: An example block that shows a list with a custom marker color option.
* Version: 1.0.0
* Requires at least: 6.3
* Requires PHP: 7.4
* Author: WordPress Developer Blog
* Author URI: https://developer.wordpress.org/news/
* Text Domain: devblog
*/
add_action( 'init', 'devblog_list_marker_colors_setup' );
function devblog_list_marker_colors_setup() {
register_block_type( trailingslashit( __DIR__ ) . 'build' );
}
Adding color attributes to block.json
When adding custom color options, you should always be mindful of what’s already available to you out of the box. WordPress has attributes for handling:
- Text color
- Link text color
- Background color and gradient
- Border color (handled through
border
supports rather thancolor
)
It only makes sense to add new color attributes if you cannot make use of the defaults. Keep in mind that you can use the Selectors API to apply existing color attributes to specific selectors for your block.
For our fictional list block, let’s add a single color option that lets users change the list marker (bullet) color.
To do this, you will need two new attributes:
markerColor
: (string) For storing the slug when the user selects a preset color.customMarkerColor
: (string) For saving the CSS version of the color for either the color preset or when a user chooses a custom color.
Technically, you can use a single attribute for this and add some custom logic behind the scenes for handling both presets and custom colors. But using two separate attributes makes for a simpler codebase. You’ll probably find that there are many different ways of wrangling this once you start customizing this for your own blocks.
In your block.json
file, add the markerColor
and customMarkerColor
properties to the attributes
object:
{
"apiVersion": 3,
"version": "1.0.0",
"name": "devblog/list-with-marker-colors",
"title": "List With Marker Colors",
"category": "widgets",
"description": "Add a custom description here.",
"attributes" : {
"markerColor": {
"type": "string"
},
"customMarkerColor": {
"type": "string"
}
},
"supports": {
"color": {
"link": true,
"gradients": true
}
},
"textdomain": "devblog",
"editorScript": "file:./index.js",
"style": "file:./style-index.css",
"example": {}
}
Building the block edit function
With all the initial setup and block.json
code in place, it’s time to get into the heart of this tutorial and add that custom control for your block type. That’s what you came here for, right?
In the following subsections, you will work directly within your block’s edit.js
file.
Importing dependencies
Before writing any custom code, you’ll import several dependencies from the @wordpress/block-editor
and @wordpress/i18n
packages. You should already be familiar with most of these, but the color-specific components that might be new to you are:
withColors
__experimentalColorGradientSettingsDropdown
__experimentalUseMultipleOriginColorsAndGradients
We’ll dive into how those work in the upcoming sections. For now, you just need to import them at the top of your edit.js
file:
import {
InspectorControls,
useBlockProps,
withColors,
__experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
__experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients
} from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
The code uses aliases for the experimental component names, removing the __experimental
prefix. This is standard practice so that you only need to change the import code itself when the component is no longer experimental.
Coding the block edit function
After you’ve added your imports, you need a block edit function to handle the functionality in the editor. To do this, add this code to your block’s edit.js
file:
const Edit = ( {
attributes: {
customMarkerColor
},
markerColor,
setMarkerColor,
setAttributes,
style,
clientId
} ) => {
// Add your custom code here.
};
export default withColors( {
markerColor: 'marker-color'
} )( Edit );
You’ll likely notice that markerColor
is not nested under the attributes
property. It is a separate property altogether, and there is an accompanying setMarkerColor
. This is because the edit function is wrapped with the withColors
higher-order component. This gives you specific properties to access for more efficiently working with colors.
Instead of a string, markerColor
is now an object with several properties that you can access. This is an example of what that object looks like when a preset color is selected:
{
class: "has-vivid-red-marker-color",
color: "#cf2e2e",
name: "Vivid red",
slug: "vivid-red"
}
But it looks like this when a custom color is selected:
{
class: undefined,
color: "#66b3dc"
}
You can use this data to do all sorts of neat things, such as adding the class to the block wrapper or manipulating the slug to do something custom.
setMarkerColor
is a function for setting a new marker color for the list. It is built from the markerColor
name passed into withColors
by prefixing it with set
.
Now let’s start building the guts of the Edit()
function. The remainder of the code snippets in this section should be placed within the function itself.
The first thing you need to grab is a copy of the WordPress color and gradient settings. This uses the useMultipleOriginColorsAndGradients()
(experimental) React hook. It gives you an object with most of the settings you’ll need for your color control, including arrays of the WordPress, theme, and user-defined colors and gradients.
Add this code within your block’s Edit()
function:
const colorGradientSettings = useMultipleOriginColorsAndGradients();
Next, you will assign the useBlockProps()
hook to the blockProps
constant. But you’ll also use this opportunity to add your logic for outputting the marker color.
To do this, you’ll manipulate the style
property for the block. Because this particular scenario will target list markers, the code below uses a CSS custom property named --devblog-list-marker
and assigns it the marker color.
Add this code within your block’s Edit()
function:
const blockProps = useBlockProps( {
style: {
...style,
'--devblog-list-marker': markerColor.slug
? `var( --wp--preset--color--${ markerColor.slug } )`
: customMarkerColor,
}
} );
Now it’s time to add the custom color control. For this, you’ll need the ColorGradientSettingsDropdown
(experimental) component. Really, all you’re mostly doing at this point is plugging in a handful of values.
Add this code to your block’s Edit()
function:
const markerColorDropdown = (
<ColorGradientSettingsDropdown
settings={ [ {
label: __( 'Marker', 'devblog' ),
colorValue: markerColor.color || customMarkerColor,
onColorChange: ( value ) => {
setMarkerColor( value );
setAttributes( {
customMarkerColor: value
} );
}
} ] }
panelId={ clientId }
hasColorsOrGradients={ false }
disableCustomColors={ false }
__experimentalIsRenderedInSidebar
{ ...colorGradientSettings }
/>
);
I want to draw your attention to two of the component’s properties:
colorValue
: For the value here, make sure to check formarkerColor.color
orcustomMarkerColor
.onColorChange
: You need to call bothsetMarkerColor()
(for setting themarkerColor
attribute) andsetAttributes
(for setting thecustomMarkerColor
attribute).
The last item is to return the block controls and markup. For this block type, I left this as a simple unordered list for the purposes of demonstration. You will obviously want to apply this technique to more complex blocks.
Now add this final bit of code inside of your block’s Edit()
function:
return (
<>
<InspectorControls group="color">
{ markerColorDropdown }
</InspectorControls>
<ul { ...blockProps }>
<li>{ __( 'List Item 1', 'devblog' ) }</li>
<li>{ __( 'List Item 2', 'devblog' ) }</li>
<li>{ __( 'List Item 3', 'devblog' ) }</li>
<li>{ __( 'List Item 4', 'devblog' ) }</li>
<li>{ __( 'List Item 5', 'devblog' ) }</li>
</ul>
</>
);
One thing to note about this code is the group
attribute for <InspectorControls>
. By giving it a value of color
, you’re telling WordPress to stick your marker color picker alongside all of the other color settings in the block’s sidebar. To learn more about how this works, check out Using block inspector sidebar groups.
Building the block save function
Since this is a static block, we also need to save the block markup in the backend. If you’re building a dynamic block, you will add your handling on the PHP side.
In the following subsections, you will be working in your block’s save.js
file.
Importing dependencies
As usual, you need to import some dependencies for your save function. And again, you’ll need a couple of things from the @wordpress/block-editor
and @wordpress/i18n
packages.
Add this code to the top of your block’s save.js
file:
import { useBlockProps } from '@wordpress/block-editor';
import { __ } from '@wordpress/i18n';
Exporting the save function
The save function is much simpler than the edit function from the previous section. For this, you basically just need to export your final markup for the block so that it’s stored in the database.
The major difference here is that you’ll need both the markerColor
and customMarkerColor
attributes. As defined in block.json
, each will be a string value.
Add this code in your save.js
file:
export default function Save( {
attributes: {
markerColor,
customMarkerColor
},
style
} ) {
const blockProps = useBlockProps.save( {
style: {
...style,
'--devblog-list-marker': markerColor !== undefined
? `var( --wp--preset--color--${ markerColor } )`
: customMarkerColor,
}
} );
return (
<ul { ...blockProps }>
<li>{ __( 'List Item 1', 'devblog' ) }</li>
<li>{ __( 'List Item 2', 'devblog' ) }</li>
<li>{ __( 'List Item 3', 'devblog' ) }</li>
<li>{ __( 'List Item 4', 'devblog' ) }</li>
<li>{ __( 'List Item 5', 'devblog' ) }</li>
</ul>
);
}
Adding custom styles
Since the block uses the --devblog-list-marker
CSS custom property for handling the list marker color, it needs a way to tell the browser to display that color. For this, you need to target any ::marker
pseudo-elements for the block in your CSS.
Add this to your block’s style.scss
file:
.wp-block-devblog-list-with-marker-colors ::marker {
color: var( --devblog-list-marker, inherit );
}
Of course, for your own block types, you should target the specific element that you’re using the color for. ::marker
is specific to the list used in the block.
Registering your block
Now you just need to register your block via JavaScript for it to work. To do this, open your block’s index.js
file.
Once again, you need to import a few things. You’ll need the registerBlockType()
function from the @wordpress/blocks
package and your block’s custom files.
Add this code at the top of your block’s index.js
file:
// Import stylesheets.
import './style.scss';
// Import dependencies.
import { registerBlockType } from '@wordpress/blocks';
import blockEdit from './edit';
import blockSave from './save';
import blockData from './block.json';
Now you just need to pass the data you imported into the registerBlockType()
function:
registerBlockType( blockData, {
edit: blockEdit,
save: blockSave
} );
Once you’ve saved everything, you should see your new block under the Widgets category in inserter:
Add your own color options
There is a lot that I left unsaid in this tutorial. I’ve experimented with various methods for wrangling color options in the last year or so. In that time, some things have changed in WordPress. I’m also continually learning new techniques—a colleague even showed me an entirely new approach in the middle of writing the first version of this tutorial. And given that this tutorial is using components that are experimental, I think it’s OK to leave a few things out.
The goal for this tutorial was to provide you with a base to run your own experiments, break a few things along the way, and bring your experience back into the discussion. Feel free to share in the comments.
So go forth and have some fun with custom colors!
Props to @webcommsat, @juanmaguitar, and @ndiego for feedback and review.
Leave a Reply