htmx ile Modern Web: JavaScript Olmadan Dinamik Sayfalar
htmx Nedir ve Neden Önemlidir?
Modern web geliştirme dünyası, React, Vue, Angular gibi ağır JavaScript framework'leriyle dolup taşıyor. Ancak çoğu projede bu karmaşıklığa gerçekten ihtiyaç var mı? İşte tam bu noktada htmx devreye giriyor. htmx, HTML'in doğal gücünü genişleterek JavaScript yazmadan dinamik, interaktif web sayfaları oluşturmanızı sağlayan hafif bir kütüphanedir.
htmx'in temel felsefesi basittir: HTML zaten bir hypermedia'dır ve sunucudan gelen HTML parçacıklarıyla sayfa dinamik olarak güncellenebilir. JSON API'ler ve istemci tarafı rendering yerine, sunucu doğrudan HTML döner ve htmx bu HTML'i sayfanın ilgili bölümüne yerleştirir. Bu yaklaşım, web'in orijinal mimarisine sadık kalırken modern kullanıcı deneyimi sunar.
Kurulum ve Temel Kullanım
htmx'i projenize eklemek son derece kolaydır. Tek bir script etiketi yeterlidir:
<script src="https://unpkg.com/htmx.org@2.0.4"></script>
Alternatif olarak npm ile de kurabilirsiniz:
npm install htmx.org
htmx sadece ~14 KB (gzip'lenmiş) boyutundadır. React + ReactDOM'un yüzlerce kilobayt olduğunu düşünürsek, bu ciddi bir avantajdır.
Temel htmx Nitelikleri (Attributes)
htmx, HTML elemanlarına eklenen özel nitelikler aracılığıyla çalışır. En sık kullanılan niteliklere bakalım:
- hx-get – Belirtilen URL'ye GET isteği gönderir
- hx-post – POST isteği gönderir
- hx-put – PUT isteği gönderir
- hx-delete – DELETE isteği gönderir
- hx-target – Sunucudan dönen HTML'in yerleştirileceği hedef elementi belirler
- hx-swap – İçeriğin nasıl değiştirileceğini tanımlar (innerHTML, outerHTML, beforeend, vb.)
- hx-trigger – İsteği tetikleyecek olayı belirler
- hx-indicator – Yükleme göstergesi olarak kullanılacak elementi belirler
Pratik Örnekler
1. Tıkla ve İçerik Yükle
En basit htmx örneğiyle başlayalım. Bir butona tıklandığında sunucudan içerik yükleyelim:
<button hx-get="/api/merhaba" hx-target="#sonuc" hx-swap="innerHTML">
İçeriği Yükle
</button>
<div id="sonuc"></div>
Sunucu tarafında /api/merhaba endpoint'i düz HTML döner:
<p>Merhaba! Bu içerik sunucudan dinamik olarak yüklendi.</p>
Bu kadar. JavaScript yok, state yönetimi yok, build pipeline yok. Sunucu HTML döner, htmx onu sayfaya yerleştirir.
2. Arama Kutusu ile Canlı Arama (Live Search)
Kullanıcı yazarken anlık arama sonuçları gösteren bir bileşen oluşturalım:
<input type="text"
name="arama"
hx-get="/arama"
hx-trigger="keyup changed delay:300ms"
hx-target="#arama-sonuclari"
hx-indicator="#yukleniyor"
placeholder="Arama yapın...">
<span id="yukleniyor" class="htmx-indicator">Aranıyor...</span>
<div id="arama-sonuclari"></div>
Burada hx-trigger niteliğindeki delay:300ms ifadesi, debounce işlevi görür. Kullanıcı yazmayı bıraktıktan 300 milisaniye sonra istek gönderilir. Bu, sunucuya gereksiz istek yağmurunu önler. Aynı işlevi JavaScript ile yapmak için en az 15-20 satır kod yazmanız gerekirdi.
3. Sonsuz Kaydırma (Infinite Scroll)
Sayfa sonuna gelindiğinde otomatik olarak daha fazla içerik yükleyen bir liste:
<div id="yazilar">
<div class="yazi">Yazı 1</div>
<div class="yazi">Yazı 2</div>
<div class="yazi">Yazı 3</div>
<div hx-get="/yazilar?sayfa=2"
hx-trigger="revealed"
hx-swap="afterend">
Daha fazla yükleniyor...
</div>
</div>
hx-trigger="revealed" niteliği, element görünür alanda belirdiğinde isteği tetikler. Sunucu bir sonraki yazı grubunu ve yeni bir revealed tetikleyici ile birlikte döner. Bu şekilde sonsuz kaydırma zinciri oluşur.
4. Form Gönderimi ve Doğrulama
<form hx-post="/kayit"
hx-target="#form-sonuc"
hx-swap="outerHTML">
<label>Ad Soyad:
<input type="text" name="ad" required>
</label>
<label>E-posta:
<input type="email" name="email"
hx-post="/email-kontrol"
hx-trigger="blur"
hx-target="next .hata">
<span class="hata"></span>
</label>
<button type="submit">Kayıt Ol</button>
</form>
<div id="form-sonuc"></div>
E-posta alanından çıkıldığında (blur olayı) sunucuya anlık doğrulama isteği gider. Sunucu e-posta zaten kayıtlıysa hata mesajı döner, htmx bunu ilgili .hata span'ına yerleştirir.
5. Silme İşlemi ve Onay
<tr id="kullanici-42">
<td>Ahmet Yılmaz</td>
<td>ahmet@ornek.com</td>
<td>
<button hx-delete="/kullanicilar/42"
hx-target="#kullanici-42"
hx-swap="outerHTML swap:500ms"
hx-confirm="Bu kullanıcıyı silmek istediğinize emin misiniz?">
Sil
</button>
</td>
</tr>
hx-confirm tarayıcının doğal onay diyaloğunu gösterir. swap:500ms ise silme animasyonu için 500 milisaniye gecikme sağlar; bu süre zarfında CSS geçiş efektleri uygulanabilir.
hx-swap Stratejileri
İçeriğin nasıl yerleştirileceğini kontrol eden hx-swap niteliği birçok strateji sunar:
- innerHTML (varsayılan) – Hedefin iç içeriğini değiştirir
- outerHTML – Hedef elementin kendisi dahil tamamını değiştirir
- beforebegin – Hedeften hemen önce ekler
- afterbegin – Hedefin iç içeriğinin başına ekler
- beforeend – Hedefin iç içeriğinin sonuna ekler
- afterend – Hedeften hemen sonra ekler
- delete – Hedef elementi siler
- none – Hiçbir swap yapmaz
Sunucu Tarafı Entegrasyonu
htmx, sunucu tarafında herhangi bir dil veya framework ile çalışır. İşte Go ile basit bir örnek:
func aramaHandler(w http.ResponseWriter, r *http.Request) {
sorgu := r.URL.Query().Get("arama")
sonuclar := veritabanindaAra(sorgu)
for _, s := range sonuclar {
fmt.Fprintf(w, "<div class='sonuc'>%s</div>", s.Baslik)
}
}
Python Flask ile aynı mantık:
@app.route("/arama")
def arama():
sorgu = request.args.get("arama", "")
sonuclar = Yazi.query.filter(Yazi.baslik.contains(sorgu)).all()
return render_template("parcalar/arama_sonuclari.html", sonuclar=sonuclar)
Dikkat edin: sunucu JSON değil, doğrudan HTML parçacığı dönüyor. Bu, htmx'in en temel prensibidir. Tam sayfa template'i değil, sadece güncellenmesi gereken kısmın HTML'ini dönersiniz.
htmx ile WebSocket ve SSE Desteği
htmx, gerçek zamanlı iletişim için de çözümler sunar:
<div hx-ext="sse"
sse-connect="/olaylar"
sse-swap="mesaj">
Gerçek zamanlı mesajlar burada görünecek...
</div>
Server-Sent Events (SSE) kullanarak canlı bildirimler, anlık sohbet veya dashboard güncellemeleri gibi özellikleri tek bir HTML niteliğiyle gerçekleştirebilirsiniz.
htmx Ne Zaman Doğru Seçimdir?
htmx her proje için uygun değildir. İşte karar vermenize yardımcı olacak bir rehber:
- htmx idealdir: İçerik ağırlıklı siteler, yönetim panelleri, CRUD uygulamaları, e-ticaret siteleri, bloglar, dahili araçlar, çok sayfalı uygulamalar (MPA) ve prototipleme
- SPA framework'leri tercih edin: Karmaşık istemci tarafı state yönetimi gerektiren uygulamalar (örneğin Figma benzeri editörler), çevrimdışı çalışması gereken uygulamalar, yoğun animasyon ve geçiş efektleri gerektiren arayüzler
Performans ve SEO Avantajları
htmx kullanmanın somut avantajları şunlardır:
- Küçük bundle boyutu: ~14 KB vs. tipik bir React uygulamasının 200+ KB'ı
- Sunucu tarafı rendering: İlk sayfa yüklemesi hızlıdır ve SEO dostu HTML döner
- Build adımı yok: Webpack, Vite, Babel gibi araçlara ihtiyaç duymazsınız
- Daha az karmaşıklık: State yönetimi, hydration, code splitting gibi sorunlarla uğraşmazsınız
- Sunucu esnekliği: Backend dili veya framework'ünüz ne olursa olsun htmx çalışır
Sonuç
htmx, web geliştirmeye "daha az JavaScript, daha fazla HTML" perspektifinden yaklaşan güçlü bir araçtır. Her projenin yüzlerce kilobayt JavaScript'e ihtiyaç duymadığını hatırlatır ve web'in temellerine geri dönmenin çoğu zaman en pragmatik çözüm olduğunu kanıtlar. Eğer bir sonraki projenizde karmaşık bir SPA framework'ü yerine daha basit bir alternatif arıyorsanız, htmx'i ciddi bir şekilde değerlendirmenizi öneriyorum. Öğrenme eğrisi son derece düşüktür ve mevcut backend altyapınızla sorunsuz entegre olur.