diff --git a/blocks/details/editor.scss b/blocks/details/editor.scss
new file mode 100644
index 00000000..625fad40
--- /dev/null
+++ b/blocks/details/editor.scss
@@ -0,0 +1,6 @@
+/* Editor styles */
+.wp-block-a8c-details {
+ summary .rich-text {
+ display: inline;
+ }
+}
diff --git a/blocks/details/index.php b/blocks/details/index.php
new file mode 100644
index 00000000..ad6ce843
--- /dev/null
+++ b/blocks/details/index.php
@@ -0,0 +1,9 @@
+ 'block-experiments',
+ 'style' => 'block-experiments',
+ 'editor_style' => 'block-experiments-editor',
+ ] );
+} );
diff --git a/blocks/details/src/block.json b/blocks/details/src/block.json
new file mode 100644
index 00000000..1d6cda81
--- /dev/null
+++ b/blocks/details/src/block.json
@@ -0,0 +1,13 @@
+{
+ "name": "a8c/details",
+ "category": "layout",
+ "attributes": {
+ "initialOpen": {
+ "type": "boolean",
+ "default": false
+ },
+ "summaryContent": {
+ "type": "string"
+ }
+ }
+}
\ No newline at end of file
diff --git a/blocks/details/src/edit.js b/blocks/details/src/edit.js
new file mode 100644
index 00000000..fe31c5db
--- /dev/null
+++ b/blocks/details/src/edit.js
@@ -0,0 +1,94 @@
+/**
+ * WordPress dependencies
+ */
+import {
+ InnerBlocks,
+ RichText,
+ InspectorControls,
+} from '@wordpress/block-editor';
+import { __ } from '@wordpress/i18n';
+import { useSelect } from '@wordpress/data';
+import {
+ ToggleControl,
+ Panel,
+ PanelBody,
+ PanelRow,
+} from '@wordpress/components';
+import { useEffect, useRef } from '@wordpress/element';
+import { SPACE } from '@wordpress/keycodes';
+
+export default function DetalsEdit( {
+ attributes,
+ className,
+ clientId,
+ isSelected,
+ setAttributes,
+} ) {
+ const summaryRef = useRef( null );
+
+ const keyUpListener = ( e ) => {
+ if ( e.keyCode === SPACE ) {
+ e.preventDefault();
+ }
+ };
+
+ const clickListener = ( e ) => e.preventDefault();
+
+ useEffect( () => {
+ if ( ! summaryRef.current ) {
+ return;
+ }
+
+ summaryRef.current.addEventListener( 'keyup', keyUpListener );
+ summaryRef.current.addEventListener( 'click', clickListener );
+ return () => {
+ summaryRef.current.removeEventListener( 'keyup', keyUpListener );
+ summaryRef.current.removeEventListener( 'click', clickListener );
+ };
+ }, [ summaryRef.current ] );
+
+ const isInnerBlockSelected = useSelect(
+ ( select ) =>
+ select( 'core/block-editor' ).hasSelectedInnerBlock( clientId ),
+ [ clientId ]
+ );
+
+ const showInnerBlocks =
+ attributes.initialOpen || isSelected || isInnerBlockSelected;
+
+ return (
+ <>
+
+
+
+
+
+ setAttributes( { initialOpen } )
+ }
+ checked={ attributes.initialOpen }
+ />
+
+
+
+
+
+
+ setAttributes( { summaryContent } )
+ }
+ ref={ summaryRef }
+ placeholder={ __( 'Write a summary…' ) }
+ keepPlaceholderOnFocus
+ aria-label={ __( 'Summary text' ) }
+ />
+
+
+
+
+ >
+ );
+}
diff --git a/blocks/details/src/icon.js b/blocks/details/src/icon.js
new file mode 100644
index 00000000..ef9d3c95
--- /dev/null
+++ b/blocks/details/src/icon.js
@@ -0,0 +1,12 @@
+/**
+ * WordPress dependencies
+ */
+import { SVG, Path } from '@wordpress/primitives';
+
+const details = (
+
+);
+
+export default details;
diff --git a/blocks/details/src/index.js b/blocks/details/src/index.js
new file mode 100644
index 00000000..8e819e4a
--- /dev/null
+++ b/blocks/details/src/index.js
@@ -0,0 +1,44 @@
+/**
+ * WordPress dependencies
+ */
+import { registerBlockType } from '@wordpress/blocks';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import edit from './edit';
+import metadata from './block.json';
+import save from './save';
+import icon from './icon';
+
+const { name, category, attributes } = metadata;
+
+export { metadata, name };
+
+export const settings = {
+ title: __( 'Details' ),
+ description: __( 'Create a toggle to show and hide content.' ),
+ icon,
+ category,
+ edit,
+ save,
+ // details and summary are not translated because they are the HTML tags
+ keywords: [ 'details', 'summary', __( 'faq' ), __( 'spoiler' ) ],
+ attributes,
+ styles: [
+ {
+ name: 'disclosure',
+ label: __( 'Open / Close' ),
+ isDefault: true,
+ },
+ {
+ name: 'flipcard',
+ label: __( 'Flip Card' ),
+ },
+ ],
+};
+
+export function registerBlock() {
+ registerBlockType( name, settings );
+}
diff --git a/blocks/details/src/save.js b/blocks/details/src/save.js
new file mode 100644
index 00000000..38e90147
--- /dev/null
+++ b/blocks/details/src/save.js
@@ -0,0 +1,18 @@
+/**
+ * WordPress dependencies
+ */
+import { InnerBlocks, RichText } from '@wordpress/block-editor';
+
+export default ( { attributes } ) => {
+ return (
+
+
+
+
+
+
+ );
+};
diff --git a/blocks/details/style.scss b/blocks/details/style.scss
new file mode 100644
index 00000000..b96702b0
--- /dev/null
+++ b/blocks/details/style.scss
@@ -0,0 +1,60 @@
+// Front end and editor styles.
+
+$bgcolor: #efefef; // Be nice if this was customizable via a background color property.
+
+@keyframes open-card {
+ 0% {
+ transform: rotateX(-180deg);
+ opacity: 0;
+ }
+ 100% {
+ transform: rotateX(0deg);
+ opacity: 1;
+ }
+}
+
+.wp-block-a8c-details {
+
+ // 3D flip-card style.
+ &.is-style-flipcard {
+ margin-bottom: 1.5em;
+
+ // Enable 3D perspective.
+ transform-style: preserve-3d;
+ perspective: 300px;
+
+
+ // Card front-face.
+ summary {
+ background: $bgcolor;
+ padding: 1em;
+
+ // Allows a focus style on the summary to be uncropped.
+ position: relative;
+ }
+
+ // Back-face regardless of opened or closed.
+ > *:not(summary) {
+ background: $bgcolor;
+ transform-origin: top center;
+ -webkit-backface-visibility: hidden;
+ backface-visibility: hidden;
+
+ // Some baseline left and right padding.
+ padding-left: 1em;
+ padding-right: 1em;
+ }
+
+ // Neutralize the top margin of the first innerblock, add padding.
+ > summary+*, // Frontend
+ > .block-editor-inner-blocks > .block-editor-block-list__layout > * { // Editor
+ margin-top: 0;
+ padding-top: 1em;
+ }
+
+ // Back-face when opened.
+ &[open] > *:not(summary) {
+ animation: open-card .2s ease;
+ }
+ }
+}
diff --git a/bundler/bundles/details.json b/bundler/bundles/details.json
new file mode 100644
index 00000000..141c110b
--- /dev/null
+++ b/bundler/bundles/details.json
@@ -0,0 +1,9 @@
+{
+ "blocks": [
+ "details"
+ ],
+ "version": "0.0.1",
+ "name": "Details Block",
+ "description": "Create a toggle to show and hide content",
+ "resource": "a8c-details"
+}
diff --git a/editor.scss b/editor.scss
index 64623338..e30c40cc 100644
--- a/editor.scss
+++ b/editor.scss
@@ -6,3 +6,4 @@
@import './blocks/starscape/editor.scss';
@import './blocks/waves/editor.scss';
@import './blocks/book/editor.scss';
+@import './blocks/details/editor.scss';
diff --git a/src/index.js b/src/index.js
index c9317974..fdfb32ea 100644
--- a/src/index.js
+++ b/src/index.js
@@ -29,6 +29,7 @@ import * as motionBackgroundBlock from '../blocks/motion-background/src';
import * as starscapeBlock from '../blocks/starscape/src';
import * as wavesBlock from '../blocks/waves/src';
import * as bookBlock from '../blocks/book/src';
+import * as detailsBlock from '../blocks/details/src';
// Instantiate the blocks, adding them to our block category
bauhausCentenaryBlock.registerBlock();
@@ -38,3 +39,4 @@ motionBackgroundBlock.registerBlock();
starscapeBlock.registerBlock();
wavesBlock.registerBlock();
bookBlock.registerBlock();
+detailsBlock.registerBlock();
diff --git a/style.scss b/style.scss
index 1587de4a..6cb21273 100644
--- a/style.scss
+++ b/style.scss
@@ -6,3 +6,4 @@
@import './blocks/starscape/style.scss';
@import './blocks/waves/style.scss';
@import './blocks/book/style.scss';
+@import './blocks/details/style.scss';