diff --git a/lib/blocks.php b/lib/blocks.php
index b92a656513714..68950a66b94fa 100644
--- a/lib/blocks.php
+++ b/lib/blocks.php
@@ -33,6 +33,7 @@ function gutenberg_reregister_core_block_types() {
'missing',
'more',
'navigation-link',
+ 'navigation-link-list',
'nextpage',
'paragraph',
'preformatted',
@@ -61,6 +62,7 @@ function gutenberg_reregister_core_block_types() {
'navigation.php' => 'core/navigation',
'navigation-link.php' => 'core/navigation-link',
'home-link.php' => 'core/home-link',
+ 'navigation-link-list.php' => 'core/navigation-link-list',
'rss.php' => 'core/rss',
'search.php' => 'core/search',
'shortcode.php' => 'core/shortcode',
diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js
index a4ec8243c4e74..5961016bdcf51 100644
--- a/packages/block-library/src/index.js
+++ b/packages/block-library/src/index.js
@@ -35,6 +35,7 @@ import * as html from './html';
import * as mediaText from './media-text';
import * as navigation from './navigation';
import * as navigationLink from './navigation-link';
+import * as navigationLinkList from './navigation-link-list';
import * as homeLink from './home-link';
import * as latestComments from './latest-comments';
import * as latestPosts from './latest-posts';
@@ -234,6 +235,7 @@ export const __experimentalRegisterExperimentalCoreBlocks =
[
navigation,
navigationLink,
+ navigationLinkList,
homeLink,
// Register Legacy Widget block.
diff --git a/packages/block-library/src/navigation-link-list/block.json b/packages/block-library/src/navigation-link-list/block.json
new file mode 100644
index 0000000000000..b2003841b9880
--- /dev/null
+++ b/packages/block-library/src/navigation-link-list/block.json
@@ -0,0 +1,12 @@
+{
+ "apiVersion": 2,
+ "name": "core/navigation-link-list",
+ "category": "design",
+ "parent": [ "core/navigation" ],
+ "supports": {
+ "reusable": false,
+ "html": false
+ },
+ "editorStyle": "wp-block-navigation-link-list-editor",
+ "style": "wp-block-navigation-link-list"
+}
diff --git a/packages/block-library/src/navigation-link-list/edit.js b/packages/block-library/src/navigation-link-list/edit.js
new file mode 100644
index 0000000000000..4f476fbb65ad5
--- /dev/null
+++ b/packages/block-library/src/navigation-link-list/edit.js
@@ -0,0 +1,68 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ InnerBlocks,
+ BlockControls,
+ InspectorControls,
+ useBlockProps,
+ __experimentalUseInnerBlocksProps as useInnerBlocksProps,
+ store as blockEditorStore,
+} from '@wordpress/block-editor';
+import { useSelect } from '@wordpress/data';
+
+const ALLOWED_BLOCKS = [ 'core/navigation-link', 'core/spacer' ];
+
+export default function NavigationLinksEdit( { clientId, isSelected } ) {
+ const {
+ isImmediateParentOfSelectedBlock,
+ selectedBlockHasDescendants,
+ } = useSelect(
+ ( select ) => {
+ const {
+ getClientIdsOfDescendants,
+ hasSelectedInnerBlock,
+ getSelectedBlockClientId,
+ } = select( blockEditorStore );
+ const selectedBlockId = getSelectedBlockClientId();
+ return {
+ isImmediateParentOfSelectedBlock: hasSelectedInnerBlock(
+ clientId,
+ false
+ ),
+ selectedBlockHasDescendants: !! getClientIdsOfDescendants( [
+ selectedBlockId,
+ ] )?.length,
+ };
+ },
+ [ clientId ]
+ );
+
+ const blockProps = useBlockProps( {
+ className: 'wp-block-navigation__container',
+ } );
+
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
+ allowedBlocks: ALLOWED_BLOCKS,
+ renderAppender:
+ ( isImmediateParentOfSelectedBlock &&
+ ! selectedBlockHasDescendants ) ||
+ isSelected
+ ? InnerBlocks.DefaultAppender
+ : false,
+ __experimentalAppenderTagName: 'li',
+ __experimentalCaptureToolbars: true,
+ __experimentalLayout: {
+ type: 'default',
+ alignments: [],
+ },
+ } );
+
+ return (
+ <>
+