Create different color palettes with Gutenberg

In this post I show how to create different color palettes in Gutenberg, to – for example – allow other colors for the text than for the background.

Update from November 18, 2018: One of the latest Gutenberg updates removed the PanelColor component, so I updated the code with the instead-to-use PanelColorSettings component. That makes it easier, because it directly allows us to specify custom colors.

Update from July 11, 2018: Both color attributes need to be set as attributes in the last code block. Otherwise, the selected colors are not recognized from the color pickers after reloading the browser.

The Goal

The goal was to recreate the color pickers that are available in the paragraph block:

A screenshot of the color palettes present in the sidebar when a paragraph block is selected in Gutenberg. Both palettes – for text and background color – have the same colors.

The colors are inside an area that can be toggled, and the selected color is shown next to the title of the area. When a color is selected, the paragraph element gets a class and an inline style.

The solution

First, my solution was to use the PanelColor component, which does not allow custom colors easily, so that was a little trickier than the solution via PanelColorSettings. That component allows us to set a custom color set – but you need to define all used colors via add_theme_support( 'editor-color-palette' ), because that is what Gutenberg uses for generating the color class names.

With that, the solution is made of two parts:

  • Tell Gutenberg about the wanted colors with add_theme_support( 'editor-color-palette' ).
  • Recreate the color part from the paragraph block.

I assume that you have installed Gutenberg and included a JavaScript file in the editor and are already using a package.json. I am using modern JavaScript syntax, which is converted to ES5 with Babel.

Define the color palette

At first, we need to define our colors, which we want to use later:

add_action( 'after_setup_theme', 'setup_theme_supported_features' );

/**
 * Remove unused Gutenberg features.
 */
function setup_theme_supported_features() {
	add_theme_support( 'editor-color-palette', 
		[
			'name' => 'Puerto Rico',
			'slug' => 'puerto-rico',
			'color' => '#53c4ab',
		],
		[
			'name' => 'Tundora',
			'slug' => 'tundora',
			'color' => '#454545',
		],
		[
			'name' => 'Butterfly Bush',
			'slug' => 'butterfly-bush',
			'color' => '#5151a0',
		],
		[
			'name' => 'White',
			'slug' => 'white',
			'color' => '#ffffff',
		],
	);

	add_theme_support( 'disable-custom-colors' );
}

The JavaScript part

Besides Gutenberg components, we need the classnames library. To install it, we run the following command in our command line:

npm install classnames

Now let us begin with the external things, that we need to import into the JavaScript file:

import classnames from 'classnames';

const {
	registerBlockType,
} = wp.blocks;
const {
	InspectorControls,
	InnerBlocks,
	withColors,
	getColorClass
} = wp.editor;
const {
	PanelBody,
	withFallbackStyles,
	PanelColor,
	ColorPalette,
} = wp.components;

const {
	compose,
	Component,
} = wp.element;

const {getComputedStyle} = window;

const FallbackStyles = withFallbackStyles((node, ownProps) => {
	const {textColor, backgroundColor} = ownProps.attributes;
	const editableNode = node.querySelector('[contenteditable="true"]');
	//verify if editableNode is available, before using getComputedStyle.
	const computedStyles = editableNode ? getComputedStyle(editableNode) : null;
	return {
		fallbackBackgroundColor: backgroundColor || !computedStyles ? undefined : computedStyles.backgroundColor,
		fallbackTextColor: textColor || !computedStyles ? undefined : computedStyles.color,
	};
});

Like already written, the solution is composed of existing Gutenberg components – that said, those definitions and the withFallbackStyles() function in the paragraph block and the PanelColor component.

Like it is made in the paragraph block, we will define the edit part of our block as a subclass of Component:

class OneColumnBlock extends Component {
	constructor() {
		super(...arguments);
	}

