Voici la marche à suivre, étape par étape, pour construire un panneau de réglages latéral propre pour un bloc « grille de produits » qui doit permettre de choisir le nombre de colonnes, d’activer les prix, de définir un tri et de régler un espacement. Rien de complexe individuellement, mais l’empilement de plusieurs réglages mal organisés donne vite un panneau illisible.
Étape 1 : poser InspectorControls et PanelBody
InspectorControls, comme BlockControls, vient de @wordpress/block-editor et ne rend rien dans save() : son contenu est téléporté dans le panneau latéral droit de l’éditeur, visible uniquement quand le bloc est sélectionné.
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody } from '@wordpress/components';
export default function Edit( { attributes, setAttributes } ) {
return (
<>
<InspectorControls>
<PanelBody title="Mise en page" initialOpen={ true }>
{ /* contrôles ici */ }
</PanelBody>
</InspectorControls>
{ /* rendu du bloc */ }
</>
);
}
PanelBody crée une section repliable avec un titre. Sur un bloc à plusieurs familles de réglages, il vaut mieux plusieurs PanelBody distincts (« Mise en page », « Affichage », « Couleurs ») qu’un seul panneau interminable : l’utilisateur replie ce qui ne l’intéresse pas pour l’instant.
Étape 2 : ToggleControl pour les booléens
import { ToggleControl } from '@wordpress/components';
<ToggleControl
label="Afficher les prix"
checked={ attributes.showPrices }
onChange={ ( showPrices ) => setAttributes( { showPrices } ) }
/>
Le nom de la variable passée à onChange correspond directement à la nouvelle valeur du toggle : pas besoin de lire un événement DOM, @wordpress/components fait cette traduction en interne.
Étape 3 : SelectControl pour un choix fermé

import { SelectControl } from '@wordpress/components';
<SelectControl
label="Tri des produits"
value={ attributes.sortBy }
options={ [
{ label: 'Date, plus récents', value: 'date' },
{ label: 'Prix croissant', value: 'price_asc' },
{ label: 'Popularité', value: 'popularity' },
] }
onChange={ ( sortBy ) => setAttributes( { sortBy } ) }
/>
Au-delà de cinq ou six options, SelectControl reste plus adapté qu’un groupe de boutons radio, qui occuperait trop de place verticale dans un panneau déjà chargé.
Étape 4 : RangeControl pour une valeur numérique bornée
import { RangeControl } from '@wordpress/components';
<RangeControl
label="Nombre de colonnes"
value={ attributes.columns }
onChange={ ( columns ) => setAttributes( { columns } ) }
min={ 1 }
max={ 6 }
/>
RangeControl combine un curseur et un champ numérique éditable, ce qui évite à l’utilisateur de devoir viser précisément une petite poignée à la souris pour une valeur exacte.
Étape 5 : organiser plutôt qu’empiler
Un panneau de réglages se lit de haut en bas dans l’ordre où il est écrit : autant faire correspondre cet ordre à l’importance réelle des réglages pour l’utilisateur, pas à l’ordre dans lequel ils ont été codés.
- Placer en premier ce qui change visuellement le plus (ici, le nombre de colonnes).
- Regrouper les réglages d’affichage binaires (toggles) ensemble, plutôt que de les disperser entre deux panneaux.
- Réserver un
PanelBodydistinct, fermé par défaut (initialOpen={ false }), pour les réglages avancés peu utilisés.
Un piège fréquent : des valeurs par défaut absentes
Si un attribut n’a pas de valeur par défaut dans block.json, RangeControl et SelectControl peuvent afficher un état incohérent au premier chargement du bloc. Déclarer un default explicite pour chaque attribut réglé depuis l’inspecteur évite ce genre de flottement visuel dès l’insertion du bloc.
Un panneau latéral qui dépasse quatre ou cinq réglages visibles sans défilement mérite d’être redécoupé en sections repliables, même si cela demande deux
PanelBodyde plus.
Pour aller plus loin
Ces quatre contrôles couvrent l’essentiel des besoins courants, mais @wordpress/components en propose bien d’autres pour des cas plus spécifiques, comme la sélection de couleur ou la composition de listes dynamiques. Le principe reste identique dans tous les cas : chaque contrôle lit un attribut et le modifie via setAttributes, sans logique cachée entre les deux.