x-data
Alpine
Alpine.js · x-collapse · Animation · Akkordeon
Alpine.js x-collapse:
Smooth Akkordeon-Animation ohne CSS-Hack

Der max-height-Trick funktioniert, sieht aber nie wirklich flüssig aus. Alpine.js x-collapse animiert die tatsächliche Inhaltshöhe, reagiert auf dynamische Inhalte und integriert sich nahtlos in Alpine-State – ohne eine einzige Zeile eigenes JavaScript.

10 Min. Lesezeit x-collapse · x-show · x-transition · Akkordeon · FAQ Alpine.js 3.x · Hyvä Themes

1. Das Problem mit dem max-height-Hack

Wer Inhalte im Browser per CSS animieren will, stößt schnell auf ein fundamentales Limit: height: auto lässt sich nicht animieren. CSS-Transitions funktionieren nur zwischen zwei messbaren Werten. Der klassische Workaround ist der max-height-Hack: Man setzt max-height: 0 für den geschlossenen Zustand und einen großzügig geschätzten Wert wie max-height: 1000px für den geöffneten Zustand. CSS animiert dann diesen Maximalwert, nicht die echte Höhe. Das Ergebnis ist ein verzögerter Eingangseffekt beim Öffnen und ein abruptes Schließen, weil der Browser von 1000px auf 0 animiert – obwohl der Inhalt vielleicht nur 200px hoch ist.

In der Praxis entstehen dabei zwei konkrete Probleme. Erstens: Ist der geschätzte max-height-Wert zu klein, wird der Inhalt abgeschnitten. Ist er zu groß, entsteht eine deutlich sichtbare Easing-Verzögerung, weil die Animation bei einem viel höheren Wert als dem tatsächlichen Inhalt beginnt zu bremsen. Zweitens: Bei dynamisch geladenem Inhalt – etwa durch eine API-Antwort, die mehr Text liefert als erwartet – versagt der Hack vollständig. Man müsste max-height per JavaScript dynamisch setzen und landet damit exakt dort, wo Alpine.js x-collapse bereits eine saubere Lösung bietet.

Viele Entwickler greifen in diesem Moment zu jQuery-Animationen mit slideDown() und slideUp(). Diese Methoden messen die echte Höhe und animieren sie korrekt – aber sie bringen jQuery als Abhängigkeit mit, was in modernen Projekten wie Hyvä Themes, die bewusst auf jQuery verzichten, keine Option ist. Alpine.js x-collapse schließt diese Lücke: echte Höhenanimation, kein jQuery, keine eigene Logik.

2. Was x-collapse leistet und wie es intern funktioniert

Alpine.js x-collapse ist ein offizielles Plugin, das als separate npm-Paket oder CDN-Script ausgeliefert wird. Es registriert eine neue Direktive x-collapse, die auf ein Element angewendet wird und dessen Höhe in Abhängigkeit von einem booleschen Alpine-State animiert. Intern verwendet das Plugin die Web Animations API, um die tatsächlich gemessene Inhaltshöhe (scrollHeight) als Animationsziel zu verwenden. Das bedeutet: Egal wie hoch der Inhalt tatsächlich ist, die Animation läuft immer genau bis zur echten Grenze.

Das Plugin übernimmt auch den overflow: hidden-Stil während der Animation, sodass kein Inhalt außerhalb des animierten Bereichs sichtbar wird. Nach Abschluss der Öffnungsanimation wird overflow auf visible zurückgesetzt – wichtig für Inhalte, die z.B. Tooltips oder Dropdowns enthalten, die über den Panel-Rand hinausragen. Das Zusammenspiel mit x-show ist nahtlos: x-collapse erweitert das Verhalten von x-show und ersetzt die Standard-Transition des Direktives durch die gemessene Höhenanimation. Der Entwickler muss keine weiteren Konfigurationen vornehmen.

3. Installation und Einbindung in Alpine.js

