Open a Modal from Outside Alpine Components
Learn how to open a modal dialog from anywhere on your page, even outside its Alpine.js component.
Method 1: Using Events (Recommended for Hyvä >= 1.1.18)
As of Hyvä release 1.1.18, you can open modal dialogs by dispatching the hyva-modal-show event.
From an Alpine.js component:
<button type="button" aria-haspopup="dialog"
@click="$dispatch('hyva-modal-show', {dialog: 'my-modal'})"
>Open</button>
From anywhere with vanilla JS:
Important: Hyvä >= 1.1.18
The hyva-modal-show event listener requires hyva-themes/magento2-theme-module version 1.1.18 or higher. If your module depends on this event, ensure you add the following to its composer.json:
"hyva-themes/magento2-theme-module": "^1.1.18"
For Hyvä <= 1.1.17: Using a Custom Event
For older Hyvä versions, the most direct approach is to use a custom event.
Step 1: Declare the view model:
$modal = $viewModels->require(\Hyva\Theme\ViewModel\Modal::class)
->createModal()
->withDialogRefName('my-dialog')
->withContent(<<<EOCONTENT
<div>
<h3>Example dialog that can be opened with an event.</h3>
<pre class="my-4">
// To open from an alpine component use
$dispatch('open-my-dialog')
// or globaly
window.dispatchEvent(new CustomEvent('open-my-dialog'))
</pre>
<button @click="hide" type="button" class="btn">Cancel</button>
</div>
EOCONTENT
);
Step 2: Declare the modal component with an event listener:
Accessibility: Specifying Focus After Modal Close
Available since Hyvä 1.2.9 / 1.3.5
For improved accessibility, ensure focus returns to the correct element after the modal closes. When dispatching the hyva-modal-show event, you can specify this element using the focusAfterHide property:
Method 2: Using a Global Function
Alternatively, you can define a global function to open the modal from anywhere. This involves capturing the Alpine component's scope within a global function during initialization.
Step 1: Declare the view model:
$modal = $viewModels->require(\Hyva\Theme\ViewModel\Modal::class)
->createModal()
->withDialogRefName('my-dialog')
->withContent(<<<EOCONTENT
<div>
<h3>Example dialog that can be opened from anywhere using a function.</h3>
<pre class="my-4">
// To open this dialog call the function
window.openMyDialog();
</pre>
<button @click="hide" type="button" class="btn">Cancel</button>
</div>
EOCONTENT
);
Step 2: Render the modal and define the global function:
<div x-data="{
...hyva.modal(),
init() {
window.openMyDialog = function (event) {
this.show('my-dialog', event);
}.bind(this);
}
}" x-init="init()">
<?= $modal ?>
</div>
The init function, declared within x-data and merged with hyva.modal(), captures the component's scope. It's then called via x-init="init()" (automatically handled in Alpine v3).
Once set up, you can open the dialog from anywhere by calling window.openMyDialog().