diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index 0e0de9d4f8a507..6d5dedbeb74c4a 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -8,6 +8,51 @@ This page lists the blocks included in the block-library package.
+## Accordion Group
+
+A group of headers and associated expandable content. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/accordion-group))
+
+- **Name:** core/accordion-group
+- **Experimental:** true
+- **Category:** design
+- **Allowed Blocks:** core/accordion-item
+- **Supports:** align (full, wide), background (backgroundImage, backgroundSize), color (background, gradient, text), interactivity, layout, shadow, spacing (blockGap, margin, padding), ~~html~~
+- **Attributes:** allowedBlocks, autoclose, iconPosition
+
+## Accordion Header
+
+Accordion header. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/accordion-header))
+
+- **Name:** core/accordion-header
+- **Experimental:** true
+- **Category:** design
+- **Parent:** core/accordion-item
+- **Supports:** anchor, border, color (background, gradient, text), interactivity, layout, shadow, spacing (margin, padding), typography (fontSize, textAlign), ~~align~~
+- **Attributes:** icon, iconPosition, level, levelOptions, openByDefault, textAlignment, title
+
+## Accordion
+
+A single accordion that displays a header and expandable content. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/accordion-item))
+
+- **Name:** core/accordion-item
+- **Experimental:** true
+- **Category:** design
+- **Parent:** core/accordion-group
+- **Allowed Blocks:** core/accordion-header, core/accordion-panel
+- **Supports:** align (full, wide), color (background, gradient, text), interactivity, layout, shadow, spacing (blockGap, margin)
+- **Attributes:** openByDefault
+
+## Accordion Panel
+
+Accordion Panel ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/accordion-panel))
+
+- **Name:** core/accordion-panel
+- **Experimental:** true
+- **Category:** design
+- **Parent:** core/accordion-item
+- **Supports:** border, color (background, gradient, text), interactivity, layout, shadow, spacing (blockGap, margin, padding), typography (fontSize, lineHeight)
+- **Attributes:** allowedBlocks, isSelected, openByDefault, templateLock
+
## Archives
Display a date archive of your posts. ([Source](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src/archives))
diff --git a/lib/blocks.php b/lib/blocks.php
index c3fdb26700c58c..e5f2d0620172b8 100644
--- a/lib/blocks.php
+++ b/lib/blocks.php
@@ -14,6 +14,8 @@ function gutenberg_reregister_core_block_types() {
$blocks_dirs = array(
__DIR__ . '/../build/block-library/blocks/' => array(
'block_folders' => array(
+ 'accordion-header',
+ 'accordion-panel',
'audio',
'button',
'buttons',
@@ -45,6 +47,8 @@ function gutenberg_reregister_core_block_types() {
'embed',
),
'block_names' => array(
+ 'accordion-item.php' => 'core/accordion-item',
+ 'accordion-group.php' => 'core/accordion-group',
'archives.php' => 'core/archives',
'avatar.php' => 'core/avatar',
'block.php' => 'core/block',
diff --git a/lib/experimental/editor-settings.php b/lib/experimental/editor-settings.php
index 919be2e6e34a45..c6bd99a18bf4c7 100644
--- a/lib/experimental/editor-settings.php
+++ b/lib/experimental/editor-settings.php
@@ -28,15 +28,18 @@ function gutenberg_enable_experiments() {
if ( gutenberg_is_experiment_enabled( 'gutenberg-full-page-client-side-navigation' ) ) {
wp_add_inline_script( 'wp-block-library', 'window.__experimentalFullPageClientSideNavigation = true', 'before' );
}
+ if ( $gutenberg_experiments && array_key_exists( 'gutenberg-zoomed-out-patterns-tab', $gutenberg_experiments ) ) {
+ wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableZoomedOutPatternsTab = true', 'before' );
+ }
if ( $gutenberg_experiments && array_key_exists( 'gutenberg-quick-edit-dataviews', $gutenberg_experiments ) ) {
wp_add_inline_script( 'wp-block-editor', 'window.__experimentalQuickEditDataViews = true', 'before' );
}
+ if ( $gutenberg_experiments && array_key_exists( 'gutenberg-block-bindings-ui', $gutenberg_experiments ) ) {
+ wp_add_inline_script( 'wp-block-editor', 'window.__experimentalBlockBindingsUI = true', 'before' );
+ }
if ( $gutenberg_experiments && array_key_exists( 'gutenberg-media-processing', $gutenberg_experiments ) ) {
wp_add_inline_script( 'wp-block-editor', 'window.__experimentalMediaProcessing = true', 'before' );
}
- if ( $gutenberg_experiments && array_key_exists( 'gutenberg-zoom-out-experiment', $gutenberg_experiments ) ) {
- wp_add_inline_script( 'wp-block-editor', 'window.__experimentalEnableZoomOutExperiment = true', 'before' );
- }
}
add_action( 'admin_init', 'gutenberg_enable_experiments' );
diff --git a/packages/block-library/package.json b/packages/block-library/package.json
index 1353ef24c77d89..10d8e34e100ca5 100644
--- a/packages/block-library/package.json
+++ b/packages/block-library/package.json
@@ -31,6 +31,7 @@
"{src,build,build-module}/*/init.js"
],
"wpScriptModuleExports": {
+ "./accordion-group/view": "./build-module/accordion-group/view.js",
"./file/view": "./build-module/file/view.js",
"./image/view": "./build-module/image/view.js",
"./navigation/view": "./build-module/navigation/view.js",
diff --git a/packages/block-library/src/accordion-group/block.json b/packages/block-library/src/accordion-group/block.json
new file mode 100644
index 00000000000000..572ad2a7afd30c
--- /dev/null
+++ b/packages/block-library/src/accordion-group/block.json
@@ -0,0 +1,61 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "core/accordion-group",
+ "title": "Accordion Group",
+ "category": "design",
+ "description": "A group of headers and associated expandable content.",
+ "example": {},
+ "__experimental": true,
+ "supports": {
+ "html": false,
+ "align": [ "wide", "full" ],
+ "background": {
+ "backgroundImage": true,
+ "backgroundSize": true,
+ "__experimentalDefaultControls": {
+ "backgroundImage": true
+ }
+ },
+ "color": {
+ "background": true,
+ "gradient": true
+ },
+ "__experimentalBorder": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true,
+ "__experimentalDefaultControls": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true
+ }
+ },
+ "spacing": {
+ "padding": true,
+ "margin": [ "top", "bottom" ],
+ "blockGap": true
+ },
+ "shadow": true,
+ "layout": true,
+ "interactivity": true
+ },
+ "attributes": {
+ "iconPosition": {
+ "type": "string",
+ "default": "right"
+ },
+ "autoclose": {
+ "type": "boolean",
+ "default": false
+ },
+ "allowedBlocks": {
+ "type": "array"
+ }
+ },
+ "allowedBlocks": [ "core/accordion-item" ],
+ "textdomain": "default",
+ "style": "wp-block-accordion-group"
+}
diff --git a/packages/block-library/src/accordion-group/edit.js b/packages/block-library/src/accordion-group/edit.js
new file mode 100644
index 00000000000000..96b1ba59622633
--- /dev/null
+++ b/packages/block-library/src/accordion-group/edit.js
@@ -0,0 +1,49 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ useBlockProps,
+ useInnerBlocksProps,
+ InspectorControls,
+} from '@wordpress/block-editor';
+import { __ } from '@wordpress/i18n';
+import { PanelBody, ToggleControl } from '@wordpress/components';
+
+const ACCORDION_BLOCK_NAME = 'core/accordion-item';
+const ACCORDION_BLOCK = {
+ name: ACCORDION_BLOCK_NAME,
+};
+
+export default function Edit( { attributes: { autoclose }, setAttributes } ) {
+ const blockProps = useBlockProps();
+
+ const innerBlocksProps = useInnerBlocksProps( blockProps, {
+ template: [ [ ACCORDION_BLOCK_NAME ], [ ACCORDION_BLOCK_NAME ] ],
+ defaultBlock: ACCORDION_BLOCK,
+ directInsert: true,
+ } );
+
+ return (
+ <>
+
+
+ {
+ setAttributes( {
+ autoclose: value,
+ } );
+ } }
+ checked={ autoclose }
+ help={ __(
+ 'Automatically close accordions when a new one is opened.'
+ ) }
+ />
+
+
+
+ >
+ );
+}
diff --git a/packages/block-library/src/accordion-group/index.js b/packages/block-library/src/accordion-group/index.js
new file mode 100644
index 00000000000000..37230fe7d30cd5
--- /dev/null
+++ b/packages/block-library/src/accordion-group/index.js
@@ -0,0 +1,49 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import edit from './edit';
+import save from './save';
+import metadata from './block.json';
+import initBlock from '../utils/init-block';
+
+const icon = (
+
+);
+
+const { name } = metadata;
+
+export { metadata, name };
+
+export const settings = {
+ icon,
+ example: {},
+ edit,
+ save,
+};
+
+export const init = () => initBlock( { name, metadata, settings } );
diff --git a/packages/block-library/src/accordion-group/index.php b/packages/block-library/src/accordion-group/index.php
new file mode 100644
index 00000000000000..281d5b873f1e70
--- /dev/null
+++ b/packages/block-library/src/accordion-group/index.php
@@ -0,0 +1,59 @@
+next_tag( array( 'class_name' => 'wp-block-accordion-group' ) ) ) {
+ $p->set_attribute( 'data-wp-interactive', 'core/accordion' );
+ $p->set_attribute( 'data-wp-context', '{ "autoclose": ' . $autoclose . ', "isOpen": [] }' );
+
+ // Only modify content if directives have been set.
+ $content = $p->get_updated_html();
+ }
+
+ return $content;
+}
+
+/**
+ * Registers the `core/accordion-group` block on server.
+ *
+ * @since 6.6.0
+ */
+function register_block_core_accordion_group() {
+ register_block_type_from_metadata(
+ __DIR__ . '/accordion-group',
+ array(
+ 'render_callback' => 'render_block_core_accordion_group',
+ )
+ );
+}
+add_action( 'init', 'register_block_core_accordion_group' );
diff --git a/packages/block-library/src/accordion-group/init.js b/packages/block-library/src/accordion-group/init.js
new file mode 100644
index 00000000000000..79f0492c2cb2f8
--- /dev/null
+++ b/packages/block-library/src/accordion-group/init.js
@@ -0,0 +1,6 @@
+/**
+ * Internal dependencies
+ */
+import { init } from './';
+
+export default init();
diff --git a/packages/block-library/src/accordion-group/save.js b/packages/block-library/src/accordion-group/save.js
new file mode 100644
index 00000000000000..2b03d9bbcd0878
--- /dev/null
+++ b/packages/block-library/src/accordion-group/save.js
@@ -0,0 +1,23 @@
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+/**
+ * WordPress dependencies
+ */
+import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
+
+export default function save( { attributes } ) {
+ const { iconPosition } = attributes;
+ const blockProps = useBlockProps.save();
+ const className = clsx(
+ {
+ 'icon-position-left': iconPosition === 'left',
+ },
+ blockProps.className
+ );
+
+ return (
+
+ );
+}
diff --git a/packages/block-library/src/accordion-group/style.scss b/packages/block-library/src/accordion-group/style.scss
new file mode 100644
index 00000000000000..b7aa3c9185cb51
--- /dev/null
+++ b/packages/block-library/src/accordion-group/style.scss
@@ -0,0 +1,94 @@
+.wp-block-accordion-item {
+ display: grid;
+ grid-template-rows: max-content 0fr;
+}
+
+.wp-block-accordion-item.is-open {
+ grid-template-rows: max-content 1fr;
+}
+
+.wp-block-accordion-item .accordion-item__heading {
+ color: inherit;
+ padding: 0;
+ margin: 0;
+}
+
+.accordion-item__toggle {
+ font-family: inherit;
+ font-size: inherit;
+ font-weight: inherit;
+ line-height: inherit;
+ letter-spacing: inherit;
+ text-transform: inherit;
+ text-decoration: inherit;
+ word-spacing: inherit;
+ background: none;
+ border: none;
+ color: inherit;
+ padding: var(--wp--preset--spacing--20, 1em) 0;
+ cursor: pointer;
+ outline: none;
+ display: flex;
+ align-items: center;
+ text-align: inherit;
+ position: relative;
+ width: 100%;
+}
+
+.accordion-item__toggle > span {
+ width: 100%;
+}
+
+.is-layout-flow > .wp-block-accordion-panel,
+.wp-block-accordion-panel {
+ overflow: hidden;
+ margin: 0;
+}
+
+.accordion-panel__wrapper {
+ padding-bottom: var(--wp--preset--spacing--20, 1em);
+}
+
+/* No icon block style */
+.is-style-no-icon .accordion-item__toggle-icon {
+ background-color: unset;
+}
+
+.wp-block-accordion-header.icon-position-left .accordion-item__toggle {
+ /* stylelint-disable-next-line declaration-property-value-allowed-list -- This should be refactored to not use the row-reverse value. */
+ flex-direction: row-reverse;
+}
+
+.accordion-item__toggle:focus-visible {
+ outline: 2px solid -webkit-focus-ring-color;
+ outline-offset: 2px;
+}
+
+/* Add transitions only for users who do not prefer reduced motion */
+@media (prefers-reduced-motion: no-preference) {
+ .wp-block-accordion-item .accordion-item__toggle-icon {
+ transition: transform 0.2s ease-in-out;
+ }
+
+ .wp-block-accordion-item {
+ transition: grid-template-rows 0.3s ease-out;
+ }
+}
+
+.is-open {
+ .accordion-item__toggle-icon.has-icon-plus {
+ transform: rotate(45deg);
+ }
+ .accordion-item__toggle-icon.has-icon-chevron {
+ transform: rotate(-180deg);
+ }
+ .accordion-item__toggle-icon.has-icon-circlePlus {
+ transform: rotate(45deg);
+ }
+ .accordion-item__toggle-icon.has-icon-caret {
+ transform: rotate(-180deg);
+ }
+ .accordion-item__toggle-icon.has-icon-chevronRight {
+ transform: rotate(90deg);
+ }
+}
diff --git a/packages/block-library/src/accordion-group/view.js b/packages/block-library/src/accordion-group/view.js
new file mode 100644
index 00000000000000..cf1639710bdd33
--- /dev/null
+++ b/packages/block-library/src/accordion-group/view.js
@@ -0,0 +1,38 @@
+/**
+ * WordPress dependencies
+ */
+import { store, getContext } from '@wordpress/interactivity';
+
+const { state } = store( 'core/accordion', {
+ state: {
+ get isOpen() {
+ const { isOpen, id } = getContext();
+ return isOpen.includes( id );
+ },
+ },
+ actions: {
+ toggle: () => {
+ const context = getContext();
+ const { id, autoclose } = context;
+
+ if ( autoclose ) {
+ context.isOpen = state.isOpen ? [] : [ id ];
+ } else if ( state.isOpen ) {
+ context.isOpen = context.isOpen.filter(
+ ( item ) => item !== id
+ );
+ } else {
+ context.isOpen.push( id );
+ }
+ },
+ },
+ callbacks: {
+ initIsOpen: () => {
+ const context = getContext();
+ const { id, openByDefault } = context;
+ if ( openByDefault ) {
+ context.isOpen.push( id );
+ }
+ },
+ },
+} );
diff --git a/packages/block-library/src/accordion-header/block.json b/packages/block-library/src/accordion-header/block.json
new file mode 100644
index 00000000000000..6173e356dca9e0
--- /dev/null
+++ b/packages/block-library/src/accordion-header/block.json
@@ -0,0 +1,98 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "core/accordion-header",
+ "version": "0.1.0",
+ "title": "Accordion Header",
+ "category": "design",
+ "description": "Accordion header.",
+ "example": {},
+ "__experimental": true,
+ "parent": [ "core/accordion-item" ],
+ "supports": {
+ "anchor": true,
+ "color": {
+ "background": true,
+ "gradient": true
+ },
+ "align": false,
+ "border": true,
+ "interactivity": true,
+ "spacing": {
+ "padding": true,
+ "margin": [ "top", "bottom" ],
+ "__experimentalDefaultControls": {
+ "padding": true,
+ "margin": true
+ }
+ },
+ "__experimentalBorder": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true,
+ "__experimentalDefaultControls": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true
+ }
+ },
+ "typography": {
+ "textAlign": true,
+ "fontSize": true,
+ "__experimentalFontFamily": true,
+ "__experimentalFontWeight": true,
+ "__experimentalFontStyle": true,
+ "__experimentalTextTransform": true,
+ "__experimentalTextDecoration": true,
+ "__experimentalLetterSpacing": true,
+ "__experimentalDefaultControls": {
+ "fontSize": true,
+ "fontFamily": true
+ }
+ },
+ "shadow": true,
+ "layout": true
+ },
+ "attributes": {
+ "openByDefault": {
+ "type": "boolean",
+ "default": false
+ },
+ "title": {
+ "type": "rich-text",
+ "source": "rich-text",
+ "selector": "span"
+ },
+ "level": {
+ "type": "number",
+ "default": 3
+ },
+ "levelOptions": {
+ "type": "array"
+ },
+ "textAlignment": {
+ "type": "string",
+ "default": "left"
+ },
+ "icon": {
+ "type": [ "string", "boolean" ],
+ "enum": [
+ "plus",
+ "chevron",
+ "chevronRight",
+ "caret",
+ "circlePlus",
+ false
+ ],
+ "default": "plus"
+ },
+ "iconPosition": {
+ "type": "string",
+ "enum": [ "left", "right" ],
+ "default": "right"
+ }
+ },
+ "textdomain": "default"
+}
diff --git a/packages/block-library/src/accordion-header/edit.js b/packages/block-library/src/accordion-header/edit.js
new file mode 100644
index 00000000000000..e8cc9cbc526489
--- /dev/null
+++ b/packages/block-library/src/accordion-header/edit.js
@@ -0,0 +1,185 @@
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import {
+ useBlockProps,
+ __experimentalUseBorderProps as useBorderProps,
+ __experimentalUseColorProps as useColorProps,
+ __experimentalGetSpacingClassesAndStyles as useSpacingProps,
+ __experimentalGetShadowClassesAndStyles as useShadowProps,
+ BlockControls,
+ HeadingLevelDropdown,
+ RichText,
+ InspectorControls,
+} from '@wordpress/block-editor';
+import {
+ PanelBody,
+ ToolbarGroup,
+ __experimentalToggleGroupControl as ToggleGroupControl,
+ __experimentalToggleGroupControlOption as ToggleGroupControlOption,
+ __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon,
+} from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import {
+ caret,
+ chevron,
+ chevronRight,
+ circlePlus,
+ plus,
+} from '../accordion-item/icons';
+
+const ICONS = {
+ plus,
+ circlePlus,
+ chevron,
+ chevronRight,
+ caret,
+};
+
+export default function Edit( { attributes, setAttributes } ) {
+ const { level, title, textAlign, icon, iconPosition, levelOptions } =
+ attributes;
+ const TagName = 'h' + level;
+
+ const blockProps = useBlockProps();
+ const borderProps = useBorderProps( attributes );
+ const colorProps = useColorProps( attributes );
+ const spacingProps = useSpacingProps( attributes );
+ const shadowProps = useShadowProps( attributes );
+
+ const Icon = ICONS[ icon ];
+
+ return (
+ <>
+
+
+
+ setAttributes( { level: newLevel } )
+ }
+ />
+
+
+
+
+
+ setAttributes( { icon: value } )
+ }
+ >
+
+
+
+
+
+
+
+ {
+ setAttributes( { iconPosition: value } );
+ } }
+ >
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/packages/block-library/src/accordion-header/index.js b/packages/block-library/src/accordion-header/index.js
new file mode 100644
index 00000000000000..5858f025c228dd
--- /dev/null
+++ b/packages/block-library/src/accordion-header/index.js
@@ -0,0 +1,42 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import edit from './edit';
+import save from './save';
+import metadata from './block.json';
+import initBlock from '../utils/init-block';
+
+const icon = (
+
+);
+
+const { name } = metadata;
+
+export { metadata, name };
+
+export const settings = {
+ icon,
+ example: {},
+ edit,
+ save,
+};
+
+export const init = () => initBlock( { name, metadata, settings } );
diff --git a/packages/block-library/src/accordion-header/init.js b/packages/block-library/src/accordion-header/init.js
new file mode 100644
index 00000000000000..79f0492c2cb2f8
--- /dev/null
+++ b/packages/block-library/src/accordion-header/init.js
@@ -0,0 +1,6 @@
+/**
+ * Internal dependencies
+ */
+import { init } from './';
+
+export default init();
diff --git a/packages/block-library/src/accordion-header/save.js b/packages/block-library/src/accordion-header/save.js
new file mode 100644
index 00000000000000..6ce0b6f3e49fb6
--- /dev/null
+++ b/packages/block-library/src/accordion-header/save.js
@@ -0,0 +1,89 @@
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+/**
+ * WordPress dependencies
+ */
+import {
+ useBlockProps,
+ __experimentalGetBorderClassesAndStyles as getBorderClassesAndStyles,
+ __experimentalGetColorClassesAndStyles as getColorClassesAndStyles,
+ __experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles,
+ __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles,
+ RichText,
+} from '@wordpress/block-editor';
+/**
+ * Internal dependencies
+ */
+import {
+ caret,
+ chevron,
+ chevronRight,
+ circlePlus,
+ plus,
+} from '../accordion-item/icons';
+
+const ICONS = {
+ plus,
+ circlePlus,
+ chevron,
+ chevronRight,
+ caret,
+};
+
+export default function save( { attributes } ) {
+ const { level, title, iconPosition, textAlign, icon } = attributes;
+ const TagName = 'h' + level;
+
+ const blockProps = useBlockProps.save();
+ const borderProps = getBorderClassesAndStyles( attributes );
+ const colorProps = getColorClassesAndStyles( attributes );
+ const spacingProps = getSpacingClassesAndStyles( attributes );
+ const shadowProps = getShadowClassesAndStyles( attributes );
+
+ const Icon = ICONS[ icon ];
+
+ return (
+
+
+
+ );
+}
diff --git a/packages/block-library/src/accordion-item/block.json b/packages/block-library/src/accordion-item/block.json
new file mode 100644
index 00000000000000..8ac65ea0190bdf
--- /dev/null
+++ b/packages/block-library/src/accordion-item/block.json
@@ -0,0 +1,46 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "core/accordion-item",
+ "version": "0.1.0",
+ "title": "Accordion",
+ "category": "design",
+ "description": "A single accordion that displays a header and expandable content.",
+ "example": {},
+ "__experimental": true,
+ "parent": [ "core/accordion-group" ],
+ "allowedBlocks": [ "core/accordion-header", "core/accordion-panel" ],
+ "supports": {
+ "align": [ "wide", "full" ],
+ "color": {
+ "background": true,
+ "gradient": true
+ },
+ "interactivity": true,
+ "spacing": {
+ "margin": [ "top", "bottom" ],
+ "blockGap": true
+ },
+ "__experimentalBorder": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true,
+ "__experimentalDefaultControls": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true
+ }
+ },
+ "shadow": true,
+ "layout": true
+ },
+ "attributes": {
+ "openByDefault": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "textdomain": "default"
+}
diff --git a/packages/block-library/src/accordion-item/edit.js b/packages/block-library/src/accordion-item/edit.js
new file mode 100644
index 00000000000000..1c9aa6538de100
--- /dev/null
+++ b/packages/block-library/src/accordion-item/edit.js
@@ -0,0 +1,110 @@
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import {
+ useBlockProps,
+ useInnerBlocksProps,
+ InspectorControls,
+ store as blockEditorStore,
+} from '@wordpress/block-editor';
+import { useDispatch, useSelect } from '@wordpress/data';
+import { useEffect } from '@wordpress/element';
+import { PanelBody, ToggleControl } from '@wordpress/components';
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+
+export default function Edit( {
+ attributes: { openByDefault },
+ clientId,
+ setAttributes,
+} ) {
+ const isSelected = useSelect(
+ ( select ) => {
+ const { isBlockSelected, hasSelectedInnerBlock } =
+ select( blockEditorStore );
+ return (
+ isBlockSelected( clientId ) ||
+ hasSelectedInnerBlock( clientId, true )
+ );
+ },
+ [ clientId ]
+ );
+
+ const getBlockOrder = useSelect(
+ ( select ) => select( blockEditorStore ).getBlockOrder,
+ []
+ );
+
+ const contentBlockClientId = getBlockOrder( clientId )[ 1 ];
+ const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } =
+ useDispatch( blockEditorStore );
+
+ useEffect( () => {
+ if ( contentBlockClientId ) {
+ __unstableMarkNextChangeAsNotPersistent();
+ updateBlockAttributes( contentBlockClientId, {
+ isSelected,
+ } );
+ }
+ }, [
+ isSelected,
+ contentBlockClientId,
+ __unstableMarkNextChangeAsNotPersistent,
+ updateBlockAttributes,
+ ] );
+
+ const blockProps = useBlockProps();
+ const innerBlocksProps = useInnerBlocksProps(
+ {
+ ...blockProps,
+ className: clsx( blockProps.className, {
+ 'is-open': openByDefault || isSelected,
+ } ),
+ },
+ {
+ template: [
+ [ 'core/accordion-header', {} ],
+ [
+ 'core/accordion-panel',
+ {
+ isSelected: true,
+ openByDefault,
+ },
+ ],
+ ],
+ templateLock: 'all',
+ directInsert: true,
+ }
+ );
+
+ return (
+ <>
+
+
+ {
+ setAttributes( {
+ openByDefault: value,
+ } );
+ if ( contentBlockClientId ) {
+ updateBlockAttributes( contentBlockClientId, {
+ openByDefault: value,
+ } );
+ }
+ } }
+ checked={ openByDefault }
+ help={ __(
+ 'Accordion content will be displayed by default.'
+ ) }
+ />
+
+
+
+ >
+ );
+}
diff --git a/packages/block-library/src/accordion-item/icons.js b/packages/block-library/src/accordion-item/icons.js
new file mode 100644
index 00000000000000..1a5ae0469c9882
--- /dev/null
+++ b/packages/block-library/src/accordion-item/icons.js
@@ -0,0 +1,121 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/components';
+
+export const chevron = ( { width, height } ) => {
+ return (
+
+ );
+};
+
+export const plus = ( { width, height } ) => {
+ return (
+
+ );
+};
+
+export const circlePlus = ( { width, height } ) => {
+ return (
+
+ );
+};
+
+export const circleMinus = ( { width, height } ) => {
+ return (
+
+ );
+};
+
+export const caret = ( { width, height } ) => {
+ return (
+
+ );
+};
+
+export const chevronRight = ( { width, height } ) => {
+ return (
+
+ );
+};
diff --git a/packages/block-library/src/accordion-item/index.js b/packages/block-library/src/accordion-item/index.js
new file mode 100644
index 00000000000000..f54dd6be83bdc7
--- /dev/null
+++ b/packages/block-library/src/accordion-item/index.js
@@ -0,0 +1,54 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import edit from './edit';
+import save from './save';
+import metadata from './block.json';
+import initBlock from '../utils/init-block';
+
+const icon = (
+
+);
+
+const { name } = metadata;
+
+export { metadata, name };
+
+export const settings = {
+ icon,
+ example: {},
+ edit,
+ save,
+};
+
+export const init = () => initBlock( { name, metadata, settings } );
diff --git a/packages/block-library/src/accordion-item/index.php b/packages/block-library/src/accordion-item/index.php
new file mode 100644
index 00000000000000..73dbacda63c1cb
--- /dev/null
+++ b/packages/block-library/src/accordion-item/index.php
@@ -0,0 +1,73 @@
+ function () {
+ $context = wp_interactivity_get_context();
+ return $context['openByDefault'];
+ },
+ )
+ );
+
+ if ( $p->next_tag( array( 'class_name' => 'wp-block-accordion-item' ) ) ) {
+ $open_by_default = $attributes['openByDefault'] ? 'true' : 'false';
+ $p->set_attribute( 'data-wp-context', '{ "id": "' . $unique_id . '", "openByDefault": ' . $open_by_default . ' }' );
+ $p->set_attribute( 'data-wp-class--is-open', 'state.isOpen' );
+ $p->set_attribute( 'data-wp-init', 'callbacks.initIsOpen' );
+
+ if ( $p->next_tag( array( 'class_name' => 'accordion-item__toggle' ) ) ) {
+ $p->set_attribute( 'data-wp-on--click', 'actions.toggle' );
+ $p->set_attribute( 'id', $unique_id );
+ $p->set_attribute( 'aria-controls', $unique_id . '-panel' );
+ $p->set_attribute( 'data-wp-bind--aria-expanded', 'state.isOpen' );
+
+ if ( $p->next_tag( array( 'class_name' => 'wp-block-accordion-panel' ) ) ) {
+ $p->set_attribute( 'id', $unique_id . '-panel' );
+ $p->set_attribute( 'aria-labelledby', $unique_id );
+ $p->set_attribute( 'data-wp-bind--inert', '!state.isOpen' );
+
+ // Only modify content if all directives have been set.
+ $content = $p->get_updated_html();
+ }
+ }
+ }
+
+ return $content;
+}
+
+/**
+ * Registers the `core/accordion-item` block on server.
+ *
+ * @since 6.6.0
+ */
+function register_block_core_accordion_item() {
+ register_block_type_from_metadata(
+ __DIR__ . '/accordion-item',
+ array(
+ 'render_callback' => 'block_core_accordion_item_render',
+ )
+ );
+}
+add_action( 'init', 'register_block_core_accordion_item' );
diff --git a/packages/block-library/src/accordion-item/init.js b/packages/block-library/src/accordion-item/init.js
new file mode 100644
index 00000000000000..79f0492c2cb2f8
--- /dev/null
+++ b/packages/block-library/src/accordion-item/init.js
@@ -0,0 +1,6 @@
+/**
+ * Internal dependencies
+ */
+import { init } from './';
+
+export default init();
diff --git a/packages/block-library/src/accordion-item/save.js b/packages/block-library/src/accordion-item/save.js
new file mode 100644
index 00000000000000..04d95466593c70
--- /dev/null
+++ b/packages/block-library/src/accordion-item/save.js
@@ -0,0 +1,25 @@
+/**
+ * WordPress dependencies
+ */
+import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+
+export default function save( { attributes } ) {
+ const { openByDefault } = attributes;
+ const blockProps = useBlockProps.save();
+ const className = clsx(
+ {
+ 'is-open': openByDefault,
+ },
+ blockProps.className
+ );
+ const innerBlocksProps = useInnerBlocksProps.save( {
+ ...blockProps,
+ className,
+ } );
+
+ return ;
+}
diff --git a/packages/block-library/src/accordion-panel/block.json b/packages/block-library/src/accordion-panel/block.json
new file mode 100644
index 00000000000000..57c14111398ab7
--- /dev/null
+++ b/packages/block-library/src/accordion-panel/block.json
@@ -0,0 +1,75 @@
+{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
+ "apiVersion": 3,
+ "name": "core/accordion-panel",
+ "version": "0.1.0",
+ "title": "Accordion Panel",
+ "category": "design",
+ "description": "Accordion Panel",
+ "example": {},
+ "__experimental": true,
+ "parent": [ "core/accordion-item" ],
+ "supports": {
+ "color": {
+ "background": true,
+ "gradient": true
+ },
+ "border": true,
+ "interactivity": true,
+ "spacing": {
+ "padding": true,
+ "margin": [ "top", "bottom" ],
+ "blockGap": true,
+ "__experimentalDefaultControls": {
+ "padding": true,
+ "blockGap": true
+ }
+ },
+ "__experimentalBorder": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true,
+ "__experimentalDefaultControls": {
+ "color": true,
+ "radius": true,
+ "style": true,
+ "width": true
+ }
+ },
+ "typography": {
+ "fontSize": true,
+ "lineHeight": true,
+ "__experimentalFontFamily": true,
+ "__experimentalFontWeight": true,
+ "__experimentalFontStyle": true,
+ "__experimentalTextTransform": true,
+ "__experimentalTextDecoration": true,
+ "__experimentalLetterSpacing": true,
+ "__experimentalDefaultControls": {
+ "fontSize": true
+ }
+ },
+ "shadow": true,
+ "layout": true
+ },
+ "attributes": {
+ "allowedBlocks": {
+ "type": "array"
+ },
+ "templateLock": {
+ "type": [ "string", "boolean" ],
+ "enum": [ "all", "insert", "contentOnly", false ],
+ "default": false
+ },
+ "openByDefault": {
+ "type": "boolean",
+ "default": false
+ },
+ "isSelected": {
+ "type": "boolean",
+ "default": false
+ }
+ },
+ "textdomain": "default"
+}
diff --git a/packages/block-library/src/accordion-panel/edit.js b/packages/block-library/src/accordion-panel/edit.js
new file mode 100644
index 00000000000000..6f708b33cefb0c
--- /dev/null
+++ b/packages/block-library/src/accordion-panel/edit.js
@@ -0,0 +1,61 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ useBlockProps,
+ useInnerBlocksProps,
+ __experimentalUseBorderProps as useBorderProps,
+ __experimentalUseColorProps as useColorProps,
+ __experimentalGetSpacingClassesAndStyles as useSpacingProps,
+ __experimentalGetShadowClassesAndStyles as useShadowProps,
+} from '@wordpress/block-editor';
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+
+export default function Edit( { attributes } ) {
+ const { allowedBlocks, templateLock, openByDefault, isSelected } =
+ attributes;
+ const borderProps = useBorderProps( attributes );
+ const colorProps = useColorProps( attributes );
+ const spacingProps = useSpacingProps( attributes );
+ const shadowProps = useShadowProps( attributes );
+
+ const blockProps = useBlockProps();
+ const innerBlocksProps = useInnerBlocksProps(
+ {
+ className: 'accordion-content__wrapper',
+ style: {
+ ...spacingProps.style,
+ },
+ },
+ {
+ allowedBlocks,
+ template: [ [ 'core/paragraph', {} ] ],
+ templateLock,
+ }
+ );
+
+ return (
+
+ );
+}
diff --git a/packages/block-library/src/accordion-panel/index.js b/packages/block-library/src/accordion-panel/index.js
new file mode 100644
index 00000000000000..cd00c2d9413f6f
--- /dev/null
+++ b/packages/block-library/src/accordion-panel/index.js
@@ -0,0 +1,41 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/components';
+/**
+ * Internal dependencies
+ */
+import edit from './edit';
+import save from './save';
+import metadata from './block.json';
+import initBlock from '../utils/init-block';
+
+const icon = (
+
+);
+
+const { name } = metadata;
+
+export { metadata, name };
+
+export const settings = {
+ icon,
+ example: {},
+ edit,
+ save,
+};
+
+export const init = () => initBlock( { name, metadata, settings } );
diff --git a/packages/block-library/src/accordion-panel/init.js b/packages/block-library/src/accordion-panel/init.js
new file mode 100644
index 00000000000000..79f0492c2cb2f8
--- /dev/null
+++ b/packages/block-library/src/accordion-panel/init.js
@@ -0,0 +1,6 @@
+/**
+ * Internal dependencies
+ */
+import { init } from './';
+
+export default init();
diff --git a/packages/block-library/src/accordion-panel/save.js b/packages/block-library/src/accordion-panel/save.js
new file mode 100644
index 00000000000000..7ebbffc2cfd42e
--- /dev/null
+++ b/packages/block-library/src/accordion-panel/save.js
@@ -0,0 +1,51 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ InnerBlocks,
+ useBlockProps,
+ __experimentalGetBorderClassesAndStyles as getBorderClassesAndStyles,
+ __experimentalGetColorClassesAndStyles as getColorClassesAndStyles,
+ __experimentalGetSpacingClassesAndStyles as getSpacingClassesAndStyles,
+ __experimentalGetShadowClassesAndStyles as getShadowClassesAndStyles,
+} from '@wordpress/block-editor';
+/**
+ * External dependencies
+ */
+import clsx from 'clsx';
+
+export default function save( { attributes } ) {
+ const blockProps = useBlockProps.save();
+ const borderProps = getBorderClassesAndStyles( attributes );
+ const colorProps = getColorClassesAndStyles( attributes );
+ const spacingProps = getSpacingClassesAndStyles( attributes );
+ const shadowProps = getShadowClassesAndStyles( attributes );
+
+ return (
+
+ );
+}
diff --git a/packages/block-library/src/index.js b/packages/block-library/src/index.js
index 56365c87a268fd..7acea9ef85abe7 100644
--- a/packages/block-library/src/index.js
+++ b/packages/block-library/src/index.js
@@ -20,6 +20,10 @@ import {
// production build to make the final bundle smaller.
//
// See https://github.com/WordPress/gutenberg/pull/40655 for more context.
+import * as accordionGroup from './accordion-group';
+import * as accordionItem from './accordion-item';
+import * as accordionHeader from './accordion-header';
+import * as accordionPanel from './accordion-panel';
import * as archives from './archives';
import * as avatar from './avatar';
import * as audio from './audio';
@@ -232,6 +236,14 @@ const getAllBlocks = () => {
queryTitle,
postAuthorBiography,
];
+
+ if ( window?.__experimentalEnableBlockExperiments ) {
+ blocks.push( accordionGroup );
+ blocks.push( accordionItem );
+ blocks.push( accordionHeader );
+ blocks.push( accordionPanel );
+ }
+
if ( window?.__experimentalEnableFormBlocks ) {
blocks.push( form );
blocks.push( formInput );
diff --git a/packages/block-library/src/style.scss b/packages/block-library/src/style.scss
index a8819c2084dc2e..bb3957eabef8dd 100644
--- a/packages/block-library/src/style.scss
+++ b/packages/block-library/src/style.scss
@@ -1,3 +1,4 @@
+@import "./accordion-group/style.scss";
@import "./archives/style.scss";
@import "./avatar/style.scss";
@import "./audio/style.scss";