A reusable modal dialog for WordPress blocks, built using the WordPress Interactivity API.
This modal component provides a consistent, accessible way to display dialogs in different blocks within the ActivityPub plugin. It supports two styles—compact (like a popover) and full-size—and includes features like focus trapping, keyboard controls, and click-outside-to-close behavior.
- Two display modes: compact (popover-style) and full-size.
- Built-in accessibility support (focus management, ARIA roles).
- Keyboard navigation (e.g., Esc to close).
- Dismiss by clicking outside the modal.
- Optional title and customizable content.
- Uses context to safely manage modal state in each block.
The modal is built from three main parts:
-
JavaScript Controller
Manages the modal’s open/close state and behavior. It integrates with the WordPress Interactivity API using your block’s namespace. -
PHP Rendering
Renders the modal’s HTML usingBlocks::render_modal()
. You control what content appears in the modal and whether it’s compact or full-size. -
SCSS Styling
Handles the modal’s appearance and animations for both variants.
In your block’s JS file (e.g., view.js
):
import { createModalController } from '../shared/modal';
Pass your block's namespace to set up modal state handling:
createModalController('activitypub/your-block-name');
The namespace you pass to createModalController()
should match your block’s namespace because the WordPress Interactivity API merges all stores that share the same namespace.
This means:
- The modal’s actions and callbacks are added directly to your block’s existing store.
- You can access and manage modal state (
context.modal
) as part of your block’s overall context. - There’s no need to manage a separate modal store—everything is scoped and available within your block’s interactive logic.
Using a consistent namespace ensures the modal integrates cleanly into your block's behavior without conflicts or extra configuration.
In your block’s render.php
, define a modal
key in the context array:
$context = array(
'blockId' => $block_id,
'modal' => array(
'isOpen' => false,
'isCompact' => true, // Use false for a full-size modal.
// Add any other context data you need.
),
);
$wrapper_attributes = get_block_wrapper_attributes(
array(
'id' => $block_id,
'data-wp-interactive' => 'activitypub/your-block-name',
'data-wp-context' => wp_json_encode( $context ),
)
);
Call Blocks::render_modal()
to output the modal HTML:
$modal_content = '
<div class="your-modal-content">
<!-- Your modal content here -->
</div>
';
Blocks::render_modal(
array(
'is_compact' => true, // false for full-size.
'title' => __( 'Your Modal Title', 'activitypub' ), // Optional; used in full-size modals.
'content' => $modal_content,
)
);
Use the Interactivity API to connect a button that opens the modal:
$button = '<button class="wp-element-button" data-wp-on--click="actions.toggleModal">Open Modal</button>';
The modal controller provides these actions automatically in your namespace:
actions.openModal()
– Opens the modal.actions.closeModal()
– Closes the modal.actions.toggleModal()
– Toggles modal open/closed.
You can hook into modal open/close events by registering callbacks in your store:
const { callbacks } = store( 'activitypub/your-block-name', {
callbacks: {
onModalOpen() {
// Run custom logic when the modal opens.
},
onModalClose() {
// Run custom logic when the modal closes.
},
}
});
Default modal styles are in style.scss
, including animations and responsive layout for both modal sizes. Import the styles into your block:
@import '../shared/modal/style';
// Add any block-specific styles below
The modal is built with accessibility in mind:
- ARIA roles for dialogs
- Automatic focus trapping inside the modal
- Keyboard support (Escape key, tab navigation)
See implementation in:
src/reactions/view.js
src/reactions/render.php
See implementation in:
src/follow-me/view.js
src/follow-me/render.php