HTMX Troubleshooting
Häufige Probleme
1. CSRF-Token Fehler (403)
| Symptom | Request schlägt mit 403 fehl |
|---|---|
| Ursache | hx-headers fehlt oder Token ist ungültig |
| Lösung | hx-headers='{"X-CSRF-TOKEN": "<?= $csrfToken ?>"}' |
Prüfen:
- DevTools → Network → Request Headers → X-CSRF-TOKEN vorhanden?
- Token in Session gültig?
2. hx-indicator zeigt nichts an
| Symptom | Loading-Spinner erscheint nicht |
|---|---|
| Ursache | hx-indicator zeigt auf Element, CSS fehlt |
Lösung:
<!-- Indicator braucht ID oder Selektor -->
<button hx-indicator="#my-spinner">...</button>
<span id="my-spinner" class="htmx-indicator">Loading...</span>
/* CSS muss vorhanden sein */
.htmx-indicator { display: none; }
.htmx-request .htmx-indicator { display: inline; }
3. Response wird nicht angezeigt
| Symptom | Request erfolgreich, aber nichts passiert |
|---|---|
| Ursachen |
|
Debugging:
<!-- Temporär hinzufügen -->
hx-on::after-request="console.log('Response:', event.detail.xhr.responseText)"
4. Button bleibt disabled
| Symptom | Nach Request bleibt Button deaktiviert |
|---|---|
| Ursache | hx-disabled-elt wird nicht zurückgesetzt bei Fehler |
| Lösung | HTMX macht das automatisch. Prüfen ob JS den Button manuell disabled. |
5. Doppelte Requests
| Symptom | Ein Klick löst mehrere Requests aus |
|---|---|
| Ursachen |
|
Lösung:
<!-- Bei Button in Form -->
<button type="button" hx-post="..."> <!-- type="button" statt submit -->
<!-- Oder -->
<form hx-post="..." hx-trigger="submit">
<button type="submit">Submit</button> <!-- Nur form hat hx-post -->
</form>
6. Form-Daten werden nicht gesendet
| Symptom | POST-Request hat leeren Body |
|---|---|
| Ursache | hx-* auf Button statt Form |
Falsch:
<form>
<input name="title">
<button hx-post="/api">Send</button>
</form>
Richtig:
<form hx-post="/api">
<input name="title">
<button type="submit">Send</button>
</form>
7. History/Back-Button Probleme
| Symptom | Browser-Back funktioniert nicht wie erwartet |
|---|---|
| Ursache | HTMX ersetzt Inhalte ohne History-Push |
Lösung:
<!-- Für Navigation, die History braucht -->
<a href="/page" hx-push-url="true" hx-get="/page" hx-target="#main">Link</a>
<!-- Oder: Normaler Link ohne HTMX -->
<a href="/page">Link</a>
Debugging-Tools
1. HTMX Debug-Extension
<script src="https://unpkg.com/htmx.org/dist/ext/debug.js"></script>
<body hx-ext="debug">
Loggt alle HTMX-Events in die Console.
2. Request/Response in DevTools
- DevTools → Network
- XHR/Fetch filtern
- Request Headers prüfen (X-CSRF-TOKEN, HX-Request)
- Response Body prüfen
3. HTMX Events manuell loggen
document.body.addEventListener('htmx:beforeRequest', (e) => {
console.log('Before:', e.detail);
});
document.body.addEventListener('htmx:afterRequest', (e) => {
console.log('After:', e.detail);
console.log('Response:', e.detail.xhr.responseText);
});
document.body.addEventListener('htmx:responseError', (e) => {
console.error('Error:', e.detail);
});
Contract-Validierung Fehlermeldungen
Bei Contract-Validierung (contracts_validate(name="htmx-patterns")) können folgende Fehler auftreten:
"hx-post missing CSRF token"
| Bedeutung | HTMX-C1 verletzt |
|---|---|
| Fix | hx-headers='{"X-CSRF-TOKEN": "<?= $csrfToken ?>"}' |
"hx-delete missing confirmation"
| Bedeutung | HTMX-C4 verletzt |
|---|---|
| Fix | hx-confirm="Wirklich löschen?" |
Best Practices
1. Immer explizites Target
<!-- Gut -->
hx-target="#result-container"
<!-- Vermeiden (ersetzt Element selbst) -->
hx-target="this"
2. Expliziter Swap-Modus
<!-- Gut -->
hx-swap="innerHTML"
<!-- Vermeiden (Default ist innerHTML, aber explizit ist klarer) -->
(kein hx-swap)
3. Feedback bei hx-swap="none"
<!-- Bei hx-swap="none" braucht User visuelles Feedback -->
<input hx-swap="none"
hx-on::after-request="this.classList.add('is-saved'); setTimeout(() => this.classList.remove('is-saved'), 1000)">
Verwandte Themen
- HTMX Übersicht - Grundlagen und Konfiguration
- Patterns - Alle Code-Patterns
- Regeln - HTMX statt fetch() Regel