Cookbook
Copy practical patterns for signals, partial swaps, streaming, navigation, uploads, and reusable UI flows.
This page focuses on the practical details. Use the quick links below to move to the previous, next, or related docs.
Copy-paste recipes for common HyperDjango interaction patterns.
The cookbook shows practical composition of features in real flows, not just isolated API references.
1) Button -> server action -> local Alpine state sync
<section x-data="{ count: 0 }">
<button @click="$action('increment', { current: count })">
Increment
</button>
<strong x-text="count"></strong>
</section>
from __future__ import annotations
from hyperdjango.integrations.alpine.actions import Signal
@action
def increment(self, request, current: int = 0, **params):
return [Signal(name="count", value=int(current) + 1)]
Local + global patch (count + $count)
from __future__ import annotations
from hyperdjango.integrations.alpine.actions import Signals
@action
def increment(self, request, current: int = 0, **params):
value = int(current) + 1
return [Signals(values={"count": value, "$count": value})]
<section x-data="{ count: 0 }">
<button @click="$action('increment', { current: count })">Increment</button>
<p>Local: <span x-text="count"></span></p>
<p>Global: <span x-text="$store.hyper.count"></span></p>
</section>
2) Partial swap with server-selected target
from __future__ import annotations
from hyperdjango.actions import HTML, action
@action
def show_editor(self, request, **params):
return [
HTML(
content=self.render(request=request, relative_template_name="partials/editor_form.html"),
target="#editor",
swap="inner",
)
]
Client call can omit target and use server contract.
3) Multiple targeted HTML patches to keep side panels in sync
from __future__ import annotations
from hyperdjango.actions import HTML, Toast, action
@action
def add_todo(self, request, title="", **params):
return [
HTML(content="<li>...</li>", target="#todo-list", swap="append"),
HTML(content="<div>Updated stats</div>", target="#todo-stats"),
Toast(payload={"type": "success", "message": "Added"}),
]
4) Ordered multi-patch updates
from __future__ import annotations
from hyperdjango.actions import HTML
return [
HTML(content="A", target="#one"),
HTML(content="<div id='two'>B</div>", target="#two", swap="outer"),
]
5) Delete row without sending HTML
from hyperdjango.actions import Delete
return [Delete(target=f"#todo-{id}")]
6) Typeahead with request replacement
<input
x-model="q"
@input.debounce.250ms="$action('search', { q }, { sync: 'replace', key: 'live-search' })"
/>
New requests abort in-flight ones in the same key.
7) Prevent double submits with sync block
<form id="profile-form"
x-data="{}"
@submit.prevent="$action('save_profile', {}, { form: $el, sync: 'block', key: 'profile-save' })">
...
</form>
New submits while pending are ignored (blocked).
8) Loading spinner + disable controls
<div hyper-loading="live-search" hyper-loading-delay="150">Searching...</div>
<button hyper-loading-disable="live-search">Search</button>
9) Form validation with focus to first invalid field
from __future__ import annotations
from hyperdjango.actions import HTML
if not form.is_valid():
return [
HTML(
content=self.render(
request=request,
relative_template_name="partials/form.html",
context_updates={"form": form},
),
target="#profile-panel",
focus="first-invalid",
)
]
10) Push or replace URL from actions
from __future__ import annotations
from hyperdjango.actions import History, HTML
return [
HTML(content="...", target="#results"),
History(replace_url=f"/search?q={query}"),
]
Use push_url when you want a new history entry instead.
Back/Forward restoration uses the URL as the source of truth. Make sure a normal
GET to the pushed or replaced URL can render the same state. See
History And Back/Forward Restoration for target behavior and full
document restore details.
11) Use HyperPageTemplate in a custom Django view
from __future__ import annotations
from hyperdjango.page import HyperPageTemplate
class ProfileCardTemplate(HyperPageTemplate):
pass
from __future__ import annotations
from hyperdjango.shortcuts import render_template_page
def profile_card(request):
return render_template_page(
request,
ProfileCardTemplate,
context={"title": "Account", "description": "From custom view"},
)