About me
Coding since 2018
Working at Cruncher
Mother tongue Turkish
Happy Django & HTMX user
Living in Lausanne
Formerly a tour guide
Also used Rails, Hugo, Vue etc.
Halit ÇELIK
What is HTMX?
Dependency free JS library
Adds interactivity with html attributes without writing any JS
Back-end agnostic
Extends HTML
SSE and Websockets via HTML attributes
Different approaches for web applications
Multi page applications
(traditional)
Single page applications
(modern)
HTMX approach
(mixture)
Different approaches for web applications
Multi page applications
Client
Initial request
Another request
Page reload
Server
Improved SEO
Easier to scale
Does not require Javascript to run
Stays in the original Hypermedia concept
Suffers from HTML restrictions
Page reloads on every request
Faster initial page load
Different approaches for web applications
Multi page applications
(Traditional)
Single page applications
(Modern)
HTMX approach
(Mixture)
Different approaches for web applications
Single page applications
Client
Initial request
Another request
Server
No page reload required
Poor SEO
Difficult to scale
Requires Javascript to run
Does not suffer from HTML restrictions
Page does not reload on every request
Slower initial page load
Possibility of better UX
Less secure
Better for games and 3d animations etc.
Different approaches for web applications
Multi page applications
(traditional)
Single page applications
(modern)
HTMX approach
(mixture)
Different approaches for web applications
HTMX approach
Client
Initial request
HTMX request
Server
No page reload required
HTML fragment
Does not suffer from HTML restrictions
Page does not reload on every request
Possibility of better UX
Improved SEO
Easier to scale
Does not require Javascript to run
Stays in the original Hypermedia concept
Faster initial page load
Not good for games etc...
How I met HTMX
<div class="row">
<a href="{% url 'beers:edit' beer.pk %}"
hx-get="{% url 'beers:edit' beer.pk %}"
hx-target="closest .row"
hx-swap="outerHTML">
<i class="ti-pencil"></i>
</a>
</div>
Let's take a look at the example
HTMX & Django integration
Client
HTMX & Django integration
HTMX & Django integration
Django Edit Object view
# Let's imagine a regular django function based view here...
def edit(request, pk):
# This one extends base and includes the edit form.
template = "app/edit.html"
if request.htmx:
#This one is just the form. Does not extend base.html
template = "app/includes/partial.html"
render(request, template, context)
Updating multiple places at once?
Client
HTMX request
Server
HTML fragment
HTML fragment
HTML fragment
Updating multiple places at once?
Client
HTMX request
Server
HTML fragment
HTML fragment
HTML fragment
Updating multiple places at once?
(Delete example)
<div class="row">
<a href="{% url 'beers:delete' beer.pk %}"
hx-delete="{% url 'beers:delete' beer.pk %}"
hx-target="closest .row"
hx-swap="outerHTML swap:.3s"
hx-confirm="Are you sure to delete {{beer.name}}">
<i class="ti-close"></i>
</a>
</div>
But... where is the CSRF token?
Updating multiple places at once?
(Delete example)
<div class="row">
<a href="{% url 'beers:delete' beer.pk %}"
hx-delete="{% url 'beers:delete' beer.pk %}"
hx-target="closest .row"
hx-swap="outerHTML swap:.3s"
hx-confirm="Are you sure to delete {{beer.name}}"
hx-headers='{"X-CSRFToken": "{{ csrf_token }}" }'>
<i class="ti-close"></i>
</a>
</div>
// base.html
<script>
document.body.addEventListener('htmx:configRequest', (event) => {
event.detail.headers['X-CSRFToken'] = '{{ csrf_token }}';
});
</script>
Or
Response coming from Django for delete request
<!-- The fragment that updates the message block -->
<div hx-swap-oob="true" id="messages" >
<span> Success Very Pale Ale deleted!</span>
</div>
<!-- The fragment that updates the favourites count -->
<li hx-swap-oob="true" id="favourites-count">
<a href="#favourites" >
<i class="ti-heart"></i>
<span class="favourites">1</span>
<p class="hidden-md hidden-lg">
favourites
<b class="caret"></b>
</p>
</a>
</li>
<!-- Beer row appended to the end of table -->
<div hx-swap-oob="beforeend:#datatables">
{% include 'beers/includes/beer-row.html' %}
</div>
<div class="card-content row"
hx-get="{% url 'beers:similar' beer.pk %}"
hx-trigger="load"
hx-target="this"
hx-swap="innerHTML">
<img class="htmx-indicator" src="{% static 'img/indicator.svg' %}">
</div>
<input
placeholder="Begin Typing To Search..."
hx-get="{% url 'beers:active-search' %}"
hx-trigger="keyup changed delay:500ms"
hx-target="#beers-table"
hx-push-url="true"
hx-indicator="#indicator"
class="form-control"
type="text"
value="{{query|default:''}}"
name="q" />
Thank you!
Resources:
Find me: