Toggle-Button-Pattern mit aria-pressed und verlässliche Statusansagen für Screenreader
Der Merkzettel-Button gehört zu den unscheinbarsten, aber am häufigsten falsch ausgezeichneten Interaktionselementen im Onlineshop: Ein Herzen-Icon wechselt beim Klick seinen Zustand, ohne dass sich am umgebenden Markup sichtbar etwas ändert, und genau dieser stille Statuswechsel ist für Screenreader-Nutzer ohne zusätzliche ARIA-Arbeit unsichtbar. Wer das Toggle-Button-Pattern mit aria-pressed konsequent einsetzt und Statusänderungen aktiv ansagt, macht aus einem rein visuellen Wechsel eine nachvollziehbare Aktion, auch bei der Verwaltung des Merkzettels selbst.
Inhaltsverzeichnis
- 1. Warum der Merkzettel-Button ein eigenes Statuswechsel-Problem ist
- 2. Das Toggle-Button-Pattern: aria-pressed statt aria-checked
- 3. Implementierung: Herzen-Icon-Button mit wechselndem Label und Zustand
- 4. Statusänderungen für Screenreader aktiv ansagen
- 5. Icon-only Buttons: Warum aria-label und Kontrast beim Merkzettel-Icon wichtig sind
- 6. Merkzettel-Übersicht: Fokus-Management beim Entfernen von Artikeln
- 7. In den Warenkorb verschieben: zwei Ereignisse in einer Aktion ansagen
- 8. Mehrere Merkzettel und geteilte Listen barrierefrei anlegen
- 9. Umsetzung in Magento und Hyvä: Alpine.js-Komponente für den Merkzettel-Button
- 10. Zusammenfassung
- 11. FAQ
1. Warum der Merkzettel-Button ein eigenes Statuswechsel-Problem ist
Anders als eine reine Formularvalidierung oder ein klassischer Warenkorb-Button löst ein Merkzettel-Button keine Navigation und kein sichtbares neues Formularfeld aus, sondern schaltet lediglich einen booleschen Zustand um: gemerkt oder nicht gemerkt. Genau diese Einfachheit macht ihn tückisch, weil Entwicklerteams ihn oft wie einen gewöhnlichen Button ohne besonderen Zustand behandeln, obwohl er sich technisch klar von einem einfachen Aktions-Button unterscheidet.
Ein Merkzettel-Button ist kein Link, kein Formular-Submit und kein einfacher Aktions-Button, sondern ein sogenannter Toggle-Button: ein Button, der zwischen genau zwei Zuständen wechselt und diesen Zustand dauerhaft anzeigt, bis er erneut geklickt wird. Für diesen Interaktionstyp definiert die ARIA-Spezifikation ein eigenes Attribut, das in der Praxis erstaunlich oft fehlt oder falsch eingesetzt wird.
2. Das Toggle-Button-Pattern: aria-pressed statt aria-checked
Für einen Merkzettel-Button ist aria-pressed das richtige Attribut, nicht aria-checked. aria-checked gehört zu Radiobuttons, Checkboxen und Menüpunkten mit Checkbox-Verhalten und impliziert eine Gruppenzugehörigkeit oder eine formularartige Auswahl. aria-pressed dagegen ist für genau den Fall gemacht, dass ein einzelner, eigenständiger Button zwischen einem gedrückten und einem nicht gedrückten Zustand wechselt, exakt das Verhalten eines Merkzettel-Herzens.
Wichtig ist, dass aria-pressed auf dem button-Element selbst gesetzt und bei jedem Klick per JavaScript zwischen "true" und "false" umgeschaltet wird. Fehlt das Attribut komplett, meldet der Screenreader lediglich einen Button ohne jede Zustandsinformation, und der Nutzer kann nicht erkennen, ob ein Artikel bereits auf dem Merkzettel liegt, ohne die Seite visuell zu prüfen.
<button
type="button"
class="wishlist-toggle"
aria-pressed="false"
data-product-id="1234"
onclick="toggleWishlist(this)">
<svg class="wishlist-toggle__icon" aria-hidden="true"><!-- Herz-Icon --></svg>
<span class="wishlist-toggle__label">Zum Merkzettel hinzufügen</span>
</button>
3. Implementierung: Herzen-Icon-Button mit wechselndem Label und Zustand
Ein rein visuelles Icon, das sich von einem umrandeten zu einem gefüllten Herzen ändert, transportiert den neuen Zustand nur für sehende Nutzer. Damit derselbe Wechsel auch textuell verständlich bleibt, sollte das Label des Buttons zusammen mit aria-pressed aktualisiert werden: aus "Zum Merkzettel hinzufügen" wird nach dem Klick "Von Merkzettel entfernen", nicht nur der visuelle Zustand des Icons.
Diese Kombination aus aria-pressed und wechselndem Text ist doppelt redundant und genau deshalb robust: Manche Screenreader-Modi lesen bevorzugt das Label vor, andere die Zustandsinformation aus aria-pressed. Wird nur eines von beiden gepflegt, funktioniert die Ansage in bestimmten Screenreader-Konfigurationen unvollständig.
function toggleWishlist(button) {
const pressed = button.getAttribute('aria-pressed') === 'true';
const nextState = !pressed;
button.setAttribute('aria-pressed', String(nextState));
button.querySelector('.wishlist-toggle__label').textContent = nextState
? 'Von Merkzettel entfernen'
: 'Zum Merkzettel hinzufügen';
syncWishlist(button.dataset.productId, nextState);
}
4. Statusänderungen für Screenreader aktiv ansagen
In vielen Screenreader-Kombinationen wird eine Änderung von aria-pressed zwar beim nächsten Fokussieren des Buttons vorgelesen, aber nicht automatisch in dem Moment, in dem der Klick stattfindet, wenn der Fokus auf dem Button bleibt. Für eine zuverlässige, sofortige Rückmeldung empfiehlt sich zusätzlich eine dezente aria-live="polite"-Region, die kurz bestätigt, dass der Artikel zum Merkzettel hinzugefügt oder davon entfernt wurde.
Diese Live-Region sollte visuell unauffällig bleiben, etwa als sr-only-Element, und ihren Text bei jeder Statusänderung ersetzen, nicht ergänzen, damit Screenreader nicht wiederholt alte Meldungen erneut vorlesen. Eine doppelte Ansage, einmal durch aria-pressed und einmal durch die Live-Region, ist dabei kein Widerspruch, sondern erhöht die Zuverlässigkeit über verschiedene Assistenztechnologien hinweg.
<div id="wishlist-status" class="sr-only" aria-live="polite"></div>
<script>
function syncWishlist(productId, added) {
document.getElementById('wishlist-status').textContent = added
? 'Artikel wurde zum Merkzettel hinzugefügt.'
: 'Artikel wurde vom Merkzettel entfernt.';
}
</script>
5. Icon-only Buttons: Warum aria-label und Kontrast beim Merkzettel-Icon wichtig sind
In Produktlisten wird der Merkzettel-Button aus Platzgründen oft ohne sichtbaren Text nur als Icon dargestellt. In diesem Fall reicht ein wechselndes aria-pressed allein nicht, weil der Button ohne sichtbaren Text auch keinen zugänglichen Namen hat. Ein aria-label, das ebenfalls je nach Zustand aktualisiert wird, übernimmt dann die Rolle des Labels aus dem vorherigen Beispiel.
Rein visuell unterscheidet sich ein gefülltes von einem umrandeten Herzen oft nur durch eine feine Konturlinie, was bei geringem Kontrast oder bei Sehbeeinträchtigungen schwer erkennbar ist. Ein zusätzliches, wenn auch dezentes visuelles Signal wie eine Farbänderung oder ein kleiner Badge verbessert die Erkennbarkeit für Nutzer, die zwar sehen, aber feine Formunterschiede schlecht wahrnehmen können.
<button
type="button"
class="wishlist-icon-button"
aria-pressed="true"
aria-label="Von Merkzettel entfernen"
data-product-id="1234">
<svg class="wishlist-icon-button__icon" aria-hidden="true"><!-- gefülltes Herz --></svg>
</button>
6. Merkzettel-Übersicht: Fokus-Management beim Entfernen von Artikeln
Auf der eigentlichen Merkzettel-Seite entfernt jeder Klick auf den Entfernen-Button ein komplettes Listenelement aus dem DOM. Ohne bewusstes Fokus-Management verschwindet damit auch das gerade fokussierte Element, und der Tastaturfokus fällt unkontrolliert auf den Dokumentanfang oder den body zurück, wodurch Nutzer die Orientierung in der Liste verlieren.
Robuster ist es, nach dem Entfernen den Fokus gezielt auf den Entfernen-Button des nächsten Listenelements zu setzen, oder, falls es keinen weiteren Artikel mehr gibt, auf eine Überschrift oder eine Leer-Zustand-Meldung wie "Ihr Merkzettel ist leer". Zusätzlich sollte eine aria-live="polite"-Region bestätigen, welcher Artikel entfernt wurde, damit die Aktion auch ohne visuelle Beobachtung nachvollziehbar bleibt.
7. In den Warenkorb verschieben: zwei Ereignisse in einer Aktion ansagen
Die Aktion "In den Warenkorb verschieben" löst technisch zwei Ereignisse gleichzeitig aus: Der Artikel verschwindet aus dem Merkzettel und erscheint im Warenkorb. Wird nur eines der beiden Ereignisse angesagt, etwa nur eine allgemeine Warenkorb-Bestätigung, bleibt für Screenreader-Nutzer unklar, dass der Artikel gleichzeitig aus dem Merkzettel entfernt wurde.
Eine klare, kombinierte Ansage wie "Artikel wurde in den Warenkorb verschoben und vom Merkzettel entfernt" in derselben Live-Region wie bei einer reinen Entfernen-Aktion vermeidet dieses Missverständnis und verhindert, dass Nutzer denselben Artikel später versehentlich als vermeintlich noch vorhanden auf dem Merkzettel suchen.
function moveToCart(productId) {
removeFromWishlist(productId);
addToCart(productId);
document.getElementById('wishlist-status').textContent =
'Artikel wurde in den Warenkorb verschoben und vom Merkzettel entfernt.';
}
8. Mehrere Merkzettel und geteilte Listen barrierefrei anlegen
Shops mit mehreren benannten Merkzetteln, etwa für verschiedene Anlässe, oder mit einer Teilen-Funktion per Link brauchen zusätzliche Statusansagen. Das Erstellen einer neuen Liste sollte den Fokus direkt auf das neue Namensfeld setzen, während das Kopieren eines Freigabe-Links über dieselbe aria-live-Technik bestätigt werden sollte, die bereits für den Merkzettel-Toggle verwendet wird, etwa mit dem Text "Link wurde in die Zwischenablage kopiert".
Bei mehreren Listen sollte der Merkzettel-Button in der Produktansicht klar erkennbar machen, in welche Liste ein Artikel aktuell gespeichert ist, etwa über ein Dropdown mit Checkbox-Semantik statt eines einfachen Toggle-Buttons, da hier keine einfache Ja-Nein-Entscheidung mehr vorliegt, sondern eine Mehrfachauswahl aus mehreren Listen.
9. Umsetzung in Magento und Hyvä: Alpine.js-Komponente für den Merkzettel-Button
In Hyvä lässt sich der Merkzettel-Toggle als kompakte Alpine.js-Komponente umsetzen, die den gemerkten Zustand hält, das Label synchron mit aria-pressed aktualisiert und eine zentrale Live-Region im Layout für die Statusansage nutzt. Die Komponente sollte in der Produktliste, der Produktdetailseite und der Merkzettel-Übersicht wiederverwendet werden, damit sich das Verhalten nicht je nach Seite unterscheidet.
Jeder inline eingebundene script-Block für die Statusansage oder das Umschalten von aria-pressed muss über $hyvaCsp->registerInlineScript() im jeweiligen phtml-Template registriert werden, damit die Content Security Policy die Ausführung nicht blockiert.
document.addEventListener('alpine:init', () => {
Alpine.data('wishlistToggle', (productId, initialPressed) => ({
pressed: initialPressed,
toggle() {
this.pressed = !this.pressed;
this.$dispatch('wishlist-status', {
message: this.pressed
? 'Artikel wurde zum Merkzettel hinzugefügt.'
: 'Artikel wurde vom Merkzettel entfernt.',
});
},
}));
});
| Element | Attribut/Technik | Zweck | Häufiger Fehler |
|---|---|---|---|
| Merkzettel-Button | aria-pressed true/false | Zustand für Screenreader ansagen | Attribut fehlt komplett |
| Icon-only Button | aria-label je Zustand | Zugänglichen Namen ohne sichtbaren Text liefern | Statisches Label trotz Statuswechsel |
| Statuswechsel | aria-live=polite Region | Sofortige Bestätigung der Aktion | Nur visuelle Änderung ohne Ansage |
| Artikel entfernen | Fokus auf nächstes Element | Orientierung in der Liste erhalten | Fokus fällt auf Dokumentanfang zurück |
| In Warenkorb verschieben | Kombinierte Live-Ansage | Beide Ereignisse gleichzeitig kommunizieren | Nur Warenkorb-Bestätigung ohne Merkzettel-Hinweis |
Mironsoft
WCAG-Audits, barrierefreie Magento-Shops und Schulungen
Unsicher, ob der Shop wirklich barrierefrei ist?
Wir prüfen bestehende Magento-Shops gegen WCAG 2.2, beheben konkrete Barrieren im Hyvä-Frontend und schulen Teams, damit Barrierefreiheit dauerhaft im Entwicklungsprozess verankert bleibt.
WCAG-Audit
Shop systematisch gegen WCAG 2.2 AA prüfen, mit priorisierter Fehlerliste.
Barrieren beheben
Konkrete Umsetzung: Tastaturbedienbarkeit, Screenreader-Support, Kontraste, Formulare.
Team-Schulung
Entwickler und Redakteure für barrierefreie Umsetzung im Alltag sensibilisieren.
10. Zusammenfassung
Wishlist und Merkzettel barrierefrei: Die wichtigsten Fragen
Grundprinzip
aria-pressed statt aria-checked kennzeichnet den Merkzettel-Button korrekt als Toggle-Button mit zwei Zuständen.
Doppelte Redundanz
Wechselndes Label oder aria-label zusammen mit aria-pressed und einer Live-Region sichert die Ansage über verschiedene Screenreader ab.
Fokus-Management
Beim Entfernen aus der Merkzettel-Liste muss der Fokus gezielt auf das nächste Element oder eine Leer-Zustand-Meldung gesetzt werden.
Kombinierte Aktionen
In den Warenkorb verschieben betrifft zwei Listen gleichzeitig und braucht eine entsprechend kombinierte Statusmeldung.