# Quickstart Guide This guide walks you through installing `django-htmx-nav` and implementing partial rendering, out-of-band updates, reusable shell renderers, and visual debugging in Django. ## 1. Installation Install `django-htmx-nav` from PyPI: ```bash pip install django-htmx-nav ``` Optionally, add `django-htmx` if you use its middleware or header helpers: ```bash pip install "django-htmx-nav[htmx]" ``` ## 2. Basic Partial Rendering (`render_nav`) Use `render_nav` in your view functions as a drop-in replacement for Django's standard `render()`: ```python # views.py from django.shortcuts import get_object_or_404 from htmx_nav import render_nav from .models import Project def project_list(request): projects = Project.objects.all() return render_nav(request, "app/project_list.html", {"projects": projects}) ``` In your HTML template, define the partial block using native Django 6 inline partials (`{% partialdef %}`): ```html {% extends 'base.html' %} {% block content %} {% partialdef content inline %}
{% for project in projects %}
{{ project.name }}
{% endfor %}
{% endpartialdef %} {% endblock %} ``` > **Note**: `partial` defaults to `"#content"`, so on HTMX requests `"app/project_list.html"` becomes `"app/project_list.html#content"`, matched by Django's `{% partialdef content %}` block. Name your block `content` to match, or override via `partial="#your_block"` / `partial="path/to/template.html"`. ### Behavior Under the Hood - **Direct Browser Navigation (GET):** Renders the entire document including `base.html`. - **HTMX Partial Request (`HX-Request: true`):** Extracts and renders only the targeted partial block, setting `Vary: HX-Request` for correct HTTP caching. ## 3. Out-of-Band Swaps (`Swap`) When navigating within an application shell, updating only the center container causes surrounding controls (sidebars, breadcrumbs, counter badges) to go stale. Use `Swap` to append synchronized out-of-band updates alongside your response: ```python from django.shortcuts import get_object_or_404 from htmx_nav import Swap, render_nav, has_messages from .models import Project def project_detail(request, pk): project = get_object_or_404(Project, pk=pk) return render_nav( request, "app/project_detail.html", {"project": project}, swaps=[ # Auto-wrapped template swap: Swap("app/_sidebar.html", {"active_pk": project.pk}, target_id="sidebar"), Swap("app/_breadcrumbs.html", {"project": project}, target_id="breadcrumbs"), # High-performance raw string update (skips template engine): Swap.text("unread-badge", "3"), # Delete directive (removes element from DOM): Swap.delete("flash-notification"), # Django messages integration (only sent if messages are pending): Swap("app/_messages.html", target_id="messages", include_if=has_messages), ], ) ``` ### Key Advantages of `Swap` - **Zero-Boilerplate Auto-Wrapping:** Your partial templates (`_sidebar.html`) remain 100% clean HTML. `Swap` automatically wraps them into `` or `` at render time. - **Pythonic Conditionals (`include_if`):** Use `targeting(...)`, `not_targeting(...)`, `has_messages`, or custom lambdas instead of fragile `{% if request.htmx ... %}` blocks in templates. ## 4. Reusable Shell Rendering (`make_shell_renderer`) To avoid declaring the same sidebar and breadcrumb `Swap`s repeatedly across dozens of views, encapsulate them into a reusable `render_shell` helper: ```python # renderers.py from htmx_nav import Swap, make_shell_renderer def build_shell_swaps(request): return [ Swap("app/_sidebar.html", {"user": request.user}, target_id="sidebar"), Swap("app/_breadcrumbs.html", target_id="breadcrumbs"), ] render_shell = make_shell_renderer(build_shell_swaps) ``` Now any view in your application calls `render_shell` directly: ```python # views.py from django.shortcuts import get_object_or_404 from htmx_nav import Swap from .models import Project from .renderers import render_shell def project_detail(request, pk): project = get_object_or_404(Project, pk=pk) return render_shell( request, "app/project_detail.html", {"project": project}, # Per-view extra swaps attach automatically alongside shell swaps: extra_swaps=[ Swap("app/_tabs.html", {"active": "overview"}, target_id="project-tabs"), ], ) ``` ## 5. Class-Based View Integration (`make_shell_view_mixin`) For projects utilizing Django generic Class-Based Views (`DetailView`, `ListView`, `CreateView`), generate a mixin with `make_shell_view_mixin`: ```python # views.py from django.views.generic import DetailView from htmx_nav import Swap, make_shell_view_mixin from .models import Project from .renderers import render_shell ProjectShellMixin = make_shell_view_mixin(render_shell) class ProjectDetailView(ProjectShellMixin, DetailView): model = Project template_name = "app/project_detail.html" def get_extra_swaps(self): # Access self.object and self.request dynamically return [ Swap("app/_tabs.html", {"active": "overview"}, target_id="project-tabs"), ] ``` ## 6. Visual Swap Debugging Catching stale state or verifying which regions swap during development is trivial. Add one setting in `settings.py`: ```python # settings.py (development only) HTMX_NAV_DEBUG_SWAPS = True ``` Whenever an out-of-band swap arrives in the browser, `django-htmx-nav` injects a micro-script that momentarily flashes the targeted DOM element with an animated highlight outline (`.hn-swap`). ## Next Steps - Explore the deployed {demo}`Live Demo Testbed ` and compare all 8 architectural variants. - Check out the {live}`Interactive Benchmark Suite ` for payload and latency metrics. - Read the [Architectural Navigation Patterns Guide](nav_context_patterns.md). - Learn about automated parity verification in the [Testing Guide](testing.md). - Reference full signatures in the [API Reference](api.md).