Powrót do korzeni — HTML jako interfejs

Przez ostatnią dekadę budowanie aplikacji webowych zdominowały frameworki JavaScript — React, Vue, Angular. Każdy nowy projekt wymagał konfiguracji bundlera, zarządzania stanem, routingu po stronie klienta i API w formacie JSON. Dla wielu aplikacji to nadmierna złożoność.

HTMX proponuje radykalnie inne podejście: zamiast budować API zwracające JSON i renderować HTML w przeglądarce, serwer zwraca gotowe fragmenty HTML, a HTMX podmienia je na stronie. To powrót do modelu, w którym serwer kontroluje interfejs — ale z dynamicznością, którą wcześniej dawał tylko JavaScript.

Jak działa HTMX?

HTMX to biblioteka JavaScript o rozmiarze zaledwie 14 KB (minified + gzipped), która rozszerza HTML o nowe atrybuty. Dzięki nim każdy element HTML może wysyłać żądania HTTP i aktualizować fragmenty strony bez pełnego przeładowania.

Podstawowy przykład — przycisk ładujący treść:

<button hx-get="/api/wiadomosci"
        hx-target="#lista-wiadomosci"
        hx-swap="innerHTML">
  Załaduj wiadomości
</button>

<div id="lista-wiadomosci"></div>

Po kliknięciu przycisku HTMX wysyła żądanie GET do /api/wiadomosci, a odpowiedź (fragment HTML) wstawia do elementu #lista-wiadomosci. Żadnego JavaScriptu — cała logika wyrażona jest w atrybutach HTML.

Kluczowe atrybuty HTMX

Żądania HTTP

  • hx-get — żądanie GET
  • hx-post — żądanie POST
  • hx-put — żądanie PUT
  • hx-delete — żądanie DELETE

Cel i sposób wstawienia

  • hx-target — selektor CSS elementu, który zostanie zaktualizowany (domyślnie: element z atrybutem)
  • hx-swap — jak wstawić odpowiedź: innerHTML, outerHTML, beforeend, afterbegin, delete

Wyzwalacze

  • hx-trigger — zdarzenie uruchamiające żądanie: click, submit, keyup, load, revealed (element pojawił się w viewport)

Przykład formularza

<form hx-post="/kontakt"
      hx-target="#formularz-kontener"
      hx-swap="outerHTML">
  <input type="text" name="imie" placeholder="Imię" required>
  <input type="email" name="email" placeholder="Email" required>
  <textarea name="wiadomosc" placeholder="Wiadomość" required></textarea>
  <button type="submit">Wyślij</button>
</form>

Serwer po przetworzeniu formularza zwraca HTML z potwierdzeniem, który zastępuje cały formularz. Bez przekierowania, bez przeładowania strony.

Server-driven UI

HTMX promuje architekturę server-driven UI — serwer jest jedynym źródłem prawdy o stanie interfejsu. To fundamentalna zmiana w porównaniu z podejściem SPA, gdzie stan aplikacji zarządzany jest po stronie klienta.

Zalety tego podejścia:

  • Brak duplikacji logiki — walidacja, autoryzacja i renderowanie odbywają się w jednym miejscu (serwerze)
  • Prostszy stack technologiczny — nie potrzebujesz osobnego API JSON, routingu klienta, zarządzania stanem
  • Łatwiejsze debugowanie — odpowiedź serwera to gotowy HTML, który można podejrzeć w narzędziach przeglądarki
  • Bezpieczeństwo — logika biznesowa nie jest eksponowana w kodzie JavaScript dostępnym w przeglądarce

HTMX z Go — naturalne połączenie

HTMX szczególnie dobrze współgra z językami serwerowymi, które mają silne wsparcie dla szablonów HTML. Go z pakietem html/template jest tutaj idealnym przykładem:

func handleWiadomosci(w http.ResponseWriter, r *http.Request) {
    wiadomosci := pobierzWiadomosci()

    // Dla żądań HTMX zwracamy sam fragment
    if r.Header.Get("HX-Request") == "true" {
        tmpl.ExecuteTemplate(w, "lista-wiadomosci", wiadomosci)
        return
    }

    // Dla zwykłych żądań zwracamy pełną stronę
    tmpl.ExecuteTemplate(w, "strona", wiadomosci)
}

Nagłówek HX-Request pozwala rozróżnić żądania HTMX od zwykłych żądań przeglądarki. Ten sam endpoint może obsługiwać oba scenariusze — zwracając fragment HTML dla HTMX lub pełną stronę dla bezpośredniego wejścia.

Zaawansowane możliwości

HTMX oferuje znacznie więcej niż podstawowe żądania:

Wyszukiwanie w czasie rzeczywistym:

<input type="search"
       name="q"
       hx-get="/szukaj"
       hx-target="#wyniki"
       hx-trigger="keyup changed delay:300ms"
       placeholder="Szukaj...">

Żądanie wysyłane jest 300 ms po ostatnim naciśnięciu klawisza — klasyczny debounce bez linijki JavaScriptu.

Nieskończone przewijanie:

<div hx-get="/artykuly?strona=2"
     hx-trigger="revealed"
     hx-swap="afterend">
  Ładowanie...
</div>

Gdy element pojawi się w viewport, automatycznie ładowana jest kolejna strona wyników.

Wskaźniki ładowania:

<button hx-get="/dane" hx-indicator="#spinner">
  Pobierz dane
  <span id="spinner" class="htmx-indicator">⏳</span>
</button>

HTMX automatycznie pokazuje i ukrywa wskaźnik ładowania podczas trwania żądania.

Kiedy HTMX, a kiedy SPA?

HTMX sprawdzi się, gdy:

  • Budujesz aplikację z przewagą formularzy i wyświetlania danych
  • Zespół ma doświadczenie głównie w technologiach serwerowych
  • Priorytetem jest prostota i szybkość wdrożenia
  • SEO jest ważne (serwer renderuje pełny HTML)
  • Aplikacja nie wymaga skomplikowanych interakcji po stronie klienta

SPA będzie lepszym wyborem, gdy:

  • Budujesz aplikację z bogatymi interakcjami w czasie rzeczywistym (edytor graficzny, gra)
  • Potrzebujesz zaawansowanego zarządzania stanem po stronie klienta
  • Aplikacja musi działać w trybie offline z synchronizacją danych
  • Budujesz aplikację mobilną przez React Native lub podobne rozwiązanie

Podsumowanie

HTMX to nie krok wstecz — to przemyślana odpowiedź na nadmierną złożoność współczesnego frontendu. Dla dużej części aplikacji webowych — stron firmowych, paneli administracyjnych, dashboardów, CRM-ów — podejście server-driven z HTMX jest prostsze, szybsze w implementacji i łatwiejsze w utrzymaniu niż pełnoprawne SPA. Nie eliminuje potrzeby istnienia frameworków JavaScript, ale pokazuje, że wiele problemów można rozwiązać prościej, gdy serwer zwraca HTML zamiast JSON.