Das Plugin kann entweder über npm installiert oder direkt per CDN eingebunden werden. In Projekten mit einem Build-Prozess – wie es in Hyvä Themes mit Tailwind CSS der Fall ist – ist die npm-Variante die sauberere Wahl, weil sie Tree-Shaking ermöglicht und keine externe Netzwerkanfrage erfordert. Das Plugin wird nach Alpine.js importiert und vor dem Start von Alpine registriert. Die Reihenfolge ist entscheidend: Alpine muss über das Plugin informiert sein, bevor es mit der DOM-Initialisierung beginnt.


// main.js — Alpine.js mit x-collapse Plugin initialisieren
import Alpine from 'alpinejs';
import Collapse from '@alpinejs/collapse';

// Register plugin before Alpine starts
Alpine.plugin(Collapse);

// Start Alpine
window.Alpine = Alpine;
Alpine.start();

// CDN-Alternative (kein Build-Prozess):
// <script defer src="https://cdn.jsdelivr.net/npm/@alpinejs/collapse@3.x.x/dist/cdn.min.js"></script>
// <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
// Reihenfolge: x-collapse ZUERST, dann Alpine (CDN-Reihenfolge ist umgekehrt zur defer-Auflösung)

In Hyvä Themes wird Alpine.js typischerweise über das Theme-eigene Bundling eingebunden. Das Plugin lässt sich dort in der hyva-themes/magento2-default-theme-Konfiguration als zusätzlicher Import hinzufügen. Wer die CDN-Variante bevorzugt, muss auf die Ladereihenfolge achten: Da beide Scripts defer tragen, lädt der Browser sie in der Reihenfolge ihrer Script-Tags – das Collapse-Plugin muss daher im HTML vor dem Alpine-Hauptscript stehen, obwohl es logisch eine Erweiterung ist.

4. Ein einfaches Akkordeon mit x-collapse aufbauen

Das einfachste Anwendungsszenario ist ein einzelnes ausklappbares Panel. Ein Button steuert den booleschen State, ein Container-Element trägt x-show in Kombination mit x-collapse. Mehr braucht es nicht. Das Ergebnis ist eine flüssige Höhenanimation beim Öffnen und Schließen, die auf die tatsächliche Inhaltshöhe reagiert. Der Button bekommt @click="open = !open", das Panel x-show="open" und x-collapse – beide Direktiven auf demselben Element.


<!-- Einfaches ausklappbares Panel mit x-collapse -->
<div x-data="{ open: false }">
  <button
    @click="open = !open"
    :aria-expanded="open"
    class="flex items-center justify-between w-full px-6 py-4 font-semibold text-left bg-white border border-slate-200 rounded-xl hover:bg-slate-50"
  >
    <span>Was ist Alpine.js x-collapse?</span>
    <svg
      class="w-5 h-5 transition-transform duration-300"
      :class="{ 'rotate-180': open }"
      fill="none" stroke="currentColor" viewBox="0 0 24 24"
    >
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"/>
    </svg>
  </button>
  <div
    x-show="open"
    x-collapse
    class="overflow-hidden"
  >
    <div class="px-6 py-4 text-slate-600 border border-t-0 border-slate-200 rounded-b-xl bg-slate-50">
      x-collapse ist ein offizielles Alpine.js Plugin, das Höhenübergänge mit
      der echten scrollHeight animiert – kein max-height-Schätzen erforderlich.
    </div>
  </div>
</div>

Wichtig: x-collapse und x-show müssen auf demselben Element stehen. Das Plugin erweitert intern die Transition-Logik von x-show. Wer die Direktiven auf verschiedene Elemente verteilt, erhält keine Animation. Das Wrapper-Element, das x-collapse trägt, sollte kein eigenes padding oder margin haben, da diese Eigenschaften die Höhenmessung beeinflussen. Stattdessen gibt man dem inneren Inhaltselement das Padding.

5. Exklusives Akkordeon: nur ein Panel gleichzeitig offen

Ein klassisches Akkordeon, bei dem immer nur ein Panel geöffnet sein kann, erfordert einen geteilten State auf der übergeordneten Komponente. Statt eines separaten open-Booleans pro Panel speichert man den Index des aktuell geöffneten Panels. Jedes Panel prüft, ob sein Index mit dem gespeicherten übereinstimmt. Beim Klick wird der Index entweder auf den eigenen Wert gesetzt oder auf null zurückgesetzt – so kann ein Klick auf ein bereits geöffnetes Panel es wieder schließen.

