Writing Alpine v2 and v3 Compatible Code
Extension developers often need to support both Alpine.js v2 and v3.
It's straightforward to write Alpine components that work with both versions. This guide outlines key considerations for maintaining compatibility across Hyvä versions.
x-spread and x-bind
Alpine.js v2 uses x-spread, while v3 uses x-bind. To ensure compatibility, include both attributes:
<div
class="fixed inset-0 z-30 flex items-center justify-center text-left"
x-spread="overlay()"
x-bind="overlay()"
x-cloak
>
... the other modal code here ...
</div>
Using $el
In Alpine v2, $el always referred to the component's root DOM element. In v3, it refers to the DOM element of the currently evaluated binding.
For v2 and v3 compatibility, only use $el on the component's base element. To reference other elements, use x-ref or querySelector():
<div x-data="{ result: 0 }">
<button
x-ref="btn"
data-value="6"
@click="result += parseInt($refs.btn.dataset.value)"
>...<button>
</div>
Using $root
In Alpine v2, $root is unavailable. The recommended approach is to avoid using it. Alternatively, alias it in an init method for v2 compatibility:
<div
x-data="{
init(root) {
if (!this.$root) this.$root = root;
}
}"
x-init="init($el)"
>
...
</div>
Using x-init
Alpine.js v2 requires explicit x-init calls for initialization functions. In v3, an init method is called automatically. For v2 compatibility, always explicitly use x-init="init" instead of relying on implicit calls.
@click.away or @click.outside
Alpine v2's click.away modifier was renamed to click.outside in v3. To support both versions, use both modifiers:
Using Alpine plugins
Alpine.js v3 includes many native plugins and offers an improved API for custom plugin development.
For cross-version compatibility, avoid plugins unless they are available for both Alpine versions. The intersect plugin is an exception: it's native to v3, and Hyvä provides a v2 backport, making x-intersect="..." safe to use universally.
For other plugins, you'll likely need to backport them to v2 and manage version loading (see below).
Rendering templates depending on the Alpine version
The etc/hyva-libraries.json theme file defines which library versions to load. Use the \Hyva\Theme\ViewModel\ThemeLibrariesConfig::getVersionIdFor view model method to retrieve these versions. This determines both the Alpine.js and intersect plugin versions for a theme:
<?php
/** @var Template $block */
/** @var ViewModelRegistry $viewModels */
use Hyva\Theme\Model\ViewModelRegistry;
use Hyva\Theme\ViewModel\ThemeLibrariesConfig;
use Magento\Framework\View\Element\Template;
$themeLibrary = $viewModels->require(ThemeLibrariesConfig::class);
$version = $themeLibrary->getVersionIdFor('intersect-plugin')
?: $themeLibrary->getVersionIdFor('alpine')
?: '2';
?>
<?= /** @noEscape */ $block->fetchView($block->getTemplateFile("Hyva_Theme::page/js/plugins/v${version}/intersect.phtml")) ?>
This code first checks for a specific intersect-plugin version. If not found, it checks for an Alpine.js version. If neither is specified (e.g., no `etc/hyva-libraries.json` file), it defaults to version `2`. The determined version then constructs the template file path for rendering.
Apply this pattern to render custom JavaScript based on the theme's Alpine version.
Warning if the Alpine version is too old
If your module only supports a single Alpine.js version, clearly state this in the module's README and documentation. Note that a Magento instance might use different Alpine versions across store views with different themes.
To declare a minimum Alpine version dependency, add a child block to the require-alpine-v3 block using layout XML:
<body>
<referenceBlock name="require-alpine-v3">
<block name="My_Module"/>
</referenceBlock>
</body>
If this module is used with a theme running an older Alpine version, a warning will be logged to the browser console:
The current Alpine.js version is 2.8.2, but version >= 3 is required by the following extensions:
[
'My_Module'
]
The child block's name should match your module name, as it appears in the error message.
This approach only declares a minimum version
There's no generic way to warn if a higher Alpine version is present (e.g., requiring v2 but v3 is used).