Skip to main content
Version: 2.0.0

Working with Alpine.js

yStore storefronts use Alpine.js v3 for all client-side reactivity. Alpine.js is initialized globally and yStore's templates are built around its directives.

Alpine.js version

yStore uses Alpine.js v3. If you are looking at external tutorials, make sure they target v3 — the API changed significantly from v2.

Core directives you'll use

DirectivePurpose
x-dataDefine a component's reactive data and methods
x-bindBind HTML attributes to data values
x-on / @Listen for events
x-showConditionally show/hide an element
x-ifConditionally render an element (no DOM node when false)
x-forLoop over arrays
x-textSet element text content
x-modelTwo-way bind form inputs
x-refGet a reference to a DOM element
x-effectRun a side effect when data changes
x-initRun code on component initialization
x-deferyStore custom — lazy-load components (see below)

A minimal Alpine component

<div x-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<div x-show="open">
Hello from Alpine!
</div>
</div>

Calling a function on init

<div x-data="myComponent()" x-init="init()">
<p x-text="message"></p>
</div>

<script>
function myComponent() {
return {
message: '',
init() {
this.message = 'Loaded!';
}
};
}
</script>

Listening to yStore events

yStore dispatches custom window events that Alpine components can listen to:

<div x-data="{ count: 0 }"
@private-content-loaded.window="count = $event.detail.cart?.itemCount ?? 0">
<span x-text="count"></span> items in cart
</div>

See JavaScript Events for the full list of events yStore dispatches.

The x-defer directive

yStore ships a custom x-defer Alpine plugin for lazy-loading heavy components:

<!-- Load when element enters the viewport -->
<div x-data="heavyComponent()" x-defer="intersect">
...
</div>

<!-- Load after user first interacts with the page -->
<div x-data="heavyComponent()" x-defer="interact">
...
</div>

See x-defer Directive for all options.

Communication between Alpine components

Components cannot directly share state. Use window events instead:

<!-- Dispatcher -->
<button @click="$dispatch('cart-updated', { count: 3 })">Update</button>

<!-- Listener (different component on the same page) -->
<div x-data @cart-updated.window="count = $event.detail.count">...</div>

See Patterns → Communication Between Alpine Components for more examples.

Useful resources