Dieses Muster lässt sich sauber mit x-for über ein Array von Panel-Definitionen umsetzen, sodass kein HTML für jedes Panel separat geschrieben werden muss. Die Daten werden in x-data als Array von Objekten mit title und content definiert. Dieser Ansatz ist besonders bei CMS-gesteuerten Inhalten wertvoll, wo die Anzahl der Panels variiert.

6. Animationsgeschwindigkeit und Easing anpassen

Standardmäßig verwendet x-collapse eine Animationsdauer von 250 Millisekunden mit einem einfachen Easing. Für die meisten UI-Kontexte ist das angemessen, aber in manchen Designs – etwa bei sehr kleinen Panels oder bei einer bewusst lebhafteren Benutzeroberfläche – möchte man die Dauer oder das Easing anpassen. Das Plugin unterstützt dafür den Modifier x-collapse.duration.Xms, wobei X die gewünschte Dauer in Millisekunden ist.


<!-- Animationsgeschwindigkeit mit duration-Modifier anpassen -->
<div x-data="{ open: false }">
  <button @click="open = !open" :aria-expanded="open" class="w-full text-left px-6 py-4 font-semibold">
    Panel mit 500ms Animation
  </button>

  <!-- Standard: 250ms -->
  <div x-show="open" x-collapse>
    <p class="px-6 py-4">Standardgeschwindigkeit: 250 Millisekunden.</p>
  </div>
</div>

<div x-data="{ open: false }">
  <button @click="open = !open" :aria-expanded="open" class="w-full text-left px-6 py-4 font-semibold">
    Langsames Panel
  </button>

  <!-- Benutzerdefiniert: 600ms -->
  <div x-show="open" x-collapse.duration.600ms>
    <p class="px-6 py-4">Langsamere Animation für dramatischere Übergänge.</p>
  </div>
</div>

<!-- Für Nutzer mit prefers-reduced-motion: in CSS deaktivieren -->
<style>
@media (prefers-reduced-motion: reduce) {
  [x-collapse] { transition-duration: 0ms !important; }
}
</style>

Die prefers-reduced-motion-Media-Query ist bei Animationen Pflicht für barrierefreie Implementierungen. Nutzer, die Bewegungsreduktion in ihren Systemeinstellungen aktiviert haben, profitieren von sofortigen Übergängen ohne Verzögerung. Das CSS-Override lässt sich alternativ direkt in der Tailwind-Konfiguration als Utility-Klasse abbilden.

7. Dynamische Inhalte und asynchrones Laden

Einer der größten Vorteile von x-collapse gegenüber dem max-height-Hack zeigt sich bei dynamisch geladenem Inhalt. Wenn ein Panel nach dem ersten Öffnen zusätzlichen Inhalt nachladen soll – etwa durch einen API-Request, der weitere Details liefert – muss die Höhenanimation auf die neue Inhaltsgröße reagieren. Mit dem max-height-Hack müsste man den Wert nach dem Laden neu setzen. Mit x-collapse geschieht das automatisch, weil das Plugin bei jeder Öffnungsanimation die aktuelle scrollHeight neu misst.

Das Muster für asynchrones Laden kombiniert x-collapse mit Alpine's fetch-Integration und einem Ladezustand. Beim ersten Öffnen wird der Fetch gestartet, der Inhalt wird nach der Antwort in den State geschrieben, und Alpine re-rendert das Panel mit dem neuen Inhalt. Eine erneute Öffnung des Panels triggert keinen zweiten Fetch, wenn der Inhalt bereits gecacht ist.

8. Barrierefreiheit: aria-expanded und Tastaturnavigation

Barrierefreie Akkordeons erfordern mehr als nur visuelle Animation. Screenreader müssen über den Zustand jedes Panels informiert werden. Das aria-expanded-Attribut auf dem Trigger-Button kommuniziert den Öffnungszustand. Mit Alpine.js ist das einfach: :aria-expanded="open" bindet den State direkt als ARIA-Attribut. Screenreader lesen dann "ausklappbar, geöffnet" oder "ausklappbar, geschlossen" vor, wenn der Nutzer den Button fokussiert.


