Un inspecteur de bloc qui empile quinze contrôles à la suite, sans structure visible, devient rapidement plus difficile à parcourir qu’à utiliser : le rédacteur doit faire défiler l’ensemble pour retrouver un seul réglage, même familier. Passé une dizaine de contrôles, ranger l’inspecteur en sections dépliables change concrètement l’expérience d’édition, sans toucher à la logique métier du bloc.
Le composant PanelBody, brique de base du rangement
Fourni par @wordpress/components, PanelBody enveloppe un groupe de contrôles sous un intitulé cliquable, qui se replie et se déplie indépendamment des autres panneaux du même inspecteur. Plusieurs instances de PanelBody peuvent cohabiter dans un même InspectorControls, chacune correspondant à une catégorie logique de réglages : apparence, comportement, accessibilité, données liées.
Mise en place étape par étape

- Identifier les groupes logiques de réglages du bloc (au moins deux ou trois catégories distinctes justifient l’usage de panneaux séparés).
- Importer
PanelBodydepuis@wordpress/components, en plus des contrôles déjà utilisés. - Envelopper chaque groupe de contrôles dans son propre
PanelBody, avec untitleexplicite. - Décider, panneau par panneau, si
initialOpendoit valoirtrue(pour les réglages les plus fréquemment consultés) oufalse. - Vérifier dans l’éditeur que l’ouverture d’un panneau ne referme pas les autres involontairement (ce n’est normalement pas le comportement par défaut).
Prenons un bloc « Carte de tarif » dont l’inspecteur accumule les réglages : contenu, mise en avant, apparence. Voici d’abord les attributs déclarés dans block.json :
{
"apiVersion": 3,
"name": "tarifs/carte",
"title": "Carte de tarif",
"category": "widgets",
"attributes": {
"titre": { "type": "string", "default": "" },
"prix": { "type": "string", "default": "" },
"periode": { "type": "string", "default": "mois" },
"mettreEnAvant": { "type": "boolean", "default": false },
"libelleBadge": { "type": "string", "default": "Recommandé" },
"rayon": { "type": "number", "default": 8 }
},
"editorScript": "file:./index.js"
}
Et voici la fonction d’édition, avec trois panneaux : le premier, ouvert au chargement, contient les réglages de contenu ; les deux autres sont repliés.
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import {
PanelBody,
TextControl,
ToggleControl,
SelectControl,
RangeControl,
} from '@wordpress/components';
export default function Edit( { attributes, setAttributes } ) {
const { titre, prix, periode, mettreEnAvant, libelleBadge, rayon } = attributes;
const blockProps = useBlockProps( { style: { borderRadius: rayon } } );
return (
<>
<InspectorControls>
<PanelBody title={ __( 'Contenu', 'tarifs' ) } initialOpen={ true }>
<TextControl
label={ __( 'Titre', 'tarifs' ) }
value={ titre }
onChange={ ( valeur ) => setAttributes( { titre: valeur } ) }
/>
<TextControl
label={ __( 'Prix', 'tarifs' ) }
value={ prix }
onChange={ ( valeur ) => setAttributes( { prix: valeur } ) }
/>
<SelectControl
label={ __( 'Période', 'tarifs' ) }
value={ periode }
options={ [
{ label: __( 'Par mois', 'tarifs' ), value: 'mois' },
{ label: __( 'Par an', 'tarifs' ), value: 'an' },
] }
onChange={ ( valeur ) => setAttributes( { periode: valeur } ) }
/>
</PanelBody>
<PanelBody title={ __( 'Mise en avant', 'tarifs' ) } initialOpen={ false }>
<ToggleControl
label={ __( 'Afficher un badge', 'tarifs' ) }
checked={ mettreEnAvant }
onChange={ ( valeur ) => setAttributes( { mettreEnAvant: valeur } ) }
/>
{ mettreEnAvant && (
<TextControl
label={ __( 'Texte du badge', 'tarifs' ) }
value={ libelleBadge }
onChange={ ( valeur ) => setAttributes( { libelleBadge: valeur } ) }
/>
) }
</PanelBody>
<PanelBody title={ __( 'Apparence', 'tarifs' ) } initialOpen={ false }>
<RangeControl
label={ __( 'Arrondi des angles', 'tarifs' ) }
value={ rayon }
min={ 0 }
max={ 32 }
onChange={ ( valeur ) => setAttributes( { rayon: valeur } ) }
/>
</PanelBody>
</InspectorControls>
<div { ...blockProps }>
<strong>{ titre }</strong> { prix }
</div>
</>
);
}
Le découpage suit la logique de l’usage, pas celle du code : ce que le rédacteur modifie à chaque fois (titre, prix) est dans le panneau ouvert ; ce qu’il règle une fois pour toutes (angles arrondis) est dans un panneau replié. Le panneau « Mise en avant » ne montre le champ du badge que si l’option est activée, ce qui évite d’afficher un réglage sans effet.
Un seul panneau ouvert à la fois
Par défaut, les panneaux sont indépendants : en ouvrir un ne referme pas les autres. Si votre inspecteur compte beaucoup de sections, on peut obtenir un comportement d’accordéon en pilotant l’état soi-même. La propriété opened rend le panneau contrôlé, et onToggle est appelée à chaque clic sur son intitulé :
import { useState } from '@wordpress/element';
const [ panneauOuvert, setPanneauOuvert ] = useState( 'contenu' );
const basculer = ( identifiant ) => () =>
setPanneauOuvert( panneauOuvert === identifiant ? null : identifiant );
// ...
<PanelBody
title={ __( 'Apparence', 'tarifs' ) }
opened={ panneauOuvert === 'apparence' }
onToggle={ basculer( 'apparence' ) }
>
{ /* contrôles */ }
</PanelBody>
Ce code remplace initialOpen : dès qu’un panneau reçoit opened, il est entièrement piloté par votre état, et initialOpen n’a plus d’objet. L’appel à useState() se place en tête de la fonction d’édition, avant le return. Cet accordéon n’est pas toujours souhaitable : un rédacteur qui compare deux réglages situés dans deux panneaux doit pouvoir garder les deux ouverts.
Choisir ce qui s’ouvre et dans quel ordre
- Ouvrez au chargement un seul panneau, celui des réglages les plus fréquents ; laisser les autres repliés donne un inspecteur lisible dès la sélection du bloc.
- Placez les panneaux dans l’ordre d’usage : contenu, puis comportement, puis apparence, puis réglages avancés.
- Donnez à chaque panneau un intitulé qui décrit ce qu’il contient, pas une catégorie vague comme « Options » ou « Divers ».
- Ne créez pas de panneau pour un contrôle isolé : un panneau de deux ou trois contrôles au minimum a du sens.
Pièges courants
- Un panneau vide. Si tous ses contrôles sont conditionnels, le panneau reste affiché avec son intitulé et rien dedans. Rendez plutôt conditionnel le
PanelBodyentier. - Des
PanelBodyimbriqués. Ils produisent une interface déroutante et n’apportent rien que deux panneaux côte à côte ne donnent déjà. - Un intitulé non traduit. Le
titlepasse par__()comme n’importe quelle chaîne visible. - Les panneaux hors de
InspectorControls. Hors de ce composant, ils s’affichent dans le canevas de l’éditeur, et non dans la barre latérale. - Les onglets de l’inspecteur. Dans les versions récentes de WordPress, l’inspecteur propose des onglets Réglages et Styles ;
InspectorControlsaccepte alors une propriétégrouppour placer un panneau d’apparence dans l’onglet des styles. Vérifiez la prise en charge dans la version minimale que vous visez.
Un inspecteur bien rangé ne montre pas tous les réglages : il montre les bons au bon moment, et laisse les autres à un clic.
Conclusion
PanelBody est un composant modeste qui change beaucoup l’expérience d’un bloc complexe : les réglages sont regroupés par intention, l’ouverture initiale oriente le regard, et rien dans la logique du bloc ne change puisque les attributs restent les mêmes. Commencez par regrouper vos contrôles en deux ou trois panneaux, laissez ouvert celui du quotidien, et testez l’inspecteur avec quelqu’un qui n’a pas conçu le bloc : c’est la meilleure mesure de sa lisibilité.