von x-data bis x-teleport vollständig erklärt
Alpine.js v3 bietet 15 Direktiven, 6 magische Properties und 3 globale Methoden. Wer alle davon kennt und den richtigen Einsatzort versteht, schreibt interaktive UIs ohne Build-Step, ohne Virtual DOM und ohne die Komplexität großer Frameworks – direkt im HTML, reaktiv und wartbar.
Inhaltsverzeichnis
- 1. Warum Alpine.js v3 eine vollständige Direktiven-Übersicht verdient
- 2. x-data: Der Ursprung jedes reaktiven Kontexts
- 3. x-bind und x-on: Attribute und Events deklarativ verdrahten
- 4. x-model: Two-Way-Binding für Formulare
- 5. x-show vs. x-if: Sichtbarkeit und DOM-Präsenz
- 6. x-for: Listen reaktiv rendern
- 7. x-transition: Animationen ohne CSS-Klassen-Chaos
- 8. x-effect und x-ref: Seiteneffekte und DOM-Zugriff
- 9. x-teleport und x-ignore: Fortgeschrittene DOM-Kontrolle
- 10. Zusammenfassung und Entscheidungshilfe
- 11. FAQ
1. Warum Alpine.js v3 eine vollständige Direktiven-Übersicht verdient
Alpine.js v3 wurde im Mai 2021 veröffentlicht und hat sich seitdem als das bevorzugte Framework für serverseitig gerenderte Templates etabliert – besonders in Verbindung mit Laravel Blade, Hyvä Themes und ähnlichen Stacks, die kein clientseitiges Routing benötigen. Der entscheidende Unterschied zu React, Vue und Angular: Alpine.js manipuliert kein Shadow-DOM, erzeugt kein Virtual-DOM-Diff und lädt keine Hydration-Payload. Stattdessen liest es Direktiven direkt aus bestehenden HTML-Attributen und macht ein Element genau dann reaktiv, wenn es das x-data-Attribut trägt.
Die 15 Direktiven von Alpine.js v3 decken das gesamte Spektrum interaktiver Web-UIs ab: Datenbindung, Eventhandling, Formulare, Listendarstellung, Animationen, DOM-Manipulation und Kontextübertragung. Wer alle kennt und weiß, wann welche Direktive die richtige Wahl ist, vermeidet häufige Fehler wie unnötige DOM-Entfernungen mit x-if statt eines einfachen x-show oder performanceschädigende Watcher durch x-effect mit zu breitem Zugriff. Dieser Artikel geht alle 15 Direktiven durch – mit konkreten Beispielen, Fallstricken und Entscheidungshilfen.
Für Hyvä-Theme-Entwickler ist eine vollständige Kenntnis der Alpine.js-Direktiven besonders relevant, weil Hyvä auf Alpine.js als einziges JavaScript-Framework setzt und jQuery, Knockout.js sowie Magento-UI-Components vollständig ersetzt. Jede interaktive Komponente – Minicart, Navigation, Modals, Formulare – nutzt Alpine.js-Direktiven. Wer diese Direktiven nicht vollständig kennt, schreibt entweder redundanten Code oder greift zu unnötigen JavaScript-Importen.
2. x-data: Der Ursprung jedes reaktiven Kontexts
x-data ist die wichtigste Direktive von Alpine.js und der Ausgangspunkt jedes reaktiven Kontexts. Jedes Element mit x-data wird zur Wurzel einer Alpine.js-Komponente. Der Wert von x-data ist ein JavaScript-Ausdruck, der ein Objekt zurückgibt – üblicherweise ein Objekt-Literal oder ein Funktionsaufruf. Alle Eigenschaften dieses Objekts werden reaktiv: Änderungen daran lösen automatisch DOM-Updates in allen Elementen aus, die über andere Direktiven auf dieselben Eigenschaften zugreifen.
Ab Alpine.js v3 kann x-data auch leer bleiben (x-data ohne Wert), wenn ein Element nur als Ereignis-Boundary oder als Container für andere Direktiven dient, die keinen eigenen State benötigen. Verschachtelte x-data-Elemente erzeugen eigene Scopes, die den Eltern-Scope per Prototypen-Vererbung erben – ein inneres Element kann auf die Daten des äußeren x-data zugreifen, aber nicht umgekehrt. Das ist ein fundamentaler Unterschied zu globalen Stores, die mit Alpine.store() angelegt werden und aus jedem Kontext erreichbar sind.
Für komplexere Komponenten empfiehlt sich das Auslagern in eine benannte Komponente via Alpine.data('meineName', () => ({ ... })). So bleibt die HTML-Datei lesbar, und die JavaScript-Logik ist in einer zentralen Datei testbar. In Hyvä-Templates ist dieses Muster Standard: Die Komponenten werden in einer .js-Datei registriert, das Template verwendet nur x-data="meineName()".
// Alpine.js v3 — x-data patterns
// 1. Inline object literal
// <div x-data="{ open: false, count: 0 }">
// 2. Named component (registered globally)
Alpine.data('dropdown', () => ({
open: false,
toggle() { this.open = !this.open },
close() { this.open = false },
// init() is called automatically when component initializes
init() {
this.$watch('open', val => {
document.body.classList.toggle('overflow-hidden', val)
})
}
}))
// <div x-data="dropdown()">
// 3. Global store — accessible from any Alpine context
Alpine.store('cart', {
items: [],
get count() { return this.items.length },
add(item) { this.items.push(item) }
})
// Access: $store.cart.count (from any x-data context)
// 4. Nested scope — child inherits parent data
// <div x-data="{ color: 'teal' }">
// <div x-data="{ size: 'lg' }">
// <!-- Both 'color' and 'size' are accessible here -->
// </div>
// </div>
3. x-bind und x-on: Attribute und Events deklarativ verdrahten
x-bind bindet den Wert eines HTML-Attributs an einen JavaScript-Ausdruck aus dem aktuellen Alpine-Scope. Das klassische Beispiel: x-bind:class="{ active: isActive }" fügt die Klasse active hinzu, wenn isActive wahr ist. Die Kurzschreibweise :class ist identisch mit x-bind:class und wird in der Praxis bevorzugt. x-bind funktioniert für alle HTML-Attribute: href, src, disabled, aria-expanded, style und sogar für SVG-Attribute. Besonders nützlich ist das dynamische Setzen von ARIA-Attributen für Accessibility – mehr dazu im eigenen Artikel dieser Serie.
x-on registriert Event-Listener deklarativ im HTML. Die Kurzschreibweise ist @click statt x-on:click. Alpine.js unterstützt dabei alle nativen DOM-Events sowie eigene benutzerdefinierte Events via $dispatch. Modifikatoren wie .prevent (ruft event.preventDefault() auf), .stop (stopPropagation), .window (bindet den Event an window), .once (entfernt den Listener nach dem ersten Aufruf) und .debounce.300ms reduzieren den Boilerplate-Code erheblich. Das Muster @keydown.escape.window="close()" zum Schließen von Modals mit der Escape-Taste ist ein prägnantes Beispiel für die Ausdrucksstärke dieser Modifikatoren.
4. x-model: Two-Way-Binding für Formulare
x-model implementiert bidirektionale Datenbindung für Formularelemente: Ändert sich der State, aktualisiert sich das Eingabefeld. Tippt der Nutzer, aktualisiert sich der State. Das funktioniert für <input>, <textarea>, <select>, Checkboxen und Radio-Buttons. Für Checkboxen bindet x-model an einen Boolean; wenn das Ziel ein Array ist, fügt es den Wert des Checkboxes hinzu oder entfernt ihn – ideal für Mehrfachauswahl ohne eigenen Event-Handler.
Der Modifikator .lazy verzögert die State-Aktualisierung bis zum change-Event statt bei jedem Tastendruck – sinnvoll für Validierungen, die nicht bei jedem Buchstaben laufen sollen. .debounce.500ms drosselt die Aktualisierungsrate für Live-Suchen und API-Anfragen. .number konvertiert den Eingabewert automatisch in einen JavaScript-Number-Typ statt ihn als String zu behandeln. .trim entfernt führende und nachfolgende Leerzeichen direkt bei der Eingabe. Diese Modifikatoren ersetzen in vielen Fällen explizite Event-Handler komplett.
5. x-show vs. x-if: Sichtbarkeit und DOM-Präsenz
Das ist eine der häufigsten Entscheidungen in Alpine.js-Templates und eine der am häufigsten falsch getroffenen. x-show setzt display: none oder entfernt diesen Style – das Element bleibt im DOM, wird nur visuell versteckt. x-if fügt das Element in den DOM ein oder entfernt es vollständig. Das hat weitreichende Konsequenzen: x-show ist performanter, wenn ein Element häufig ein- und ausgeblendet wird, weil kein DOM-Parsing und kein Event-Listener-Aufbau nötig ist. x-if ist sinnvoll, wenn das Element initial nicht gerendert werden soll (z.B. ein Modal, das selten geöffnet wird) oder wenn es teure Kind-Komponenten enthält, die nicht initialisiert werden sollen, während es ausgeblendet ist.
Ein kritischer Unterschied: x-if muss auf einem <template>-Element stehen, nicht auf dem Element selbst. Das ist ein häufiger Fehler beim Umstieg von Vue.js, wo v-if direkt auf dem Element sitzt. Mit x-show in Kombination mit x-transition entstehen flüssige Ein- und Ausblendanimationen ohne zusätzliche CSS-Klassen. x-if dagegen triggert die Transition nur beim Einfügen, nicht beim Entfernen, es sei denn, man verwendet x-transition:leave explizit.
6. x-for: Listen reaktiv rendern
x-for rendert ein Template-Element für jeden Eintrag eines Arrays oder Objekts. Wie x-if muss x-for zwingend auf einem <template>-Element stehen. Die Syntax x-for="item in items" ist die Grundform; x-for="(item, index) in items" gibt zusätzlich den Index zurück; x-for="(value, key) in object" iteriert über Objekte. Das :key-Attribut ist technisch optional, aber in der Praxis unverzichtbar: Es gibt Alpine.js einen stabilen Bezeichner, anhand dessen es DOM-Knoten bei Listenänderungen wiederverwenden statt neu erstellen kann – das ist der Unterschied zwischen flüssigen und ruckelnden Listenaktualisierungen.
x-for reagiert auf alle reaktiven Array-Mutationen: push(), pop(), splice() und direkte Index-Zuweisung. Für Filterlisten empfiehlt sich ein berechnetes Getter-Property im x-data-Objekt: get filteredItems() { return this.items.filter(i => i.active) }. Alpine.js erkennt, dass filteredItems von items abhängt, und aktualisiert die Liste automatisch. Das ist sauberer als das Pflegen einer separaten gefilterten Array-Variable mit explizitem Watcher.
// Alpine.js v3 — x-for with filtering and key binding
Alpine.data('productList', () => ({
search: '',
products: [
{ id: 1, name: 'Alpenjacke', active: true, price: 129 },
{ id: 2, name: 'Wanderhose', active: true, price: 89 },
{ id: 3, name: 'Regenschutz', active: false, price: 59 },
],
// Computed getter — Alpine auto-tracks dependencies
get filtered() {
const q = this.search.toLowerCase()
return this.products.filter(p =>
p.active && p.name.toLowerCase().includes(q)
)
},
toggleActive(id) {
const p = this.products.find(p => p.id === id)
if (p) p.active = !p.active
}
}))
/* Template:
<div x-data="productList()">
<input x-model.debounce.300ms="search" placeholder="Suche...">
<template x-for="product in filtered" :key="product.id">
<div x-text="product.name + ' — ' + product.price + '€'"></div>
</template>
</div>
*/
7. x-transition: Animationen ohne CSS-Klassen-Chaos
x-transition fügt CSS-Transitions zu Elementen hinzu, die mit x-show oder x-if ein- und ausgeblendet werden. In der einfachsten Form reicht das Attribut x-transition ohne Wert aus – Alpine.js wendet dabei eine Standard-Opacity-und-Scale-Transition an. Für eigene Animationen gibt es sechs Phasen-Modifikatoren: :enter, :enter-start, :enter-end, :leave, :leave-start und :leave-end. Jeder nimmt Tailwind-Klassen als Wert, die Alpine.js im richtigen Moment setzt und wieder entfernt.
Das Muster für ein klassisches Dropdown: x-transition:enter="transition ease-out duration-200", x-transition:enter-start="opacity-0 scale-95", x-transition:enter-end="opacity-100 scale-100". Diese sechs Attribute ersetzen komplexe Animations-Libraries für die allermeisten UI-Patterns. Alternativ kann x-transition einen CSS-Klassen-Namen als Wert bekommen: x-transition="fade" erwartet dann Klassen wie fade-enter-active, fade-leave-active nach dem Vue-Muster – nützlich für Teams, die von Vue.js migrieren.
8. x-effect und x-ref: Seiteneffekte und DOM-Zugriff
x-effect ist die Alpine.js-Antwort auf React's useEffect ohne Dependency-Array. Der Ausdruck in x-effect wird sofort einmal ausgeführt und danach jedes Mal, wenn sich eine reactive Property ändert, die im Ausdruck gelesen wurde. Das Tracking passiert automatisch – man muss keine Dependency-Liste pflegen. Das macht x-effect ideal für Seiteneffekte wie das Synchronisieren von State mit localStorage, das Setzen eines document.title oder das Auslösen einer API-Anfrage bei Filteränderungen. Wichtig: x-effect hat keinen Cleanup-Mechanismus; für Seiteneffekte, die bereinigt werden müssen (z.B. Event-Listener, Timer), gehört die Logik in init() mit manueller Cleanup-Logik.
x-ref gibt einem Element einen Namen, über den es aus dem Alpine-Scope per $refs.name direkt zugänglich ist. Das ist der Alpine.js-Äquivalent zu document.getElementById() oder React's useRef. Typische Anwendungsfälle: ein Eingabefeld nach dem Öffnen eines Modals fokussieren (this.$refs.input.focus()), den Scroll-Offset eines Container-Elements lesen oder ein Canvas-Element für Zeichenoperationen ansprechen. $refs ist nur innerhalb derselben Alpine-Komponente sichtbar – kein Global-Scope-Problem.
// Alpine.js v3 — x-effect, x-ref, $watch, $nextTick
Alpine.data('searchBox', () => ({
query: '',
results: [],
loading: false,
init() {
// $watch: explicit watcher with old/new value
this.$watch('query', async (val) => {
if (val.length < 2) { this.results = []; return }
this.loading = true
this.results = await this.fetchResults(val)
this.loading = false
// $nextTick: run after DOM update
this.$nextTick(() => this.$refs.resultList.scrollTop = 0)
})
},
async fetchResults(q) {
const res = await fetch(`/api/search?q=${encodeURIComponent(q)}`)
return res.json()
},
clear() {
this.query = ''
// Focus input after clearing
this.$nextTick(() => this.$refs.input.focus())
}
}))
/* x-effect example — auto-sync to localStorage */
// x-effect="localStorage.setItem('theme', darkMode ? 'dark' : 'light')"
// Runs immediately and whenever darkMode changes — no watcher boilerplate
9. x-teleport und x-ignore: Fortgeschrittene DOM-Kontrolle
x-teleport ist eine der neueren Direktiven von Alpine.js v3 und löst ein klassisches Problem: Ein Modal oder ein Tooltip muss an einer anderen Stelle im DOM erscheinen als sein auslösendes Element. Ohne Teleport würde ein Modal, das tief in einem gestapelten position: relative-Container liegt, durch z-index-Probleme und overflow: hidden abgeschnitten werden. Mit x-teleport="#modal-root" auf einem <template>-Element wird dessen Inhalt in das angegebene Ziel-Element verschoben – aber der Alpine.js-Scope bleibt verbunden. Das bedeutet: Der teleportierte Inhalt kann auf die Daten der Quell-Komponente zugreifen und Events in beide Richtungen senden.
x-ignore ist das Gegenstück: Es weist Alpine.js an, ein Element und alle seine Kinder vollständig zu ignorieren – keine Direktiven werden verarbeitet, kein reaktiver Kontext wird erstellt. Das ist nützlich für Elemente mit Server-seitig gerenderten Code-Blöcken, für Drittanbieter-Widgets, die ihren eigenen DOM-Baum verwalten (z.B. eine eingebettete Karte oder ein Rich-Text-Editor), oder für rohe Template-HTML, das erst per JavaScript initialisiert wird. Ohne x-ignore würde Alpine.js versuchen, Alpine-Direktiven in diesem Bereich zu interpretieren, was zu Fehlern oder unerwünschtem Verhalten führen kann.
10. Zusammenfassung und Entscheidungshilfe
Die 15 Alpine.js v3 Direktiven lassen sich in vier Gruppen einteilen: State & Scope (x-data), Binding (x-bind, x-model, x-text, x-html), Rendering (x-show, x-if, x-for, x-transition, x-cloak) und Utilities (x-on, x-effect, x-ref, x-id, x-teleport, x-ignore). Die wichtigste Entscheidungsfrage für Rendering: Wird das Element häufig ein- und ausgeblendet? Dann x-show. Wird es selten gezeigt oder enthält teure Kinder? Dann x-if.
Für Hyvä-Entwickler ist x-cloak besonders relevant: Es verhindert den sogenannten FOUC (Flash of Unstyled Content), bei dem Alpine.js-Templates kurz mit Direktiven-Attributen sichtbar werden, bevor Alpine.js initialisiert ist. Die Regel [x-cloak] { display: none !important } im CSS und das Attribut x-cloak auf der Komponente lösen das Problem vollständig. In Magento-Hyvä-Templates ist dieses Pattern in jedem Produktions-Deployment unerlässlich.
| Direktive | Zweck | Kurzform | Typischer Einsatz |
|---|---|---|---|
x-data |
Reaktiver Scope | — | Jede Alpine-Komponente |
x-bind |
Attribut-Binding | :attr |
class, style, aria-*, disabled |
x-on |
Event-Listener | @event |
click, input, keydown.escape |
x-show |
display:none toggle | — | Häufig togglebare Elemente |
x-if |
DOM-Einfügen/Entfernen | auf <template> | Seltene Elemente, teure Kinder |
Mironsoft
Alpine.js, Hyvä Themes und Magento 2 Frontend-Entwicklung
Alpine.js-Komponenten für euren Hyvä-Shop?
Wir entwickeln performante, barrierefreie Alpine.js-Komponenten für Magento 2 Hyvä-Themes – von der Minicart bis zur erweiterten Produktliste, mit vollem Alpine.js v3 Feature-Set und Tailwind CSS v4.
Komponenten-Entwicklung
Individuelle Alpine.js-Komponenten für Hyvä Themes – vollständig reaktiv und barrierefrei
Code-Review
Bestehende Alpine.js-Implementierungen auf Performance, Korrektheit und Accessibility prüfen
Migration
Bestehende Knockout.js / jQuery-Lösungen auf Alpine.js v3 und Hyvä migrieren
Alpine.js v3 Direktiven — Das Wichtigste auf einen Blick
State & Scope
x-data startet jede Komponente. Benannte Komponenten via Alpine.data() und globale Stores via Alpine.store() halten großen State sauber organisiert.
x-show vs. x-if
x-show für häufige Toggles (DOM bleibt), x-if auf <template> für seltene oder teure Elemente (DOM wird entfernt). Falsche Wahl kostet Performance.
Modifikatoren
@click.prevent, .stop, .window, .once, .debounce.300ms und x-model.lazy, .number, .trim reduzieren Event-Boilerplate auf ein Minimum.
Fortgeschrittene Direktiven
x-teleport löst z-index-Probleme bei Modals. x-ignore schützt Drittanbieter-Widgets. x-cloak verhindert FOUC vor Alpine-Initialisierung.