<!-- Barrierefreies Akkordeon mit vollständiger ARIA-Unterstützung -->
<div x-data="{ activePanel: null }" class="space-y-2">
  <template x-for="(panel, index) in [
    { id: 'p1', title: 'Lieferzeit', content: 'Wir liefern innerhalb von 2-3 Werktagen.' },
    { id: 'p2', title: 'Rückgabe', content: '30 Tage Rückgaberecht ohne Angabe von Gründen.' },
    { id: 'p3', title: 'Zahlung', content: 'Rechnung, Kreditkarte, PayPal und Sofortüberweisung.' }
  ]" :key="panel.id">
    <div class="border border-slate-200 rounded-xl overflow-hidden">
      <button
        :id="'trigger-' + panel.id"
        :aria-controls="'panel-' + panel.id"
        :aria-expanded="activePanel === index"
        @click="activePanel = activePanel === index ? null : index"
        class="flex items-center justify-between w-full px-6 py-4 font-semibold text-left hover:bg-slate-50"
      >
        <span x-text="panel.title"></span>
        <span aria-hidden="true" class="text-teal-700 font-mono transition-transform duration-200"
              :class="activePanel === index ? 'rotate-45' : ''" >+</span>
      </button>
      <div
        :id="'panel-' + panel.id"
        :aria-labelledby="'trigger-' + panel.id"
        role="region"
        x-show="activePanel === index"
        x-collapse
      >
        <p class="px-6 py-4 text-slate-600 border-t border-slate-100" x-text="panel.content"></p>
      </div>
    </div>
  </template>
</div>

Die role="region"-Zuordnung und die Verknüpfung von Button und Panel über aria-controls/aria-labelledby erfüllen die ARIA Authoring Practices für Disclosure-Widgets. Die Tastaturnavigation funktioniert automatisch, weil echte <button>-Elemente standardmäßig per Tab fokussierbar und per Enter/Space aktivierbar sind.

9. x-collapse vs. max-height vs. x-transition im Vergleich

Die Wahl zwischen den drei Ansätzen hängt vom konkreten Anwendungsfall ab. Für einfache Fade-Effekte ohne Höhenänderung ist x-transition ausreichend. Für Höhenanimationen bei statischem Inhalt mit bekannter maximaler Höhe funktioniert der max-height-Hack tolerierbar. Sobald der Inhalt dynamisch ist oder die Animation wirklich flüssig sein muss, führt kein Weg an x-collapse vorbei.

Kriterium max-height CSS x-transition x-collapse
Echte Höhenanimation Nein (Schätzwert) Nein (nur opacity/scale) Ja (scrollHeight)
Dynamischer Inhalt Problematisch Nicht relevant Vollständig unterstützt
Kein eigenes JS nötig Ja Ja Ja (Plugin)
Overflow nach Animation hidden (manuell ändern) Nicht betroffen Automatisch visible
Alpine-Integration Extern via :class Native Native (Plugin)

In der Praxis empfiehlt sich x-collapse für alle UI-Elemente, bei denen Inhalte sichtbar aus- und eingeblendet werden: Akkordeons, FAQ-Bereiche, Produktbeschreibungen im E-Commerce, Filter-Panels und Navigation-Submenüs. Der Overhead des Plugins ist minimal – die komprimierte CDN-Version wiegt unter 1 KB.

Mironsoft

Alpine.js, Hyvä Themes und Magento 2 Frontend-Entwicklung

Flüssige UI-Animationen für euren Magento-Shop?

Wir implementieren barrierefreie Alpine.js Komponenten mit x-collapse, x-intersect und Alpine Plugins – performant, ohne jQuery und vollständig in Hyvä Themes integriert.

Akkordeon-Komponenten

FAQ, Produktdetails und Filter-Panels mit x-collapse und vollständiger ARIA-Unterstützung

Alpine.js Plugin-Setup

