Akkordeon mit details bauen
Ziel
Ein Akkordeon, also mehrere Abschnitte zum Auf- und Zuklappen, das ganz ohne JavaScript funktioniert. Auf Wunsch exklusiv (immer nur ein Abschnitt offen) und mit weichem Auf- und Zuklappen.
Voraussetzungen
- Keine für das Grundakkordeon.
- Exklusiv:
nameandetails(seit 2024-09-03 Baseline newly available). - Styling des Inhalts:
::details-content(seit 2025-09-16 Baseline newly available).
Getestet mit / Stand
Stand 2026-09-12. Am 2026-09-13 in Chrome 152 (macOS) getestet: Bei mehreren open in einer Gruppe ist nur das erste offen, name schließt den vorigen Abschnitt, Enter auf summary öffnet per Tastatur, die Höhe klappt in beide Richtungen animiert, und der eigene Marker ersetzt den Standardpfeil. Am 2026-10-18 in Chrome 155 ergänzt: toggle beim Laden und die Gruppenbildung über verschiedene Elternelemente (siehe Fallstricke). Nicht getestet: Firefox, Safari, Screenreader. Grundlage sind die MDN-Referenzen und ein Chrome-Artikel. Die Animation des Inhalts funktioniert laut web-features 3.38.0 nicht in Firefox, die Höhenanimation nur in Chromium.
Vorgehen
-
Abschnitte als
detailsmitsummary:1<div class="accordion"> <details name="faq"> <summary>Wie lange dauert die Lieferung?</summary> <p>In der Regel zwei bis drei Werktage.</p> </details> <details name="faq"> <summary>Kann ich zurückgeben?</summary> <p>Innerhalb von 30 Tagen.</p> </details> <details name="faq"> <summary>Welche Zahlungsarten gibt es?</summary> <p>Rechnung, Karte, Überweisung.</p> </details> </div> -
Mit gleichem
nameexklusiv machen. Öffnet man einen Abschnitt, schließt sich der zuvor offene.12 Ohnenamekönnen beliebig viele gleichzeitig offen sein. -
Einen Abschnitt von Anfang an öffnen mit
open. Haben in einer Gruppe mehrere Abschnitteopen, ist nur der erste im Quelltext offen.1 -
Marker gestalten.
summaryhatdisplay: list-item. Den Pfeil kann man über::markergestalten oder durch eigenes Styling ersetzen.1.accordion summary { list-style: none; cursor: pointer; padding: 0.75rem 1rem; } .accordion summary::-webkit-details-marker { display: none; } .accordion summary::after { content: "+"; float: inline-end; } .accordion details[open] > summary::after { content: "–"; }↗ Beispiel in neuem Tab öffnen
list-style: noneund der-webkit--Pseudoselektor stammen nicht aus den ausgewerteten Quellen, sondern sind der übliche Weg, den Standardpfeil zu entfernen.::markerist lautweb-features3.38.0 limited (Chrome 86, Firefox 68, Safari fehlt). Deshalb ersetzt man den Pfeil besser wie oben durch ein eigenes::after, statt::markerzu stylen. Ob der WebKit-Selektor noch nötig ist, habe ich nicht geprüft. -
Inhalt stylen über
::details-content:3.accordion details::details-content { padding-inline: 1rem; } -
Ein- und Ausblenden animieren: Deckkraft plus
content-visibilitymitallow-discrete, nach MDN:3@media (prefers-reduced-motion: no-preference) { .accordion details::details-content { opacity: 0; transition: opacity 300ms, content-visibility 300ms allow-discrete; } .accordion details[open]::details-content { opacity: 1; } } -
Optional die Höhe mitanimieren (nur Chromium):
@supports (interpolate-size: allow-keywords) { .accordion { interpolate-size: allow-keywords; } @media (prefers-reduced-motion: no-preference) { .accordion details::details-content { block-size: 0; overflow-y: clip; transition: block-size 300ms ease, opacity 300ms, content-visibility 300ms allow-discrete; } .accordion details[open]::details-content { block-size: auto; } } }↗ Beispiel in neuem Tab öffnen
Laut dem Chrome-Artikel zu
height: autobraucht man für beide Richtungeninterpolate-sizeund::details-contentzusammen. Den genauen Code dafür enthält der ausgewertete Text nicht.4 Das Beispiel habe ich selbst gebaut und in Chrome 152 getestet.
Warum funktioniert das?
detailsist ein natives Disclosure-Widget: Zustand, Tastaturbedienung und Ansage bringt das Element selbst mit.1 Dasssummaryper Tastatur bedienbar ist und als aufklappbar angesagt wird, steht in den ausgewerteten Abschnitten nicht ausdrücklich. Die Tastaturbedienung ist in Chrome 152 bestätigt (Enteröffnet), die Ansage im Screenreader habe ich nicht geprüft.namebildet eine Gruppe. Die Elemente müssen dafür keine Geschwister sein, es zählt nur der gleiche Wert.2- Beim Auf- und Zuklappen schaltet der Browser
content-visibilitydes Inhalts zwischenhiddenundvisibleum. Mitallow-discretewartet diese Umschaltung beim Schließen, bis die Transition fertig ist. So sieht man das Ausblenden.3 interpolate-size: allow-keywordserlaubt Übergänge von0zuautound wird vererbt.4
Fallstricke
- Gleicher
namean anderer Stelle: Weildetailsmit gleichem Namen überall auf der Seite eine Gruppe bilden, schließt ein FAQ-Abschnitt womöglich einen gleichnamigen Abschnitt in einer ganz anderen Komponente. Deshalb eindeutige Namen wählen. In Chrome 155 bestätigt: Eindetailsin einersectionund eines in einemasidemit gleichemnameschließen sich gegenseitig. - Exklusiv ist nicht immer besser: Wer zwei Antworten vergleichen will, kann das dann nicht.
namenur setzen, wenn es keinen Sinn hat, mehrere gleichzeitig zu öffnen (eigene Einschätzung). - Firefox: Dort lässt sich
content-visibilitylaut Baseline-Daten nicht per Transition verzögern. Die Abschnitte klappen sofort zu, und auch das Einblenden kann fehlen. Funktion und Inhalt bleiben aber erhalten. - Höhe nur in Chromium: Andere Browser springen. Dank
@supportshat das keine Nebenwirkungen. - Ältere Browser ohne
name: Chrome beschreibt ein Polyfill über dastoggle-Event. In Browsern ohnetogglebleibt es ein normales Akkordeon.2 - Mehrfache Toggles: Bei schnellem Wechsel kann der Browser mehrere
toggle-Events zu einem zusammenfassen. Das ist nur für eigenes JavaScript wichtig.1 - Gemerkten Zustand per Skript wiederherstellen: Die Exklusivität gilt nicht nur für Klicks. Wird
openan einemdetailsmitnamegesetzt, auch per Skript, entfernt der Browseropenbeim bisher offenen Element der Gruppe.5 Stellt ein Skript nach dem Rendern gemerkte offene Abschnitte wieder her, schließt es damit womöglich genau den Abschnitt, den der Server absichtlich geöffnet hat, etwa den mit der aktuellen Seite. Regel aus einem eigenen Quartz-Plugin: Gemerkten Zustand in einer Gruppe nur anwenden, wenn dort noch nichts absichtlich geöffnet ist. - Keine Animation beim Laden: Öffnet ein Skript Abschnitte nach dem Rendern, kann die Transition aus Schritt 6 und 7 sichtbar ablaufen, obwohl niemand geklickt hat. Abhilfe aus demselben Plugin: Die Animation an ein Attribut wie
data-animatebinden, das erst bei der ersten Nutzerinteraktion gesetzt wird (details[data-animate][open]::details-content …). Nicht eigens im Browser nachgetestet. togglefeuert auch fürdetails, die von Anfang an offen sind: Laut HTML-Standard laufen die Schritte für Attributänderungen auch dann, wenn der Parser das Element mitopeneinfügt. Dabei wird eintoggle-Event eingereiht.5 jsdom 25.0.1 macht das genauso: Es reihttogglepersetTimeoutein, sobaldopengesetzt wird, auch beim Parsen.6 Eintoggle-Listener, der Zustand speichert, läuft also schon beim Laden, in Tests wie im Browser. In Chrome 155 bestätigt: Für eindetailsmitopenim HTML kam beim Laden eintogglemitnewState: "open".- Exklusivität in jsdom-Tests: jsdom 25.0.1 wertet das
name-Attribut vondetailsnicht aus.6 Ein Fehler wie beim Wiederherstellen oben lässt sich dort nicht nachstellen, nur im echten Browser.
Browsersupport
| Feature | Stand |
|---|---|
details, summary | Baseline widely available |
name (exklusives Akkordeon) | Baseline newly available seit 2024-09-03 (Chrome 120, Firefox 130, Safari 17.2) |
::details-content | Baseline newly available seit 2025-09-16 (Chrome 131, Firefox 143, Safari 18.4) |
content-visibility transitionieren | limited: Chrome 117, Safari 18, Firefox fehlt |
interpolate-size | limited: nur Chromium ab 129 |
Quelle: web-features 3.38.0 (Baseline-Daten der W3C WebDX Community Group), lokal abgefragt am 2026-09-12.
Siehe auch
Quellen
- details-Element (MDN) — Aufbau,
name,open, Marker,toggle - details-content Pseudo-Element (MDN) — Styling und Transition des Inhalts
- Exclusive Accordion (Chrome for Developers) — exklusive Gruppen, Polyfill
- Animate to height auto (Chrome for Developers) —
interpolate-size,details-Animation - HTML Living Standard, Abschnitt zum
details-Element (siehe Fußnote) — Exklusivität bei gesetztemopen,togglebeim Parsen - jsdom 25.0.1, Quelltext
HTMLDetailsElement-impl.js(siehe Fußnote) —togglein Tests, fehlende Exklusivität
Nicht aus den Quellen: das Marker-Styling mit list-style und ::-webkit-details-marker, das Höhenbeispiel in Schritt 7 und die Fallstricke zu Namen und Exklusivität. Das APG-Muster „Accordion“ habe ich nicht ausgewertet. Die Fallstricke zum Wiederherstellen und zu data-animate stammen aus einem eigenen Quartz-Plugin, der Mechanismus dahinter ist durch den HTML-Standard belegt.
Footnotes
-
details-content Pseudo-Element (MDN), Abschnitt „Transition example“. ↩ ↩2 ↩3
-
Animate to height auto (Chrome for Developers), Abschnitt „Animate the details element“. ↩ ↩2
-
WHATWG, HTML Living Standard, Abschnitt „The details element“: Attributänderungs-Schritte („ensure details exclusivity by closing other elements if needed“) und Hinweis „these attribute change and insertion steps also run when an attribute or element is inserted via the parser“, https://html.spec.whatwg.org/multipage/interactive-elements.html#the-details-element. Abgerufen 2026-09-25. ↩ ↩2
-
jsdom 25.0.1,
lib/jsdom/living/nodes/HTMLDetailsElement-impl.js(behandelt nuropen, nichtname) undlib/jsdom/browser/parser/html.js(setzt Attribute beim Parsen über dieselbe Änderungslogik). Lokal gelesen am 2026-09-25. ↩ ↩2