diff --git a/doc/20-HTMX-LEARNING.md b/doc/20-HTMX-LEARNING.md index b4bbeed..d299b51 100644 --- a/doc/20-HTMX-LEARNING.md +++ b/doc/20-HTMX-LEARNING.md @@ -14,7 +14,9 @@ This document explains HTMX patterns used in this CV website project, with pract 4. [Toggle Patterns](#toggle-patterns) 5. [Contact Form Pattern](#contact-form-pattern) 6. [Skeleton Loaders](#skeleton-loaders) -7. [Common Attributes Reference](#common-attributes-reference) +7. [HTML Invoker Commands API](#html-invoker-commands-api) +8. [Lazy Loading Web Components](#lazy-loading-web-components) +9. [Common Attributes Reference](#common-attributes-reference) --- @@ -378,6 +380,264 @@ _="on htmx:afterSettle wait 100ms then remove .loading from me" --- +## HTML Invoker Commands API + +**Browser Support**: Chrome/Edge 135+, Firefox Nightly, Safari TP + +### The Problem + +Opening and closing `` elements traditionally requires JavaScript: + +```html + + + + + + +``` + +This is verbose, error-prone, and mixes behavior with markup. + +### The Solution: `commandfor` + `command` + +The new HTML Invoker Commands API provides declarative modal control: + +```html + + + + + + +``` + +### Command Values + +| Command | Effect | Target Element | +|---------|--------|----------------| +| `show-modal` | Opens dialog as modal | `` | +| `close` | Closes dialog | `` | +| `show-popover` | Shows popover | `[popover]` | +| `hide-popover` | Hides popover | `[popover]` | +| `toggle-popover` | Toggles popover | `[popover]` | + +### Project Implementation + +**Files**: `templates/partials/widgets/*.html`, `templates/partials/modals/*.html` + +```html + + + + + +
+ + +
+
+``` + +### Benefits + +1. **No JavaScript** - Pure HTML declarative syntax +2. **Accessibility** - Built-in keyboard and screen reader support +3. **Reduced Errors** - No typos in element IDs within JavaScript +4. **Cleaner Templates** - Removes onclick clutter +5. **Progressive Enhancement** - Graceful degradation in older browsers + +### Fallback for Older Browsers + +If you need to support browsers without Invoker Commands: + +```html + +``` + +--- + +## Lazy Loading Web Components + +### The Problem + +Heavy web components (like ninja-keys command palette) add significant initial load time even when users may never use them: + +``` +Initial Load: 81 module requests, ~300KB, 2+ seconds +``` + +### The Solution: Dynamic Import on Demand + +Only load the component when the user actually needs it: + +```javascript +// Don't import at top of file +// import 'ninja-keys'; // ❌ Loads immediately + +// Instead, lazy load on first use +let loaded = false; + +async function loadNinjaKeys() { + if (loaded) return; + + // Dynamic import - only fetches when called + await import('https://esm.sh/ninja-keys@1.2.2?bundle'); + + // Create element after module loads + const container = document.getElementById('cmd-k-container'); + const ninjaKeys = document.createElement('ninja-keys'); + ninjaKeys.id = 'cmd-k-bar'; + container.appendChild(ninjaKeys); + + loaded = true; +} + +// Trigger on user action +document.addEventListener('keydown', (e) => { + if ((e.metaKey || e.ctrlKey) && e.key === 'k') { + e.preventDefault(); + loadNinjaKeys(); + } +}); +``` + +### Project Implementation + +**File**: `templates/partials/layout/body-scripts.html` + +```html + +
+ + +``` + +### CDN Choice: esm.sh with ?bundle + +| CDN | Requests | Why | +|-----|----------|-----| +| unpkg.com | 80+ (redirect chains) | ❌ Follows all peer deps | +| esm.sh | 80+ (without bundle) | ❌ Resolves all imports | +| esm.sh?bundle | 2-3 | ✅ Pre-bundled single file | +| jsdelivr | 1 | ✅ Also good option | + +```javascript +// ❌ Triggers 80+ module requests +await import('https://esm.sh/ninja-keys@1.2.2'); + +// ✅ Single bundled file +await import('https://esm.sh/ninja-keys@1.2.2?bundle'); +``` + +### CSP Configuration + +Remember to add your CDN to Content Security Policy: + +```go +// internal/middleware/security.go +csp := "default-src 'self'; " + + "script-src 'self' 'unsafe-inline' https://esm.sh https://cdn.jsdelivr.net; " + + // ... +``` + +### Performance Results + +| Metric | Before | After | +|--------|--------|-------| +| Initial requests | 81 | 0 | +| Initial load time | +2.1s | 0ms | +| On CMD+K | 0 | 3 requests | +| Subsequent uses | 0 | 0 (cached) | + +### Best Practices + +1. **Use Placeholder Containers** - Empty div ready for component injection +2. **Prevent Double Loading** - Track loading state with flags +3. **Bundle Dependencies** - Use `?bundle` parameter on esm.sh +4. **Cache First Load** - Browser caches subsequent uses automatically +5. **Multiple Triggers** - Support keyboard AND button triggers +6. **Initialization Delay** - Wait briefly after element creation for setup + +--- + ## Common Attributes Reference ### Request Attributes