Active search
The results update as you type. htmx asks the page again with hx-target="#results"; PAD answers the {fragment 'results'} of the same template - the element's name is enough.
{fragment}HX-Target
hx-gethx-trigger delayhx-push-url
Live
24 products
| Product | Category | Price |
|---|---|---|
| ð§ Aurora Headphones | Audio | €189.00 |
| ðķ Pebble Earbuds | Audio | €79.00 |
| ð Boom Speaker | Audio | €129.00 |
| ðïļ Studio Microphone | Audio | €99.00 |
| ðŧ Nimbus Laptop 14 | Computing | €1,299.00 |
| ðĨïļ Atlas Monitor 27 | Computing | €349.00 |
| ðąïļ Glide Mouse | Computing | €39.00 |
| âĻïļ Tactile Keyboard | Computing | €119.00 |
| ð· Drift Webcam | Computing | €69.00 |
| ðĄ Ember Desk Lamp | Home | €59.00 |
| ðŦ Brew Kettle | Home | €49.00 |
| â Pour-over Set | Home | €35.00 |
| ðïļ Cloud Pillow | Home | €45.00 |
| ðŠī Leaf Planter | Home | €25.00 |
| ð Trail Backpack 28L | Outdoor | €139.00 |
| ðĨĪ Summit Bottle | Outdoor | €29.00 |
| âš Ridge Tent 2P | Outdoor | €279.00 |
| ðĶ Beam Headlamp | Outdoor | €34.00 |
| â Compass Watch | Outdoor | €219.00 |
| ð Canvas Tote | Accessories | €22.00 |
| ðķïļ Shade Sunglasses | Accessories | €89.00 |
| ðą Snap Phone Case | Accessories | €19.00 |
| ð Fold Wallet | Accessories | €49.00 |
| ð Loop Charger | Accessories | €29.00 |
Requests htmx made
Nothing yet - use the example above, and every request it makes shows here with the part PAD answered.
How it is built
PAD, on the server htmx, in the browser
<div class="toolbar">
<div class="search">
<input class="input" type="search" name="q" value="{$q}" placeholder="Search - try lamp, audio or usb" autocomplete="off"
aria-label="Search the products" hx-get="?examples/search" hx-trigger="input changed delay:250ms, search"
hx-target="#results" hx-push-url="true" hx-indicator="#searching">
</div>
<span id="searching" class="htmx-indicator spinner" aria-hidden="true"></span>
</div>
<div id="results">
{fragment 'results'}
<p class="muted small">{$count} {if $count eq 1}product{else}products{/if}{if $q} for <mark>{$q}</mark>{/if}</p>
<table class="table">
<thead><tr><th>Product</th><th>Category</th><th class="num">Price</th></tr></thead>
<tbody>
{found}
<tr><td>{$emoji} {$name}</td><td><span class="badge">{$category}</span></td><td class="num">{$price | currency('EUR')}</td></tr>
{/found}
</tbody>
</table>
{if $count eq 0}<div class="empty-state"><span class="big">ð</span>Nothing in the catalogue matches.</div>{/if}
{/fragment}
</div><?php
// The products whose name, category or text holds the query. The same PHP serves the page
// and every answer to htmx: the input's hx-target="#results" sends HX-Target: results,
// and PAD answers the {fragment 'results'} of search.pad alone. The query stands in the
// address (hx-push-url), so a reload - or a link - shows the same results whole.
$q = trim ( htmxText ( 'q' ) );
$found = array_values ( array_filter ( htmxData ( 'products' ), fn ( $product ) =>
$q === '' or stripos ( $product ['name'] . ' ' . $product ['category'] . ' ' . $product ['blurb'], $q ) !== FALSE ) );
$count = count ( $found );
?>