Calmcode - htmx: search

Search in HTMX

1 2 3 4 5 6 7

In this video we will assume this Flask app:

import time

from flask import Flask, render_template, request

app = Flask(__name__)

numbers = list(range(1, 1001))


@app.route("/")
def index():
    return render_template("02-index.html", numbers=numbers)


@app.route("/search")
def search():
    time.sleep(1)  # Simulate a slow query
    query = request.args.get("query", "").lower()
    filtered_numbers = [num for num in numbers if query in str(num)]

    # Generate HTML string directly
    html = "<ul>"
    for number in filtered_numbers:
        html += f"<li>{number}</li>"
    html += "</ul>"

    return html


if __name__ == "__main__":
    app.run(debug=True)

This app assumes that there is a folder called templates with an 02-index.html file that looks like this:

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Number Filter</title>
    <script src="https://unpkg.com/htmx.org"></script>
</head>
<body>
    <h1>Number Filter</h1>
    <input type="text" name="query" placeholder="Search numbers..."
           hx-get="/search"
           hx-trigger="keyup changed delay:500ms"
           hx-target="#number-list"
           hx-indicator="#spinner">
    <div id="spinner" class="htmx-indicator">Searching...</div>
    <div id="number-list">
    </div>
</body>
</html>

This app is similar to the previous one but we are no longer dealing with a mere button press. In this case we have a text bar and we respond every time that a user starts typing. The backend still returns HTML to the user, but makes sure that we only return a subset of numbers.

One very interesting thing is that the hx-trigger attribute has extra contents that modifies the behavior. We don't respond to every single character that is typed, but instead we wait for a few milliseconds after the last key press before sending a request to the backend. This is a very powerful feature of HTMX that allows you to control the behavior of your app in a very fine-grained way.