Saubere Integration von x-collapse, x-intersect und Focus in den Hyvä Build-Prozess

Performance-Audit

Analyse bestehender Animationen, Ersatz von jQuery-Abhängigkeiten durch Alpine.js

10. Zusammenfassung

Das Alpine.js Plugin x-collapse löst ein seit Jahren bestehendes Problem in der Frontend-Entwicklung: die zuverlässige und flüssige Animation von Elementen mit variabler Höhe. Statt auf den max-height-Hack mit seinen bekannten Schwächen zu setzen oder jQuery wieder einzuführen, bietet x-collapse eine saubere, deklarative Lösung direkt in Alpine.js. Das Plugin misst die echte scrollHeight, animiert dorthin und setzt nach der Animation den Overflow korrekt zurück.

Die Einbindung erfordert wenige Zeilen – Plugin registrieren, x-collapse neben x-show auf das Element schreiben, fertig. Barrierefreiheit wird durch aria-expanded und role="region" sichergestellt. Für die Animationsdauer steht der duration-Modifier bereit. Exklusive Akkordeons mit nur einem geöffneten Panel lassen sich mit einem Index-basierten State auf dem übergeordneten Container elegant abbilden. Wer Akkordeons, FAQ-Bereiche oder Filter-Panels in Alpine.js baut, sollte x-collapse als Standard einsetzen.

x-collapse — Das Wichtigste auf einen Blick

Echte Höhenanimation

Misst scrollHeight und animiert dorthin – kein Schätzwert, kein Layout-Shift, auch bei dynamischen Inhalten korrekt.

Einfache Syntax

x-show="open" x-collapse auf demselben Element – mehr braucht es nicht für flüssige Höhenübergänge.

Barrierefreiheit

:aria-expanded="open" auf dem Trigger-Button kommuniziert den Zustand an Screenreader – Pflicht für zugängliche Akkordeons.

Duration-Modifier

x-collapse.duration.600ms passt die Animationsdauer an. prefers-reduced-motion per CSS für barrierefreie Bewegungsreduktion.

11. FAQ: Alpine.js x-collapse

1Was ist Alpine.js x-collapse?
Offizielles Alpine.js Plugin für Höhenanimationen – misst scrollHeight und verwendet Web Animations API. Kein max-height-Schätzen, kein manuelles JavaScript.
2x-collapse und x-show auf dasselbe Element?
Ja, Pflicht. x-collapse erweitert die x-show Transition-Logik intern. Verschiedene Elemente = keine Animation.
3Installation via npm oder CDN?
npm: Alpine.plugin(Collapse) vor Alpine.start(). CDN: Plugin-Script vor Alpine-Script (beide defer, Reihenfolge im HTML entscheidet).
4Animationsgeschwindigkeit anpassen?
x-collapse.duration.Xms – Standard 250ms. prefers-reduced-motion per CSS für barrierefreie Bewegungsreduktion berücksichtigen.
5Dynamisch geladener Inhalt kein Problem?
Ja. scrollHeight wird bei jeder Animation neu gemessen. Nachgeladener Inhalt ändert den Zielwert automatisch.
6Warum max-height-Hack problematisch?
Animiert Schätzwert, nicht echte Höhe. Zu klein: Inhalt abgeschnitten. Zu groß: sichtbare Easing-Verzögerung. Dynamischer Inhalt: vollständiger Ausfall.
7Exklusives Akkordeon bauen?
activePanel: null im übergeordneten x-data. x-show="activePanel === index". Klick: activePanel = activePanel === index ? null : index.
8Was passiert mit overflow nach der Animation?
Während Animation: hidden. Nach Öffnung: automatisch visible. Tooltips und Dropdowns im Panel funktionieren korrekt.
9Barrierefreiheit sicherstellen?
:aria-expanded="open" auf Button. role="region" und aria-labelledby auf Panel. Echte button-Elemente für Tastaturnavigation.
10Wie groß ist das Plugin?
Unter 1 KB komprimiert. Minimaler Performance-Overhead, der sich durch bessere Animationsqualität gegenüber CSS-Hacks vollständig rechtfertigt.