mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 08:31:08 -05:00
257 lines
7.2 KiB
Markdown
257 lines
7.2 KiB
Markdown
# 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
|
|
```html
|
|
<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
|
|
```html
|
|
<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
|
|
```html
|
|
<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
|
|
```html
|
|
<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
|
|
```html
|
|
<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
|
|
```html
|
|
<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
|
|
```html
|
|
<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
|
|
```html
|
|
<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)
|
|
```html
|
|
<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
|
|
```python
|
|
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
|
|
```html
|
|
<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
|
|
```python
|
|
@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
|
|
```python
|
|
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
|
|
```html
|
|
{% 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
|
|
```html
|
|
<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 |