Skip to content

feat(block-theme): add overlay block for the block theme#4578

Merged
laurelfulford merged 22 commits intotrunkfrom
feat/hamburger-menu-block
Apr 7, 2026
Merged

feat(block-theme): add overlay block for the block theme#4578
laurelfulford merged 22 commits intotrunkfrom
feat/hamburger-menu-block

Conversation

@laurelfulford
Copy link
Copy Markdown
Contributor

@laurelfulford laurelfulford commented Mar 17, 2026

All Submissions:

Changes proposed in this Pull Request:

This PR adds an overlay menu block for the block theme.

The block is technically comprised of three blocks:

  • The generic 'Overlay Menu' block that contains everything.
  • The Trigger block; a button that will open/close the overlay block.
  • The Panel block, which contains the close button and the overlay panel's contents.

Once this block has been merged and added to the Newspack Block theme, there's also some file cleanup we can do to get rid of the current menu template part, etc.

Closes NPPD-1279.

How to test the changes in this Pull Request:

There's a few different groups of settings to be tested in this block:

Test inserting the block

  1. Add the block to the Site Editor - edit a template part and search for the Overlay Menu
  2. Confirm a visible button is added, with a toolbar
  3. Click the Open Panel button in the toolbar and confirm that the overlay menu appears
  4. Confirm that the structure of the block is two blocks inside a container
  5. Confirm all three blocks have an Open Panel/Close Panel button in their block toolbar

Edit the button

  1. Try changing the menu trigger button's colour
  2. Try changing the menu trigger button's text by editing the button directly.
  3. Try changing the menu trigger button's style (text only, icon only).
  4. Try editing some other options (border radius, etc).
  5. Try publishing at different point; when the button's text is hidden, confirm it's still used as screen reader text on the front-end.

Edit the Panel's settings

  1. Select the Panel block (by clicking the Open Panel button in the toolbar of any of these blocks), and using the option in the right sidebar, change the panel's direction
  2. Try changing the text, background, and overlay colours
  3. Confirm your choices preview in the editor
  4. Publish your changes and confirm they work on the front-end
  5. Reset all colours and confirm they return to normal.

Adding editor content

  1. Confirm that when the Overlay block is inserted in the editor, it's pre-populated with a Navigation block
  2. Try editing the Navigating block and saving your changing; confirm they work on the front-end.
  3. Try deleting the block and adding some others; confirm they work as expected on the front-end.