	render() {
		const {
			attributes,
			setAttributes,
			mergeBlocks,
			onReplace,
			className,
			backgroundColor,
			textColor,
			setBackgroundColor,
			setTextColor,
			fallbackBackgroundColor,
			fallbackTextColor,
			fallbackFontSize,
		} = this.props;

		const textColors = [
			{
				name: 'Tundora',
				slug: 'tundora',
				color: '#454545'
			},
		];
		const backgroundColors = [
			{
				name: 'Puerto Rico',
				slug: 'puerto-rico',
				color: '#53c4ab'
			},
			{
				name: 'Butterfly Bush',
				slug: 'butterfly-bush',
				color: '#5151a0'
			},
			{
				name: 'White',
				slug: 'white',
				color: '#ffffff'
			}
		];

		return (
			<div
				className={classnames(className, {
					'has-background': backgroundColor.value,
					[backgroundColor.class]: backgroundColor.class,
					[textColor.class]: textColor.class,
				})}
				
				style={{
					backgroundColor: backgroundColor.value,
					color: textColor.value,
				}}
			>
				<InnerBlocks/>
				<InspectorControls>
					<PanelColorSettings
						title="'Farbschema"
						colorSettings={[
							{
								colors: textColors,
								label: 'Textfarbe',
								onChange: setTextColor,
								value: textColor.color,
								disableCustomColors: true,
							},
							{
								colors: backgroundColors,
								label: 'Hintergrundfarbe',
								onChange: setBackgroundColor,
								value: backgroundColor.color,
								disableCustomColors: true,
							}
						]}
					/>
				</InspectorControls>
			</div>
		);
	}
}

Interesting is the render part. The constants at the beginning are from the paragraph block – textColors and backgroundColors are our subsets of the colors defined in add_theme_support( 'editor-color-palette' ).

In the return part, we open a div, in which the class names and the inline styles are outputted. This is also taken from the paragraph component. InnerBlocks is a component, that enables it to insert other blocks into a block, and after that inside InspectorControls we create our color pickers with the PanelColorSettings component.

First, we define the title of the panel and pass an array of objects via colorSettings, where each object stands for one color picker. colors allows us to set a custom set of colors (the default colors would be the ones from the  add_theme_support( 'editor-color-palette' ) part) – the first one gets our text color, and the second one our background colors.

label is the – well – label of the individual color picker, and onChange gets the functions that save the colors (taken from the paragraph block). The value is the hex value and we want to disable that the user can select a custom color.

One last piece of code remains – also inspired by the paragraph component:

export default registerBlockType('slug/one-column', {
	title: 'Eine Spalte',
	icon: 'admin-post',
	category: 'layout',
	edit: compose([
		withColors('backgroundColor', {textColor: 'color'}),
		FallbackStyles,
	])(OneColumnBlock),
	save: props => {
		const {
			backgroundColor,
			textColor,
			customBackgroundColor,
			customTextColor,
		} = props.attributes;

		const textClass = getColorClass( 'color', textColor );
		const backgroundClass = getColorClass( 'background-color', backgroundColor );
		
		const className = classnames( {
			'has-background': backgroundColor || customBackgroundColor,
			[ textClass ]: textClass,
			[ backgroundClass ]: backgroundClass,
		} );
		return (
			<div className={className}>
				<InnerBlocks.Content/>
			</div>
		);
	},
});

Here we register our block slug/one-column and set a few meta data. edit is our OneColumnBlock class and in save we build the color classes and set them for a div container, that wraps the content of the InnerBlocks.

And that is the result (I have a few more colors in the project that used in the example):

Screenshot of our result. Two color picker controls with different color palettes.

The complete code can be found as a Gist on GitHub.

Related posts

3 comments on »Create different color palettes with Gutenberg«

  1. Mike England

    Thank you for sharing this! I've been trying to re-create this block in particular for the color palette panel and have had some very tough struggles getting it to work.

    Reply

Leave a Reply to Mike England Cancel reply

Your email address will not be published. Required fields are marked *