Global state: Alpine.store
Data from x-data belongs to one component. When the same data is needed in different parts of the page — a task counter in the header and the list itself in the middle — it goes into a store. Alpine.store() creates a global data object, and any component reads and changes it through $store.
Creating a store
A store, like a component, is registered in an alpine:init handler:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('todos', {
items: ['Buy milk']
});
});
</script>
<header x-data>
Tasks: <span x-text="$store.todos.items.length"></span>
</header>
<main x-data>
<button @click="$store.todos.items.push('New task')">Add</button>
</main>The header and the button are two separate components. A click in one changes the number in the other: both work with the same todos store.
Methods and getters
A store can hold logic too. Inside its methods this points to the store itself:
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('todos', {
items: [
{ id: 1, title: 'Buy milk', done: true },
{ id: 2, title: 'Call Oleg', done: false }
],
get left() {
return this.items.filter(task => !task.done).length;
},
toggle(task) {
task.done = !task.done;
}
});
});
</script>
<p x-data x-text="'Left: ' + $store.todos.left"></p>
<ul x-data>
<template x-for="task in $store.todos.items" :key="task.id">
<li @click="$store.todos.toggle(task)" x-text="(task.done ? '✓ ' : '') + task.title"></li>
</template>
</ul>At the top you see "Left: 1". Clicking a task toggles its mark, and the number is recalculated.
The init() method
If a store has an init() method, Alpine calls it on registration. It is a good place to prepare initial data:
// index.html, inside the alpine:init handler
Alpine.store('todos', {
items: [],
init() {
this.items = [{ id: 1, title: 'Buy milk', done: false }];
}
});A store in an npm project
In src/main.js the store is registered before Alpine.start():
// src/main.js
import Alpine from 'alpinejs';
Alpine.store('todos', {
items: []
});
Alpine.start();From plain JavaScript outside the markup, the store is read the same way: Alpine.store('todos').items.
Component or store
| Data | Where to keep it |
|---|---|
| Needed by one block: is the menu open, the field text | x-data |
| Needed by several blocks: tasks, the user, the theme | Alpine.store |
Common mistake
Using $store on an element without x-data. Like every directive, x-text="$store.todos.left" works only inside a component. Give a standalone element that only needs store data an empty x-data, like the <header> in the first example.