Add several many blocks

  1. Try adding more than one Overlay Menu block to a post/page/template part.
  2. Confirm that they work independently in the editor (only the one set of buttons in the editor opens the associated panel)
  3. Publish and confirm they work independently on the front end (if you open/close one block's buttons, it only affects that overlay block)

Test accessibility

  1. Try tabbing to the menu button to open the overlay panel; click enter to open it
  2. Using tab and tab + shift, navigate up and down through the panel's content; confirm the menu traps focus
  3. Try tabbing to the close button and clicking 'enter'; confirm keyboard focus returns to the associated menu trigger button
  4. Try reopening the menu again; click esc and confirm it closes the menu

Other information:

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully ran tests with your changes locally?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new composite “Overlay Menu” Gutenberg block (parent + trigger + panel) for block themes, including frontend behavior (open/close, scrim, focus handling) and editor controls for previewing/configuring the panel.

Changes:

  • Registers new overlay-menu blocks (parent/trigger/panel) and loads their PHP render callbacks under the block-theme gate.
  • Adds a dedicated frontend script bundle (overlay-menu-block) and associated styles for panel/scrim behavior.
  • Implements editor UI for trigger text/styles and panel settings (direction + colors) with a shared preview toggle.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
webpack.config.js Adds overlay-menu-block entry to build the frontend script bundle.
src/blocks/index.js Registers overlay-menu blocks and gates them to block themes.
includes/class-blocks.php Requires the new overlay-menu PHP block classes under wp_is_block_theme().
src/blocks/overlay-menu/block.json Defines parent block metadata, context, and viewScript.
src/blocks/overlay-menu/index.js Registers the parent block (editor) and imports styles.
src/blocks/overlay-menu/edit.js Parent edit UI with locked InnerBlocks template and preview toggle.
src/blocks/overlay-menu/class-overlay-menu-block.php Server render callback for the parent wrapper + data-overlay-id.
src/blocks/overlay-menu/style.scss Frontend/editor styles for trigger, panel, and scrim.
src/blocks/overlay-menu/view.js Frontend open/close logic, scrim creation, and focus trapping.
src/blocks/overlay-menu/panel-preview-toggle.js Shared toolbar toggle for editor preview open/close.
src/blocks/overlay-menu/trigger/block.json Trigger block metadata and supports (colors/typography/spacing/border).
src/blocks/overlay-menu/trigger/index.js Registers trigger block styles and editor settings.
src/blocks/overlay-menu/trigger/edit.js Trigger edit UI with RichText label and preview toggle integration.
src/blocks/overlay-menu/trigger/class-overlay-menu-trigger-block.php Dynamic PHP render for the trigger button.
src/blocks/overlay-menu/panel/block.json Panel block metadata and attributes (direction/colors/preview state).
src/blocks/overlay-menu/panel/index.js Registers panel block and saves InnerBlocks content.
src/blocks/overlay-menu/panel/edit.js Panel editor UI (direction + colors) and in-editor preview overlay/scrim.
src/blocks/overlay-menu/panel/class-overlay-menu-panel-block.php Dynamic PHP render for the panel wrapper + close button.
src/blocks/overlay-menu/NOTES.md Development notes documenting architecture and behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread src/blocks/overlay-menu/class-overlay-menu-block.php Outdated
Comment thread src/blocks/overlay-menu/view.js
Comment thread src/blocks/overlay-menu/panel/class-overlay-menu-panel-block.php
Comment thread src/blocks/overlay-menu/view.js
Comment thread src/blocks/overlay-menu/view.js Outdated
Comment thread src/blocks/overlay-menu/view.js Outdated
Comment thread src/blocks/overlay-menu/index.js Outdated
Comment thread src/blocks/overlay-menu/trigger/block.json
Comment thread src/blocks/overlay-menu/style.scss Outdated
@laurelfulford laurelfulford changed the title feat: add overlay block for the block theme feat(block-theme): add overlay block for the block theme Mar 24, 2026
@laurelfulford laurelfulford added the [Status] Needs Review The issue or pull request needs to be reviewed label Mar 24, 2026
@laurelfulford laurelfulford marked this pull request as ready for review March 24, 2026 00:58
@laurelfulford laurelfulford requested a review from a team as a code owner March 24, 2026 00:58
Copy link
Copy Markdown
Member

@adekbadek adekbadek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested all 6 sections from the PR description in an isolated environment with the block theme. Everything works well - block insertion, button editing (color/text/styles), panel settings (direction/colors), editor content, multiple independent instances, and keyboard accessibility.

A few items to address below.

'data-direction' => $direction,
'data-overlay-color' => $overlay_color,
'aria-hidden' => 'true',
'role' => 'dialog',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility bug: The panel renders aria-hidden="true" but is missing the inert attribute. The JS adds/removes inert on open/close (view.js lines 144 and 192), but on initial page load the panel is closed without inert. This means screen readers and keyboard navigation can reach hidden panel content before any JS runs (or if JS fails to load).

Add 'inert' => true to $extra_attributes here so the initial server-rendered state matches what JS produces after a close:

'aria-hidden'        => 'true',
'inert'              => true,
'role'               => 'dialog',

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Adam! Added in c106f01.

// Lock document scrolling while any overlay menu instance is open.
body:is( [class*=" menu-open--overlay-menu-"] ) {
overflow: hidden !important; // !important to temporarily override style from block theme's overlay approach.
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CSS edge case: The *=" menu-open--overlay-menu-" selector requires a leading space before the class name. If this happens to be the first class on <body> (no leading space in the attribute string), the selector won't match and scroll lock won't apply.

Fix with an additional selector for the start-of-attribute case:

body:is(
  [class^="menu-open--overlay-menu-"],
  [class*=" menu-open--overlay-menu-"]
) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eep, thanks! Fixed in 3a7b051.

Comment thread src/blocks/overlay-menu/view.js Outdated
overlay = null;
el.style.opacity = '0';
// Remove from DOM once the CSS opacity transition finishes.
el.addEventListener( 'transitionend', () => el.remove(), { once: true } );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential bug with prefers-reduced-motion: If the CSS transition is skipped (e.g., prefers-reduced-motion is active, element is hidden, or the browser collapses the transition), transitionend never fires and the scrim element stays in the DOM forever.

Consider adding a fallback timeout:

const el = overlay;
overlay = null;
el.style.opacity = '0';
const cleanup = () => el.remove();
el.addEventListener( 'transitionend', cleanup, { once: true } );
setTimeout( cleanup, 600 ); // Fallback if transition is skipped.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in b171549!

"default": ""
},
"isPreviewOpen": {
"type": "boolean",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: isPreviewOpen is defined in block.json, which means it gets serialized to post content. The edit component resets it to false on mount, but saving a post with the panel open will still write isPreviewOpen: true to the database -- and loading that post could briefly mark it as dirty when the mount effect clears it.

This is editor-only UI state. Consider managing it outside of block attributes entirely (e.g., via a module-level Map keyed by clientId, or a React ref), which would avoid the persist/reset cycle.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved out of the block attributes in f19d8fc.

"navigation",
"overlay",
"hamburger"
],
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "overlay" appears twice in the keywords array (lines 12 and 15). Same duplication exists in index.js.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♀️ Thanks for catching that 😆 Got it down to one mention in each file in b5355d6.

Comment thread src/blocks/overlay-menu/style.scss Outdated
// Fade panel covers the full viewport; starts slightly offset so it slides in.
.overlay-menu__panel--fade {
inset: 0;
max-width: 100%;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The .overlay-menu__panel--fade class (lines 122-125) is defined in CSS but unreachable -- the editor UI only offers "left" and "right" directions, and the PHP validation allowlist ($valid_directions) only permits those two values. Either remove this dead CSS or add it as a documented follow-up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eep, thanks! Removed in 91b174b.

@@ -0,0 +1,218 @@
/**
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: The file header says "Flyout Menu Block" but the block is named "Overlay Menu" -- looks like a remnant from an earlier naming iteration.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switched to "Overlay Menu Block" in 488d3ae!

@laurelfulford laurelfulford requested a review from adekbadek April 2, 2026 23:02
@laurelfulford
Copy link
Copy Markdown
Contributor Author

Thanks @adekbadek! I've made the updates - just let me know if anything else needs changing!

Copy link
Copy Markdown
Member

@adekbadek adekbadek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good!

@github-actions github-actions bot added [Status] Approved The pull request has been reviewed and is ready to merge and removed [Status] Needs Review The issue or pull request needs to be reviewed labels Apr 6, 2026
@laurelfulford
Copy link
Copy Markdown
Contributor Author

Sweet! Thanks @adekbadek! 🙌

@laurelfulford laurelfulford merged commit af1e4b9 into trunk Apr 7, 2026
11 checks passed
@laurelfulford laurelfulford deleted the feat/hamburger-menu-block branch April 7, 2026 18:29
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 7, 2026

Hey @laurelfulford, good job getting this PR merged! 🎉

Now, the needs-changelog label has been added to it.

Please check if this PR needs to be included in the "Upcoming Changes" and "Release Notes" doc. If it doesn't, simply remove the label.

If it does, please add an entry to our shared document, with screenshots and testing instructions if applicable, then remove the label.

Thank you! ❤️

matticbot pushed a commit that referenced this pull request Apr 16, 2026
# [6.38.0-alpha.1](v6.37.0...v6.38.0-alpha.1) (2026-04-16)

### Bug Fixes

* `is_donor` read-only only on WooCommerce-backed donations ([1dde930](1dde930))
* **access-control:** fix incorrect class name ([#4638](#4638)) ([a7a7908](a7a7908))
* **access-control:** hide My Account group features if Memberships is still active ([#4650](#4650)) ([214fa0d](214fa0d))
* add object-level authorization to corrections REST endpoint ([#4643](#4643)) ([a39a62d](a39a62d))
* address false positives in subscription status alerts on My Account ([f7d6bb8](f7d6bb8))
* address false positives in subscription status alerts on My Account ([31c8313](31c8313))
* clear stored referrer data where referrer is none or local ([c7ef6f3](c7ef6f3))
* count `pending-cancel` by testing against our canonical constant ([2a1f85b](2a1f85b))
* count `pending-cancel` by testing against our canonical constant ([8906b64](8906b64))
* include products without children when reviewing active subscriptions ([d714f3c](d714f3c))
* include products without children when reviewing active subscriptions ([aae3da2](aae3da2))
* limit success and notice snackbar treatments to My Account page ([3b40bec](3b40bec))
* **my-account:** limit notice/success snackbar overrides to My Account ([49517c1](49517c1))
* normalize referrer data when comparing ([d377afb](d377afb))
* **reader-activation:** clear referrer data when none provided ([696012b](696012b))
* **reader-data:** make is_donor read-only only when platform has server-side tracking ([92b0d34](92b0d34))
* update docblock to reflect simple product support ([ea1f03e](ea1f03e))
* update docblock to reflect simple product support ([ba14f85](ba14f85))
* **woocommerce:** image handling in paginated block ([#4149](#4149)) ([1c91f6c](1c91f6c))

### Features

* **access-control:** advanced settings for RSS content restriction ([#4613](#4613)) ([85aa560](85aa560))
* **access-control:** update default patterns ([#4569](#4569)) ([7f9a6c9](7f9a6c9))
* add filter for future integrations to self-declare server-side (secure?) donor tracking ([76e40fc](76e40fc))
* add README.md for the Overlay Block ([#4651](#4651)) ([6d7de6e](6d7de6e))
* **advertising:** replace placements UI with inline expandable cards ([#4625](#4625)) ([e5de003](e5de003))
* **block-theme:** add overlay block for the block theme ([#4578](#4578)) ([af1e4b9](af1e4b9))
* **components:** update CardFeature button size and variant ([#4609](#4609)) ([1d03d4c](1d03d4c))
* **content-gate:** add per-block access control for Group, Stack, and Row blocks ([#4646](#4646)) ([5bdf458](5bdf458))
* **content-gate:** add POST method for external IP access checks ([#4598](#4598)) ([36bfeea](36bfeea))
* **google-site-kit:** enable custom GA frontend params by default ([#4664](#4664)) ([19830ce](19830ce))
* **handoff:** add URL-based handoff with customizable banner text ([#4603](#4603)) ([be59c68](be59c68))
* **integrations:** add My Account menu hook to integration abstraction ([#4640](#4640)) ([4ef2c91](4ef2c91))
* **integrations:** add subscription and donation metadata ([#4597](#4597)) ([ca928f8](ca928f8))
* **integrations:** implement profile metadata ([#4624](#4624)) ([b1daf85](b1daf85))
* make it easier to do "Block until consent given" setups in Complianz and improve blocking ([#4549](#4549)) ([44dda72](44dda72))
* reader activation segments ([#4604](#4604)) ([3821fed](3821fed))
* **reader-data:** add engagement fields ([#4594](#4594)) ([1cba4ef](1cba4ef))
* **reader-data:** store sync reconciliation ([#4633](#4633)) ([69bdda4](69bdda4))
* require reader to set name when commenting ([#4647](#4647)) ([db5ad73](db5ad73))
* session hydration ([#4618](#4618)) ([665b152](665b152))

### Reverts

* address false positives in subscription status alerts on My Account ([9d203b0](9d203b0))
@github-actions
Copy link
Copy Markdown

🎉 This PR is included in version 6.38.0-alpha.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Status] Approved The pull request has been reviewed and is ready to merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants