Any ideal way how to change Gutenberg’s categories checkboxes to radio inputs? I have tried using this plugin: Categories Metabox Enhanced.
But it doesn’t work fully well with Gutenberg, meaning my conditions to show some field when a term is checked doesn’t work. Also this plugin adds an extra meta box without replacing Gutenberg’s default categories box.

Fortunately there is a hook that we can use to customize what component is used to render the taxonomy panels called editor.PostTaxonomyType
.
Gutenberg renders taxonomy panels with a component called PostTaxonomies
, which really just checks whether the taxonomy is heirarchical or not, and passes the props along to either the HierarchicalTermSelector
or FlatTermSelector
components accordingly. Normally, these two components don’t appear to be exposed in the Gutenberg API, except for within the editor.PostTaxonomyType
hook, which passes the relevant component as the 1st argument.
From there, all we have to do is extend the component, override the renderTerms
method to change the input type from checkbox
to radio
, and override the onChange
method to only return one selected term.
Unfortunately, extending the class within the hook seemed to cause a noticable performance hit, but storing the extended class in the window
seemed to mitigate that.
PostTaxonomies
HierarchicalTermSelector
/**
* External dependencies
*/
import { unescape as unescapeString } from 'lodash';
function customizeTaxonomySelector( OriginalComponent ) {
return function( props ) {
if ( props.slug === 'my_taxonomy') {
if ( ! window.HierarchicalTermRadioSelector ) {
window.HierarchicalTermRadioSelector = class HierarchicalTermRadioSelector extends OriginalComponent {
// Return only the selected term ID
onChange( event ) {
const { onUpdateTerms, taxonomy } = this.props;
const termId = parseInt( event.target.value, 10 );
onUpdateTerms( [ termId ], taxonomy.rest_base );
}
// Copied from HierarchicalTermSelector, changed input type to radio
renderTerms( renderedTerms ) {
const { terms = [] } = this.props;
return renderedTerms.map( ( term ) => {
const id = `editor-post-taxonomies-hierarchical-term-${ term.id }`;
return (
<div key={ term.id } className="editor-post-taxonomies__hierarchical-terms-choice">
<input
id={ id }
className="editor-post-taxonomies__hierarchical-terms-input"
type="radio"
checked={ terms.indexOf( term.id ) !== -1 }
value={ term.id }
onChange={ this.onChange }
/>
<label htmlFor={ id }>{ unescapeString( term.name ) }</label>
{ !! term.children.length && <div className="editor-post-taxonomies__hierarchical-terms-subchoices">{ this.renderTerms( term.children ) }</div> }
</div>
);
} );
}
};
}
return <window.HierarchicalTermRadioSelector { ...props } />;
}
return <OriginalComponent { ...props } />;
};
}
wp.hooks.addFilter( 'editor.PostTaxonomyType', 'my-custom-plugin', customizeTaxonomySelector );