Files
thrillwiki_django_no_react/memory-bank/research/htmx-best-practices.md

7.2 KiB

HTMX Best Practices and Advanced Techniques

Research Summary

Comprehensive research from HTMX documentation and Django-specific patterns to inform the ThrillWiki frontend redesign.

Core HTMX Patterns for Implementation

1. Essential UI Patterns

Active Search Pattern

<input type="search" name="q" placeholder="Search..."
       hx-get="/search" 
       hx-trigger="input changed delay:250ms" 
       hx-target="#results">
<div id="results"></div>

Application: Enhance park and ride search functionality with real-time results.

Click to Edit Pattern

<div hx-target="this" hx-swap="outerHTML">
  <span id="name">World</span>
  <button hx-get="/names/1" hx-target="closest div">Edit</button>
</div>

Application: Inline editing for park details, ride information.

Infinite Scroll Pattern

<div id="content">
  <!-- Initial content here -->
</div>
<div hx-trigger="revealed" hx-get="/more-content" hx-swap="beforeend" hx-target="#content">
  Loading...
</div>

Application: Park and ride listings with progressive loading.

Lazy Loading Pattern

<div hx-trigger="intersect" hx-get="/lazy-content" hx-swap="innerHTML">
  Loading...
</div>

Application: Photo galleries, detailed ride statistics.

2. Form Handling Patterns

Inline Validation Pattern

<form hx-post="/contact">
  <input type="email" id="email" name="email" required
         hx-trigger="input changed delay:500ms" 
         hx-post="/validate-email"
         hx-target="#email-error">
  <span id="email-error" class="error"></span>
</form>

Application: Real-time validation for park creation, ride submission forms.

Bulk Update Pattern

<form hx-put="/names">
  <input type="hidden" name="_method" value="PUT">
  <table class="table">
    <tbody>
      <tr>
        <td><input class="form-check-input" type="checkbox" name="ids[]" value="1">
        <td><input type="text" name="names[]" value="Alice">
      </tr>
    </tbody>
  </table>
  <button>Update Selected</button>
</form>

Application: Batch operations for moderation, bulk park updates.

3. Advanced Interaction Patterns

Progress Bar Pattern

<div class="progress">
  <div id="progress-bar" class="progress-bar" style="width: 0%;">0%</div>
</div>
<button hx-post="/run-job" 
        hx-target="#progress-bar" 
        hx-swap="innerHTML">Run Job</button>

Application: Photo upload progress, data import operations.

Modal Dialog Pattern

<button hx-get="/modal/content" hx-target="#modal-container" hx-swap="innerHTML">Open Modal</button>
<div id="modal-container"></div>

Application: Park creation forms, ride detail modals, photo viewers.

Value Select Pattern (Dependent Dropdowns)

<select name="country" hx-get="/states" hx-target="#state-select">
  <option value="US">United States</option>
  <option value="CA">Canada</option>
</select>
<select id="state-select" name="state">
  <option value="">Please select a state</option>
</select>

Application: Location selection (Country -> State -> City), park filtering.

Django-Specific HTMX Patterns

1. Form Validation with Django

HTMX Form Validation Decorator

def htmx_form_validate(*, form_class: type):
    def decorator(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if (
                request.method == "GET"
                and "Hx-Request" in request.headers
                and (htmx_validation_field := request.GET.get("_validate_field", None))
            ):
                form = form_class(request.GET)
                form.is_valid()  # trigger validation
                return HttpResponse(render_single_field_row(form, htmx_validation_field))
            return view_func(request, *args, **kwargs)
        return wrapper
    return decorator

Template Integration

<div
  class="field is-horizontal {{ classes }}"
  id="form-row-{{ field.name }}"
  hx-get="."
  hx-vals='{"_validate_field": "{{ field.name }}" }'
  hx-trigger="focusout from:#form-row-{{ field.name }}"
  hx-include="#form-row-{{ field.name }}"
  hx-target="this"
  hx-ext="morph"
  hx-swap="morph:outerHTML"
>

2. Django View Patterns

Block-Based Partial Rendering

@for_htmx(use_block_from_params=True)
def monster_detail(request: HttpRequest, monster_id: int):
    monster = get_object_or_404(Monster.objects.all(), id=monster_id)
    
    if request.method == "POST":
        if "kick" in request.POST:
            monster.kick()
        elif "hug" in request.POST:
            monster.hug()
        if not is_htmx(request):
            return HttpResponseRedirect("")
    
    return TemplateResponse(request, "monster_detail.html", {"monster": monster})

Modal Form Handling

form = CreateMonsterForm(request.POST)
if form.is_valid():
    monster = form.save()
    return HttpResponse(
        headers={
            "Hx-Trigger": json.dumps({
                "closeModal": True,
                "monsterCreated": monster.id,
            })
        }
    )

3. Template Organization

Inline Partials Pattern

{% block monster-form %}
  <form
    method="POST"
    action=""
    id="monster-form"
    hx-post=""
    hx-target="#monster-form"
    hx-swap="outerHTML"
    hx-vals='{"use_block": "monster-form"}'
    >
    {% csrf_token %}
    <!-- Form content -->
  </form>
{% endblock %}

Performance Optimizations

1. Request Optimization

  • Use hx-trigger="input changed delay:500ms" for debounced search
  • Implement hx-push-url="true" for browser history management
  • Use hx-swap="morph:outerHTML" for efficient DOM updates

2. Loading States

  • Implement loading indicators with htmx-indicator class
  • Use skeleton screens for better perceived performance
  • Add progress bars for long-running operations

3. Error Handling

  • Implement comprehensive error responses
  • Use hx-confirm for destructive actions
  • Provide clear user feedback for all operations

Integration with Alpine.js

Complementary Usage

<div x-data="{ count: 0 }">
    <button hx-post="/increment" 
            hx-target="#count-display" 
            hx-swap="innerHTML"
            @click="count++">
        Increment
    </button>
    <span id="count-display" x-text="'Count: ' + count">Count: 0</span>
</div>

Event Coordination

  • Use HTMX for server communication
  • Use Alpine.js for client-side state management
  • Coordinate between both using custom events

Implementation Priorities for ThrillWiki

High Priority

  1. Active Search: Real-time park and ride search
  2. Inline Validation: Form validation with immediate feedback
  3. Click to Edit: Inline editing for park/ride details
  4. Modal Dialogs: Form submissions and detail views

Medium Priority

  1. Infinite Scroll: Progressive loading for large lists
  2. Bulk Operations: Moderation and batch updates
  3. Progress Indicators: File uploads and data operations
  4. Dependent Dropdowns: Location and category selection

Low Priority

  1. Advanced Animations: Smooth transitions between states
  2. Real-time Updates: Live notifications and updates
  3. Offline Support: Progressive web app features