Sidebars (technically called “complementary areas” in Gutenberg’s architecture) are the panels that appear on the right side of the editor interface. Understanding how to detect which sidebar is open and how to control them programmatically is essential for creating advanced editor customizations.
All examples in this article are available at https://github.com/juanma-wp/sidebar-detecting-controlling-examples repo
Table of Contents
- Detecting Which Sidebar is Open
- Opening and Closing Sidebars Programmatically
- Advanced Use Cases
- Opening Specific Panels Within Sidebars
- Key Takeaways
- Related WordPress Documentation
Detecting Which Sidebar is Open
The getActiveComplementaryArea Selector
The primary way to detect which sidebar is currently active is through the getActiveComplementaryArea selector from the core/interface store (store value imported from @wordpress/interface:
/**
* WordPress dependencies
*/
import { registerPlugin } from '@wordpress/plugins';
import { __ } from '@wordpress/i18n';
import { cog } from '@wordpress/icons';
import { store as interfaceStore } from '@wordpress/interface';
import { useSelect } from '@wordpress/data';
/**
* Sidebar content component
*/
const SidebarContent = () => {
// Get the active state using the interface store
const activeSidebar = useSelect((select) => {
return select(interfaceStore).getActiveComplementaryArea("core");
}, []);
if (activeSidebar == null) {
console.log("Sidebar is inactive");
} else {
console.log(`Sidebar is active: ${activeSidebar}`);
}
return null;
};
// Register the main plugin with sidebar
registerPlugin('sidebar-log', {
render: SidebarContent,
icon: cog,
});By using useSelect we subscribe to any change in the getActiveComplementaryArea("core") value so every time the status sidebar change (is opened/closed for example) the component reacts
Console Command (run from /wp-admin/post.php?post=X&action=edit):
// Get currently active sidebar
wp.data.select('core/interface').getActiveComplementaryArea('core')
// Returns: 'edit-post/document', 'edit-post/block', null, etc.Understanding Scopes
The getActiveComplementaryArea function requires a scope parameter that identifies which editor context you’re querying:
'core'– The main unified scope for both post editor and site editor (most common)'core/edit-widgets'– Scope for the widgets editor- Custom plugin scopes – Plugins can define their own scopes like
'myplugin/custom-screen-a'
Note: The scopes
'core/edit-post'and'core/edit-site'are deprecated and automatically normalized to'core'for backward compatibility.
Possible Return Values
The function returns the identifier of the currently active complementary area, or null/undefined if no sidebar is open:
Built-in Post Editor Sidebars:
'edit-post/document'– The document settings sidebar (post title, status, categories, etc.)'edit-post/block'– The block inspector sidebar (settings for the selected block)
Site Editor Sidebars:
'edit-site/global-styles'– The global styles sidebar
Widgets Editor Sidebars:
'edit-widgets/block-areas'– The widget areas sidebar'edit-widgets/block-inspector'– The block inspector in the widgets editor
Plugin Sidebars:
- Custom identifiers like
'my-plugin/insert-image-sidebar'
No Active Sidebar:
nullorundefinedwhen no complementary area is active
Practical Example: Conditional Rendering
You can use this selector to conditionally render components based on the active sidebar:
/**
* WordPress dependencies
*/
import { registerPlugin } from '@wordpress/plugins';
import { __ } from '@wordpress/i18n';
import { cog } from '@wordpress/icons';
import { store as interfaceStore } from '@wordpress/interface';
import { useSelect } from '@wordpress/data';
/**
* Sidebar content component
*/
const SidebarContent = () => {
// Get the active state using the interface store
const { activeSidebar, isDocumentSidebarOpen } = useSelect((select) => {
const activeSidebar = select(interfaceStore).getActiveComplementaryArea("core");
const isDocumentSidebarOpen = activeSidebar === "edit-post/document";
return { activeSidebar, isDocumentSidebarOpen };
}, []);
if (isDocumentSidebarOpen) {
console.log(`The document sidebar is open: ${activeSidebar}`);
}
return null;
};
// Register the main plugin with sidebar
registerPlugin('sidebar-log', {
render: SidebarContent,
icon: cog,
});Console Commands (run from /wp-admin/post.php?post=X&action=edit):
// Check if document sidebar is open
wp.data.select('core/interface').getActiveComplementaryArea('core') === 'edit-post/document'
// Check if block inspector is open
wp.data.select('core/interface').getActiveComplementaryArea('core') === 'edit-post/block'
// Check if any sidebar is open
!!wp.data.select('core/interface').getActiveComplementaryArea('core')Opening and Closing Sidebars Programmatically
There are several ways to open sidebars programmatically in the Block Editor:
1. Direct API: enableComplementaryArea & disableComplementaryArea
The most direct method is using the enableComplementaryArea action from the core/interface store:
/**
* WordPress dependencies
*/
import { registerPlugin } from '@wordpress/plugins';
import { __ } from '@wordpress/i18n';
import { cog } from '@wordpress/icons';
import { store as interfaceStore } from '@wordpress/interface';
import { useSelect, useDispatch } from '@wordpress/data';
import { useCommand } from "@wordpress/commands";
const SidebarCommands = () => {
const { enableComplementaryArea, disableComplementaryArea } =
useDispatch(interfaceStore);
const isDocumentSidebarOpen = useSelect((select) => {
const activeSidebar =
select(interfaceStore).getActiveComplementaryArea("core");
return activeSidebar === "edit-post/document";
}, []);
// Register open command when sidebar is closed
useCommand({
name: "sidebar-log/open-document-sidebar",
label: __("Open Document Sidebar (custom)", "sidebar-log"),
icon: cog,
callback: () => {
enableComplementaryArea("core", "edit-post/document");
},
disabled: isDocumentSidebarOpen, // Disabled when sidebar is open
});
// Register close command when sidebar is open
useCommand({
name: "sidebar-log/close-document-sidebar",
label: __("Close Document Sidebar (custom)", "sidebar-log"),
icon: cog,
callback: () => disableComplementaryArea("core"),
disabled: !isDocumentSidebarOpen, // Disabled when sidebar is closed
});
return null;
};
// Register the plugin with sidebar commands
registerPlugin('sidebar-log', {
render: SidebarCommands,
icon: cog,
});Console Commands (run from /wp-admin/post.php?post=X&action=edit):
// Open document sidebar (post settings)
wp.data.dispatch('core/interface').enableComplementaryArea('core', 'edit-post/document')
// Open block inspector
wp.data.dispatch('core/interface').enableComplementaryArea('core', 'edit-post/block')2. Store-Specific Actions: openGeneralSidebar & closeGeneralSidebar
Each editor store provides convenience wrapper actions:
In the Post Editor (@wordpress/edit-post):
import { store as interfaceStore } from "@wordpress/interface";
import { useSelect, useDispatch } from "@wordpress/data";
import { useCommandLoader } from "@wordpress/commands";
import { __ } from "@wordpress/i18n";
import { useMemo } from "@wordpress/element";
const getSidebarCommandsAlt2 = () => function useSidebarCommandsAlt2({ search }) {
const { openGeneralSidebar, closeGeneralSidebar } =
useDispatch("core/edit-post");
const isDocumentSidebarOpen = useSelect((select) => {
const activeSidebar =
select(interfaceStore).getActiveComplementaryArea("core");
return activeSidebar === "edit-post/document";
}, []);
const commands = useMemo(() => {
const baseCommands = [];
if (!isDocumentSidebarOpen) {
baseCommands.push({
name: "sidebar-log/open-document-sidebar-alt",
label: __("Open Document Sidebar (custom alt2)", "sidebar-log"),
callback: () => openGeneralSidebar("edit-post/document"),
});
} else {
baseCommands.push({
name: "sidebar-log/close-document-sidebar-alt",
label: __("Close Document Sidebar (custom alt2)", "sidebar-log"),
callback: () => closeGeneralSidebar("edit-post/document"),
});
}
return baseCommands;
}, [isDocumentSidebarOpen]);
return { commands, isLoading: false };
};
const OpenCloseDocumentSidebarAlt2 = () => {
useCommandLoader({
name: "sidebar-log/commands-alt2",
hook: getSidebarCommandsAlt2(),
});
return null;
};
export default OpenCloseDocumentSidebarAlt2;
We could also run the following commands from the JS console of the browser while in the post editor
// Alternative: Using edit-post wrapper
wp.data.dispatch('core/edit-post').openGeneralSidebar('edit-post/document')
wp.data.dispatch('core/edit-post').openGeneralSidebar('edit-post/block')For the Site Editor (@wordpress/edit-site) we would do
const { openGeneralSidebar, closeGeneralSidebar } = useDispatch( 'core/edit-site' );
...
openGeneralSidebar('edit-site/global-styles'),Or run the following commands from the JS console of the browser while in the site editor
// Open global styles sidebar
wp.data.dispatch('core/edit-site').openGeneralSidebar('edit-site/global-styles')
// Open template sidebar
wp.data.dispatch('core/edit-site').openGeneralSidebar('edit-site/template')Note: These wrapper actions internally call
enableComplementaryAreaon the interface store.
Advanced Use Cases
Smart Sidebar Opening Based on Context
The following code registers a command that opens the right sidebar depending on the context:
import { useSelect, useDispatch } from "@wordpress/data";
import { useCommand } from "@wordpress/commands";
import { __ } from "@wordpress/i18n";
import { sidebar } from "@wordpress/icons";
const SmartSidebar = () => {
const { activeSidebar, hasBlockSelection } = useSelect((select) => {
const { getActiveComplementaryArea } = select("core/interface");
const { getBlockSelectionStart } = select("core/block-editor");
return {
activeSidebar: getActiveComplementaryArea("core"),
hasBlockSelection: !!getBlockSelectionStart(),
};
}, []);
const { enableComplementaryArea, disableComplementaryArea } =
useDispatch("core/interface");
const isAnySidebarOpen = ["edit-post/document", "edit-post/block"].includes(
activeSidebar
);
useCommand({
name: "sidebar-log/smart-sidebar-toggle",
label: __(
isAnySidebarOpen ? "Close (smart) Sidebar" : "Open (smart) Sidebar",
"sidebar-log"
),
icon: sidebar,
callback: () => {
if (isAnySidebarOpen) {
disableComplementaryArea("core");
} else {
const sidebarToOpen = hasBlockSelection
? "edit-post/block"
: "edit-post/document";
enableComplementaryArea("core", sidebarToOpen);
}
},
});
return null;
};
export default SmartSidebar;
From the post editor we could also run the following commands from the JS console of the browser
// Smart toggle (like Ctrl+Shift+,) - opens block inspector if block selected, otherwise document sidebar
const activeSidebar = wp.data.select('core/interface').getActiveComplementaryArea('core');
const hasBlockSelection = !!wp.data.select('core/block-editor').getBlockSelectionStart();
const isAnySidebarOpen = ['edit-post/document', 'edit-post/block'].includes(activeSidebar);
if (isAnySidebarOpen) {
wp.data.dispatch('core/interface').disableComplementaryArea('core');
} else {
const sidebarToOpen = hasBlockSelection ? 'edit-post/block' : 'edit-post/document';
wp.data.dispatch('core/interface').enableComplementaryArea('core', sidebarToOpen);
}Creating Custom Plugin Sidebars
When creating your own plugin sidebar, you’ll register it with a custom identifier using registerPlugin. You can then detect and control this sidebar using its full identifier:
import { registerPlugin } from '@wordpress/plugins';
import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/editor';
import { PanelBody } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { useCommand } from '@wordpress/commands';
import { __ } from '@wordpress/i18n';
import {image} from '@wordpress/icons';
const CustomPluginSidebar = () => {
const isOpen = useSelect((select) => {
return (
select('core/interface').getActiveComplementaryArea('core') ===
'complementary-area-toggle-demo/custom-sidebar'
);
}, []);
const { enableComplementaryArea, disableComplementaryArea } =
useDispatch('core/interface');
useCommand({
name: 'my-plugin-sidebar/toggle',
label: __(
isOpen ? 'Close Custom Sidebar' : 'Open Custom Sidebar',
'sidebar-log'
),
icon: image,
callback: () => {
if (isOpen) {
disableComplementaryArea('core');
} else {
enableComplementaryArea('core', 'complementary-area-toggle-demo/custom-sidebar');
}
},
});
return (
<>
<PluginSidebarMoreMenuItem target="custom-sidebar">
My Custom Sidebar
</PluginSidebarMoreMenuItem>
<PluginSidebar
name="custom-sidebar"
icon={image}
title="My Custom Sidebar"
>
<PanelBody>
<p>Custom sidebar content</p>
</PanelBody>
</PluginSidebar>
</>
);
};
registerPlugin("complementary-area-toggle-demo", {
render: CustomPluginSidebar,
});
Opening Specific Panels Within Sidebars
Once a sidebar is open, you may want to expand or collapse specific panels (sections) within that sidebar. The Block Editor provides dedicated actions for this purpose.
Using toggleEditorPanelOpened
The core/edit-post store provides the toggleEditorPanelOpened action to control individual panels:
import { useDispatch } from '@wordpress/data';
function PanelControls() {
const { openGeneralSidebar, toggleEditorPanelOpened } = useDispatch( 'core/edit-post' );
const openStatusPanel = () => {
// First ensure the document sidebar is open
openGeneralSidebar( 'edit-post/document' );
// Then toggle the specific panel
toggleEditorPanelOpened( 'post-status' );
};
return (
<button onClick={ openStatusPanel }>
Open Post Status Panel
</button>
);
}From the post editor we could also run the following commands from the JS console of the browser
// Get all available panels and their state
wp.data.select('core/edit-post').getPreferences()
// Check if specific panel is open (returns true/false regardless of sidebar visibility)
wp.data.select('core/edit-post').isEditorPanelOpened('post-status')
// Toggle a panel
wp.data.dispatch('core/edit-post').toggleEditorPanelOpened('post-status')Common Panel Names
Post Editor Document Sidebar Panels:
'post-status'– Status & visibility settings'taxonomy-panel-category'– Categories'taxonomy-panel-post_tag'– Tags'post-excerpt'– Post excerpt field'discussion-panel'– Allow comments and pingbacks'featured-image'– Featured image selector (if theme supports it)'page-attributes'– Template, parent, and order settings
Available panels depend on your post type, theme support, and installed plugins. Use wp.data.select('core/edit-post').getPreferences() to see all available panels in your setup.
Custom plugin panels registered via PluginDocumentSettingPanel use a custom identifier.
Ensuring a Panel is Open (Not Toggled)
Since toggleEditorPanelOpened toggles the panel state, you may want to check if it’s already open before toggling:
const { openGeneralSidebar, toggleEditorPanelOpened } = useDispatch( 'core/edit-post' );
const isPanelOpen = useSelect( ( select ) => {
return select( 'core/edit-post' ).isEditorPanelOpened( 'post-status' );
}, [] );
const ensurePanelOpen = () => {
// Open the document sidebar first
openGeneralSidebar( 'edit-post/document' );
// Only toggle if the panel is not already open
if ( ! isPanelOpen ) {
toggleEditorPanelOpened( 'post-status' );
}
};From the post editor you could also run the following commands from the JS console of the browser
// Open sidebar and ensure panel is expanded
wp.data.dispatch('core/edit-post').openGeneralSidebar('edit-post/document');
if (!wp.data.select('core/edit-post').isEditorPanelOpened('post-status')) {
wp.data.dispatch('core/edit-post').toggleEditorPanelOpened('post-status');
}// Check if panel is actually visible (sidebar open AND panel expanded)
const sidebarOpen = wp.data.select('core/interface').getActiveComplementaryArea('core') === 'edit-post/document';
const panelExpanded = wp.data.select('core/edit-post').isEditorPanelOpened('post-status');
console.log('Panel visible:', sidebarOpen && panelExpanded);isEditorPanelOpened() returns whether a panel is expanded or collapsed, not whether it’s visible. A panel can be “opened” (expanded) even when the sidebar is closed. To check actual visibility, verify both the sidebar state and panel state:
Complete Example: Opening a Sidebar and Panel
Here’s a complete example that opens a sidebar and ensures a specific panel is expanded:
/**
* WordPress dependencies
*/
import { useDispatch, useSelect } from '@wordpress/data';
import { useCommand } from '@wordpress/commands';
import { __ } from '@wordpress/i18n';
import { category } from '@wordpress/icons';
/**
* Component to open a specific panel inside a sidebar
*/
const OpenSpecificPanel = () => {
const { openGeneralSidebar, toggleEditorPanelOpened } = useDispatch( 'core/edit-post' );
const isCategoriesPanelOpen = useSelect( ( select ) => {
return select( 'core/edit-post' ).isEditorPanelOpened( 'taxonomy-panel-category' );
}, [] );
// Dynamic command that changes based on panel state
useCommand( {
name: 'complementary-area-toggle-demo/toggle-categories-panel',
label: __(
isCategoriesPanelOpen ? 'Close (specific) Categories Panel' : 'Open (specific) Categories Panel',
'complementary-area-toggle-demo'
),
icon: category,
callback: () => {
if ( ! isCategoriesPanelOpen ) {
// First ensure the document sidebar is open
openGeneralSidebar( 'edit-post/document' );
}
// Then toggle the specific panel
toggleEditorPanelOpened( 'taxonomy-panel-category' );
},
} );
return null;
};
Inserter Sidebar
For the Inserter Sidebar we can use the setIsInserterOpened dispatcher:
/**
* WordPress dependencies
*/
import { useDispatch, useSelect } from '@wordpress/data';
import { useCommand } from '@wordpress/commands';
import { __ } from '@wordpress/i18n';
import { plus } from '@wordpress/icons';
/**
* Component to toggle the block inserter
*/
const ToggleInserter = () => {
const { setIsInserterOpened } = useDispatch( 'core/edit-post' );
const isInserterOpen = useSelect( ( select ) => {
return select( 'core/edit-post' ).isInserterOpened();
}, [] );
useCommand( {
name: 'complementary-area-toggle-demo/toggle-inserter',
label: __(
isInserterOpen ? 'Close Block Inserter' : 'Open Block Inserter',
'complementary-area-toggle-demo'
),
icon: plus,
callback: () => {
setIsInserterOpened( ! isInserterOpen );
},
} );
return null;
};
export default ToggleInserter;
To select a specific tab we can pass an object to setIsInserterOpened
setIsInserterOpened({tab: "media"})From the site editor we can run from the JS Console in the browser:
// Check if inserter is open
wp.data.select('core/edit-site').isInserterOpened()
// Open/close inserter
wp.data.dispatch('core/edit-site').setIsInserterOpened(true)
wp.data.dispatch('core/edit-site').setIsInserterOpened(false)
// Toggle inserter
wp.data.dispatch('core/edit-site').setIsInserterOpened(!wp.data.select('core/edit-site').isInserterOpened())
// Close inserter and open template settings
wp.data.dispatch('core/edit-site').setIsInserterOpened(false);
wp.data.dispatch('core/edit-site').openGeneralSidebar('edit-site/template');From the post editor we can also do:
wp.data.dispatch('core/editor').setIsInserterOpened({tab: "patterns"})Key Takeaways
- Use
getActiveComplementaryArea( 'core' )to detect which sidebar is currently open - Use
enableComplementaryArea( 'core', identifier )to open a specific sidebar - Use
disableComplementaryArea( 'core' )to close any open sidebar - Use
toggleEditorPanelOpened( panelName )to expand/collapse panels within sidebars - Use
isEditorPanelOpened( panelName )to check if a panel is currently expanded (not visible) - Panel expanded state persists even when sidebar is closed – check both conditions for actual visibility
- Sidebar identifiers follow the pattern
editor-name/sidebar-name(e.g.,edit-post/document) - The scope parameter (
'core') determines which editor context the sidebar belongs to - All methods ultimately call the
core/interfacestore actions for sidebars - Always open the sidebar first before attempting to control panels within it
- Test commands in browser console using
wp.data.select()andwp.data.dispatch()for quick debugging
Understanding these patterns allows you to create sophisticated editor experiences that respond to and control both the editor’s sidebar state and the individual panels within those sidebars effectively.

Leave a Reply