diff --git a/packages/block-editor/src/components/block-navigation/branch.js b/packages/block-editor/src/components/block-navigation/branch.js
new file mode 100644
index 0000000000000..3b3b5839772d1
--- /dev/null
+++ b/packages/block-editor/src/components/block-navigation/branch.js
@@ -0,0 +1,59 @@
+/**
+ * WordPress dependencies
+ */
+import { Children, cloneElement, useContext } from '@wordpress/element';
+import { Fill, Slot } from '@wordpress/components';
+
+/**
+ * Internal dependencies
+ */
+import BlockNavigationListItem from './list-item';
+import { BlockNavigationContext } from './list';
+import { BlockListBlockContext } from '../block-list/block';
+
+const BlockNavigationBranch = ( { children, ...props } ) => {
+ const { __experimentalWithBlockNavigationSlots } = useContext(
+ BlockNavigationContext
+ );
+ if ( ! __experimentalWithBlockNavigationSlots ) {
+ return (
+
+
+ { children }
+
+ );
+ }
+
+ return (
+
+
+ { ( fills ) => {
+ if ( ! fills.length ) {
+ return ;
+ }
+
+ return Children.map( fills, ( fill ) =>
+ cloneElement( fill, {
+ ...props,
+ ...fill.props,
+ } )
+ );
+ } }
+
+ { children }
+
+ );
+};
+
+export default BlockNavigationBranch;
+
+const listItemSlotName = ( blockId ) => `BlockNavigationList-item-${ blockId }`;
+
+export const BlockNavigationListItemSlot = ( { blockId, ...props } ) => (
+
+);
+
+export const BlockNavigationListItemFill = ( props ) => {
+ const { clientId } = useContext( BlockListBlockContext );
+ return ;
+};
diff --git a/packages/block-editor/src/components/block-navigation/dropdown.js b/packages/block-editor/src/components/block-navigation/dropdown.js
index b230aac4236ad..ba0e824c3667c 100644
--- a/packages/block-editor/src/components/block-navigation/dropdown.js
+++ b/packages/block-editor/src/components/block-navigation/dropdown.js
@@ -53,7 +53,10 @@ function BlockNavigationDropdownToggle( { isEnabled, onToggle, isOpen } ) {
);
}
-function BlockNavigationDropdown( { isDisabled } ) {
+function BlockNavigationDropdown( {
+ isDisabled,
+ __experimentalWithBlockNavigationSlots,
+} ) {
const hasBlocks = useSelect(
( select ) => !! select( 'core/block-editor' ).getBlockCount(),
[]
@@ -71,7 +74,12 @@ function BlockNavigationDropdown( { isDisabled } ) {
/>
) }
renderContent={ ( { onClose } ) => (
-
+
) }
/>
);
diff --git a/packages/block-editor/src/components/block-navigation/index.js b/packages/block-editor/src/components/block-navigation/index.js
index 4d25ffda1bb01..cd00328440c6e 100644
--- a/packages/block-editor/src/components/block-navigation/index.js
+++ b/packages/block-editor/src/components/block-navigation/index.js
@@ -21,6 +21,7 @@ function BlockNavigation( {
rootBlocks,
selectedBlockClientId,
selectBlock,
+ __experimentalWithBlockNavigationSlots,
} ) {
if ( ! rootBlocks || rootBlocks.length === 0 ) {
return null;
@@ -44,6 +45,9 @@ function BlockNavigation( {
blocks={ [ rootBlock ] }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
+ __experimentalWithBlockNavigationSlots={
+ __experimentalWithBlockNavigationSlots
+ }
showNestedBlocks
/>
) }
@@ -52,6 +56,9 @@ function BlockNavigation( {
blocks={ rootBlocks }
selectedBlockClientId={ selectedBlockClientId }
selectBlock={ selectBlock }
+ __experimentalWithBlockNavigationSlots={
+ __experimentalWithBlockNavigationSlots
+ }
/>
) }
diff --git a/packages/block-editor/src/components/block-navigation/list-item.js b/packages/block-editor/src/components/block-navigation/list-item.js
new file mode 100644
index 0000000000000..965f2d648e8b0
--- /dev/null
+++ b/packages/block-editor/src/components/block-navigation/list-item.js
@@ -0,0 +1,58 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { Button, VisuallyHidden } from '@wordpress/components';
+import {
+ __experimentalGetBlockLabel as getBlockLabel,
+ getBlockType,
+} from '@wordpress/blocks';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import BlockIcon from '../block-icon';
+
+export default function BlockNavigationListItem( {
+ block,
+ onClick,
+ isSelected,
+ wrapperComponent: WrapperComponent,
+ children,
+} ) {
+ const blockType = getBlockType( block.name );
+
+ return (
+
+
+
+ { children
+ ? children
+ : getBlockLabel( blockType, block.attributes ) }
+ { isSelected && (
+
+ { __( '(selected block)' ) }
+
+ ) }
+
+
+ );
+}
+
+BlockNavigationListItem.defaultProps = {
+ onClick: () => {},
+ wrapperComponent: ( props ) => ,
+};
diff --git a/packages/block-editor/src/components/block-navigation/list.js b/packages/block-editor/src/components/block-navigation/list.js
index 55a1b28848b9d..c8228aba8f32f 100644
--- a/packages/block-editor/src/components/block-navigation/list.js
+++ b/packages/block-editor/src/components/block-navigation/list.js
@@ -2,25 +2,23 @@
* External dependencies
*/
import { isNil, map, omitBy } from 'lodash';
-import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { Button, VisuallyHidden } from '@wordpress/components';
-import {
- __experimentalGetBlockLabel as getBlockLabel,
- getBlockType,
-} from '@wordpress/blocks';
-import { __ } from '@wordpress/i18n';
+import { useMemo, createContext } from '@wordpress/element';
/**
* Internal dependencies
*/
-import BlockIcon from '../block-icon';
import ButtonBlockAppender from '../button-block-appender';
+import BlockNavigationBranch from './branch';
-export default function BlockNavigationList( {
+export const BlockNavigationContext = createContext( {
+ __experimentalWithBlockNavigationSlots: false,
+} );
+
+function BlockNavigationList( {
blocks,
selectedBlockClientId,
selectBlock,
@@ -40,30 +38,14 @@ export default function BlockNavigationList( {
/* eslint-disable jsx-a11y/no-redundant-roles */