Dynamic Forms Handling with HTMX and Python Flask
Dynamic forms enhance the user experience by updating the parts of a web page without the full page reload, the powerful library can allow for the AJAX requests and dynamic updates, while Flask can provide a robust backend framework for Python. This article will guide you through integrating the HTMX with Flask to create dynamic forms.
- HTMX: It can allow you to use the AJAX, CSS transitions, and WebSockets directly in the HTML. It can enable you to update the parts of the Web page dynamically based on the user interactions without needing to write the extensive JavaScript Code.
- Flask: It is a micro web framework for Python. It can be designed to be simple and easy to use, making it a good choice for small to medium-sized applications. Flask is based on the WSGI toolkit and Jinja2 template engine.
Setting up Flask and HTMX
Installing the Flask
We need to install the Flask using pip:
pip install Flask
Installing the HTMX
HTMX is the JavaScript library that can be included via the CDN and add the following scripts to the HTML template.
<script src="https://unpkg.com/htmx.org@1.8.0"></script>
Creating the Basic Flask Application
Create the new file named as app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
- Flask(__name__): It can be initializes the Flask application.
- @app.route('/'): It can defines the routes for the homepage and renders the index.html template.
- app.run(debug=True): It can be starts the development server with debug mode enabled.
HTMX Setup:
Include the HTMX in HTML
Add the HTMX library to the HTML via CDN
<script src="https://unpkg.com/htmx.org@1.8.0"></script>
This script can allows you to use the HTMX features such as the AJAX requests and dynamic content updates directly into the HTML page.
Create the new directory for the project and setup the basic Flask application.
Project Structure

templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Forms with HTMX and Flask</title>
<script src="https://unpkg.com/htmx.org@1.8.0"></script>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
</head>
<body>
<div class="container">
<h1>Dynamic Forms with HTMX and Flask</h1>
<form hx-get="/update-fields" hx-target="#dynamic-fields">
<div class="form-group">
<label for="type">Form Type:</label>
<select id="type" name="type" class="form-control">
<option value="basic">Basic</option>
<option value="advanced">Advanced</option>
</select>
</div>
</form>
<form hx-post="/submit" hx-target="#response" hx-swap="innerHTML">
<div class="form-group">
<label for="name">Name:</label>
<input type="text" id="name" name="name" class="form-control" required>
</div>
<div class="form-group">
<label for="email">Email:</label>
<input type="email" id="email" name="email" class="form-control" required>
</div>
<div class="form-group">
<label for="phone">Phone:</label>
<input type="tel" id="phone" name="phone" class="form-control">
</div>
<div class="form-group">
<label for="address">Address:</label>
<textarea id="address" name="address" class="form-control"></textarea>
</div>
<div id="dynamic-fields"></div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<div id="response"></div>
</div>
</body>
</html>
static/styles.css
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.container {
width: 80%;
max-width: 800px;
margin: 20px auto;
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
h1 {
text-align: center;
color: #333;
}
form {
margin-bottom: 20px;
}
.form-group {
margin-bottom: 15px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
input[type="text"],
input[type="email"],
input[type="tel"],
textarea {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
textarea {
height: 100px;
}
button {
padding: 10px 20px;
border: none;
border-radius: 4px;
background-color: #007bff;
color: #fff;
font-size: 16px;
cursor: pointer;
}
button:hover {
background-color: #0056b3;
}
.alert {
padding: 15px;
margin-top: 20px;
border-radius: 4px;
}
.alert-success {
background-color: #d4edda;
color: #155724;
}
.alert-error {
background-color: #f8d7da;
color: #721c24;
}
test/test_app.py
import pytest
from app import app
@pytest.fixture
def client():
app.config['TESTING'] = True
with app.test_client() as client:
yield client
def test_index(client):
response = client.get('/')
assert b'Dynamic Forms with HTMX and Flask' in response.data
def test_update_fields_basic(client):
response = client.get('/update-fields', query_string={'type': 'basic'})
assert b'' in response.data
def test_update_fields_advanced(client):
response = client.get('/update-fields', query_string={'type': 'advanced'})
assert b'Additional Information' in response.data
def test_submit(client):
response = client.post('/submit', data={'name': 'Alice', 'email': 'alice@example.com'})
assert b'Hello, Alice!' in response.data
def test_submit_with_extra_field(client):
response = client.post('/submit', data={'name': 'Alice', 'email': 'alice@example.com', 'extra': 'Extra Value'})
assert b'Hello, Alice! Extra field value: Extra Value' in response.data
def test_submit_no_name(client):
response = client.post('/submit', data={'email': 'alice@example.com'})
assert b'Error: Name and Email are required!' in response.data
app.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/update-fields')
def update_fields():
type_ = request.args.get('type')
if type_ == 'advanced':
fields = '''
<div class="form-group">
<label for="extra">Additional Information:</label>
<input type="text" id="extra" name="extra" class="form-control">
</div>
'''
else:
fields = ''
return fields
@app.route('/submit', methods=['POST'])
def submit():
name = request.form.get('name')
email = request.form.get('email')
phone = request.form.get('phone')
address = request.form.get('address')
extra = request.form.get('extra', '')
if not name or not email:
return "<p>Error: Name and Email are required!</p>", 400
response = f"""
<div class="alert alert-success">
<h4>Submission Successful!</h4>
<p><strong>Name:</strong> {name}</p>
<p><strong>Email:</strong> {email}</p>
<p><strong>Phone:</strong> {phone}</p>
<p><strong>Address:</strong> {address}</p>
<p><strong>Additional Info:</strong> {extra}</p>
</div>
"""
return response
if __name__ == '__main__':
app.run(debug=True)
Output
Conclusion
Combining the HTMX with Flask for the powerful dynamic form handling. By the following these steps outlined above, we can create the responsive, interactive web applications that improve the user experience. Continue to explore the HTMX and Flask documentation for more advanced features and best pratices.