# Tooling and Ecosystem Standards for HTMX
This document outlines the recommended standards for tooling and ecosystem usage when developing applications with HTMX. It aims to provide clear guidelines for developers to ensure maintainable, performant, and secure code. These standards apply to all HTMX-related development, including server-side code, HTML templates, and any related scripting.
## 1. Development Environment Setup
### 1.1. Recommended Editors and IDEs
* **Do This:** Use IDEs or editors with HTMX support, such as VS Code with HTMX extensions or JetBrains IDEs with HTML/JavaScript support enhanced with HTMX syntax highlighting.
* **Don't Do This:** Rely on basic text editors without HTMX-specific features if your project is more than a simple proof of concept.
**Why:** Integrated development environments with HTMX support provide syntax highlighting, autocompletion, and other features that can significantly improve developer productivity and reduce errors.
**Example (VS Code Settings):**
"""json
// settings.json
{
"files.associations": {
"*.html": "html",
"*.htmx": "html"
},
"editor.quickSuggestions": {
"strings": true
},
"emmet.includeLanguages": {
"htmx": "html"
}
}
"""
### 1.2. Browser Developer Tools
* **Do This:** Utilize browser developer tools (e.g., Chrome DevTools, Firefox Developer Tools) to inspect HTMX requests, responses, and attributes applied to elements.
* **Don't Do This:** Neglect using browser tools and rely solely on server-side logs for debugging.
**Why:** Browser developer tools provide real-time visibility into HTMX interactions, allowing you to quickly identify issues with requests, responses, and attribute configurations.
**Practical Advice:** Pay close attention to the "Network" tab to understand the data being exchanged and any errors that occur. Use the "Elements" tab to see how HTMX modifies the DOM.
### 1.3. Version Control System (VCS)
* **Do This:** Use Git for version control. Enforce code reviews before merging changes via pull requests. Store code in a remote repository (GitHub, GitLab, Bitbucket).
* **Don't Do This:** Work directly on the main branch or skip code reviews.
**Why:** Version control systems are essential for tracking changes, collaborating effectively, and maintaining a history of the project. Code reviews ensure code quality and knowledge sharing within the team.
**Example (Git Workflow):**
1. Create a new branch for each feature or bug fix: "git checkout -b feature/new-htmx-component"
2. Commit changes with clear, concise messages: "git commit -m "feat: Implement HTMX-powered search""
3. Push branch to remote repository: "git push origin feature/new-htmx-component"
4. Create a pull request for review.
5. Once approved, merge the pull request into the main branch.
## 2. Templating Engines and Framework Integration
### 2.1. Server-Side Template Engines
* **Do This:** Use server-side template engines (e.g., Jinja2, Django Templates, Thymeleaf, Razor) to dynamically generate HTML content that includes HTMX attributes.
* **Don't Do This:** Hardcode HTML with HTMX attributes directly in your application logic.
**Why:** Template engines separate presentation logic from application code, making it easier to maintain and update the UI.
**Example (Jinja2):**
"""html+jinja
{% if data %}
<p>Data: {{ data }}</p>
{% else %}
<p>Loading...</p>
{% endif %}
"""
### 2.2. Frameworks
* **Do This:** Integrate HTMX with backend frameworks (e.g., Django, Flask, Spring Boot, ASP.NET Core) to handle HTTP requests and responses triggered by HTMX.
* **Don't Do This:** Attempt to implement HTMX logic directly within static HTML files for complex applications.
**Why:** Backend frameworks provide structure, security features, and tools for handling data persistence, authentication, and other server-side concerns.
**Example (Flask):**
"""python
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/data')
def get_data():
# Simulate data retrieval
data = "Hello from the server!"
return jsonify({'message': data})
if __name__ == '__main__':
app.run(debug=True)
"""
"""html+jinja
Loading...
"""
### 2.3. Component Libraries
* **Do This:** Consider using component libraries that provide pre-built, reusable HTMX components (if available and suitable for the project).
* **Don't Do This:** Over-engineer custom HTMX components when existing libraries can provide the necessary functionality more efficiently.
**Why:** Component libraries save development time and ensure consistency across the application. However, be mindful of adding unnecessary dependencies.
**Note:** The HTMX ecosystem is still evolving, and the availability of comprehensive component libraries may be limited. Assess the maturity and suitability of any library before adopting it.
## 3. Testing
### 3.1. Unit Testing
* **Do This:** Write unit tests for server-side code that handles HTMX requests to ensure that responses are correctly formatted and contain the expected HTML fragments or JSON data.
* **Don't Do This:** Neglect testing server-side code that supports HTMX interactions.
**Why:** Unit tests help prevent regressions and ensure that server-side logic remains reliable.
**Example (Python and pytest):**
"""python
# app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/data')
def get_data():
return jsonify({'message': 'Test Value!'})
"""
"""python
# test_app.py
import pytest
from app import app
@pytest.fixture
def client():
with app.test_client() as client:
yield client
def test_get_data(client):
response = client.get('/data')
data = response.get_json()
assert response.status_code == 200
assert data['message'] == 'Test Value!'
"""
### 3.2. Integration Testing
* **Do This:** Implement integration tests to verify the interaction between HTMX attributes in HTML, client-side JavaScript (if any), and backend endpoints. Use tools like Selenium, Cypress, or Playwright for end-to-end testing.
* **Don't Do This:** Assume that HTMX interactions will work correctly without thorough integration testing.
**Why:** Integration tests ensure that all components of the application work together seamlessly.
**Example (Cypress):**
"""javascript
// cypress/e2e/spec.cy.js
describe('HTMX integration test', () => {
it('Loads data from the server', () => {
cy.visit('/');
cy.get('#my-component').should('contain', 'Hello from the server!');
});
});
"""
### 3.3. End-to-End Testing
* **Do This:** Perform end-to-end (E2E) tests to simulate real user scenarios and ensure that the entire application functions as expected. Use mocking or test databases to isolate tests.
* **Don't Do This:** Deploy without adequate E2E testing, especially for mission-critical features.
**Why:** E2E tests validate the application's behavior from the user's perspective and catch integration issues that unit and integration tests might miss.
## 4. Tooling for HTMX Code Quality
### 4.1. Linters and Formatters
* **Do This:** Use linters (e.g., ESLint for JavaScript, HTMLHint for HTML) and formatters (e.g., Prettier) to enforce consistent code style and identify potential errors.
* **Don't Do This:** Ignore linting and formatting errors, as they can lead to inconsistencies and maintainability issues.
**Why:** Linters and formatters automate code style enforcement, reducing the likelihood of errors and making the codebase more readable and maintainable.
**Example (ESLint Configuration):**
"""json
// .eslintrc.js
module.exports = {
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended"
],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"rules": {
"semi": ["error", "always"],
"quotes": ["error", "single"]
}
};
"""
### 4.2. Static Analyzers
* **Do This:** Utilize static analysis tools (e.g., SonarQube, Code Climate) to detect potential bugs, security vulnerabilities, and code quality issues.
* **Don't Do This:** Neglect static analysis, especially in large or complex projects.
**Why:** Static analyzers automatically identify code issues that might be missed by manual review, improving code quality and security.
### 4.3. HTMX Attribute Validation
* **Do This:** Implement custom validation to ensure HTMX attributes are used correctly and consistently across the application. This may involve creating custom linting rules or validation scripts.
* **Don't Do This:** Allow arbitrary or inconsistent use of HTMX attributes without validation.
**Why:** Correct attribute usage is crucial for HTMX's functionality. Validation helps prevent errors that can be difficult to debug. This can be done with custom tooling or build scripts.
"""python
# Example: Python script to validate htmx attributes in HTML files
import os
import re
def validate_htmx_attributes(html_content):
"""Validates HTMX attributes in HTML content."""
errors = []
# Regex to find HTMX attributes (e.g., hx-get, hx-post, etc.)
htmx_attributes = re.findall(r'hx-[a-z-]+="[^"]*"', html_content)
for attr in htmx_attributes:
# Basic validation: Check if attribute value is not empty
if attr.split("=")[1].strip() in ('""', "''"):
errors.append(f"Empty HTMX attribute found: {attr}")
# Add more specific validations based on project standards
# Example: Check if URL in hx-get attribute starts with "/"
if attr.startswith("hx-get") and not attr.split("=")[1].strip().strip('"').startswith("/"):
errors.append(f"hx-get attribute URL should start with '/': {attr}")
return errors
def process_html_file(file_path):
"""Reads HTML file, validates HTMX attributes, and prints errors."""
with open(file_path, 'r', encoding='utf-8') as file:
html_content = file.read()
errors = validate_htmx_attributes(html_content)
if errors:
print(f"Errors in {file_path}:")
for error in errors:
print(f" - {error}")
else:
print(f"No HTMX attribute errors found in {file_path}")
# Example usage:
if __name__ == "__main__":
html_file_path = "templates/index.html" # Replace with your HTML file path
process_html_file(html_file_path)
"""
## 5. Security Considerations
### 5.1. Input Validation and Sanitization
* **Do This:** Always validate and sanitize user inputs on the server-side before using them to generate HTML content or query databases.
* **Don't Do This:** Trust client-side data without proper validation.
**Why:** Input validation and sanitization prevent cross-site scripting (XSS) attacks and other security vulnerabilities.
**Example (Server-Side Input Validation):**
"""python
from flask import Flask, request, render_template, escape
app = Flask(__name__)
@app.route('/search')
def search():
query = request.args.get('q', '')
# Sanitize user input
safe_query = escape(query)
results = perform_search(safe_query) # Assuming perform_search exists
return render_template('search_results.html', results=results)
"""
### 5.2. Cross-Site Request Forgery (CSRF) Protection
* **Do This:** Implement CSRF protection to prevent malicious websites from forging requests on behalf of authenticated users. Use CSRF tokens in forms and AJAX requests. Server-side frameworks often provide built-in CSRF protection mechanisms; utilize them.
* **Don't Do This:** Disable CSRF protection without a very strong reason, and only if alternative security measures are in place.
**Why:** CSRF protection prevents unauthorized actions by verifying that requests originate from the application itself.
**Example (Django CSRF Protection):**
"""html+django
{% csrf_token %}
Update
"""
### 5.3. Secure Headers
* **Do This:** Set appropriate security headers (e.g., Content Security Policy, X-Frame-Options, Strict-Transport-Security) to protect against common web vulnerabilities.
* **Don't Do This:** Ignore security headers, as they provide an important layer of defense against attacks.
**Why:** Security headers instruct the browser on how to handle the application's resources, mitigating the risk of XSS, clickjacking, and other attacks.
**Example (Setting Security Headers in Flask):**
"""python
from flask import Flask, make_response
app = Flask(__name__)
@app.after_request
def add_security_headers(response):
response.headers['Content-Security-Policy'] = "default-src 'self'"
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains'
return response
"""
## 6. Performance Optimization Tools
### 6.1. Profiling Tools
* **Do This:** Utilize profiling tools to identify performance bottlenecks in server-side code and client-side rendering.
* **Don't Do This:** Make performance optimizations without first identifying the areas that need improvement.
**Why:** Profiling tools provide insights into the performance characteristics of the application, allowing you to focus on the most critical areas for optimization.
**Example (Profiling in Python):**
"""python
import cProfile
import pstats
def my_function():
# ... code to be profiled ...
pass
if __name__ == '__main__':
profiler = cProfile.Profile()
profiler.enable()
my_function()
profiler.disable()
stats = pstats.Stats(profiler).sort_stats('cumulative')
stats.print_stats()
"""
### 6.2. Caching Strategies
* **Do This:** Implement caching strategies (e.g., browser caching, server-side caching with Redis or Memcached) to reduce server load and improve response times.
* **Don't Do This:** Over-cache data that changes frequently and is personalized.
**Why:** Caching can significantly improve performance by reducing the need to repeatedly fetch data from the database or perform expensive computations.
**Example (Browser Caching):**
Set cache-control headers via your server. For example, in express:
"""js
app.get('/images/:imageName', (req, res) => {
const imageName = req.params.imageName;
res.set('Cache-Control', 'public, max-age=31536000'); // One year
res.sendFile(path.join(__dirname, 'public', 'images', imageName));
});
"""
### 6.3. Network Analysis
* **Do This:** Employ network analysis tools (e.g., Chrome DevTools Network panel, Wireshark) to analyze HTTP requests and responses, identify slow-loading resources, and optimize network performance.
* **Don't Do This:** Ignore network performance, as it directly impacts the user experience.
**Why:** Network analysis helps identify areas for optimization, such as reducing the size of HTTP responses, optimizing image compression, and leveraging content delivery networks (CDNs).
## 7. HTMX-Specific Tools and Extensions
### 7.1. HTMX Debugger
* **Do This:** Use browser extensions or tools purpose-built for debugging HTMX interactions. If one does not exist, consider writing custom logging or inspection tools.
**Why:** HTMX interactions can be harder to trace than traditional page loads. Good debugger tooling will provide a detailed record of triggered requests and responses.
**Example (Custom JavaScript Logging):**
"""javascript
document.addEventListener('htmx:beforeRequest', function(evt) {
console.log('HTMX Request URL:', evt.detail.path);
console.log('HTMX Request Params:', evt.detail.parameters);
});
document.addEventListener('htmx:afterRequest', function(evt) {
console.log('HTMX Response:', evt.detail.xhr.responseText);
console.log('HTMX Status:', evt.detail.xhr.status);
});
"""
### 7.2. HTMX Snippets and Code Generation Tools
* **Do This:** To improve efficiency and reduce boilerplate, use or create code snippets for common htmx patterns within your IDE. If your team uses a common set of design components, consider custom generators.
**Why:** Code snippets and generation tools speed up development time and increase consistency across projects.
### 7.3. Dedicated Libraries/Frameworks
* **Do This:** Watch how third party HTMX-specific libraries/frameworks change over time for new or better features. Implement and test these libraries gradually into existing projects.
* **Don't Do This:** Automatically bring in newly introduced HTMX frameworks into large production codebases without testing.
**Why:** The HTMX ecosystem is still developing and may include functionalities (like form validation or special UI) prebuilt that can reduce project code size.
By adhering to these standards, HTMX developers can ensure that their applications are maintainable, performant, secure, and aligned with best practices in the HTMX ecosystem. This guidelines document provides a solid foundation for creating high-quality HTMX applications.
danielsogl
Created Mar 6, 2025
This guide explains how to effectively use .clinerules
with Cline, the AI-powered coding assistant.
The .clinerules
file is a powerful configuration file that helps Cline understand your project's requirements, coding standards, and constraints. When placed in your project's root directory, it automatically guides Cline's behavior and ensures consistency across your codebase.
Place the .clinerules
file in your project's root directory. Cline automatically detects and follows these rules for all files within the project.
# Project Overview project: name: 'Your Project Name' description: 'Brief project description' stack: - technology: 'Framework/Language' version: 'X.Y.Z' - technology: 'Database' version: 'X.Y.Z'
# Code Standards standards: style: - 'Use consistent indentation (2 spaces)' - 'Follow language-specific naming conventions' documentation: - 'Include JSDoc comments for all functions' - 'Maintain up-to-date README files' testing: - 'Write unit tests for all new features' - 'Maintain minimum 80% code coverage'
# Security Guidelines security: authentication: - 'Implement proper token validation' - 'Use environment variables for secrets' dataProtection: - 'Sanitize all user inputs' - 'Implement proper error handling'
Be Specific
Maintain Organization
Regular Updates
# Common Patterns Example patterns: components: - pattern: 'Use functional components by default' - pattern: 'Implement error boundaries for component trees' stateManagement: - pattern: 'Use React Query for server state' - pattern: 'Implement proper loading states'
Commit the Rules
.clinerules
in version controlTeam Collaboration
Rules Not Being Applied
Conflicting Rules
Performance Considerations
# Basic .clinerules Example project: name: 'Web Application' type: 'Next.js Frontend' standards: - 'Use TypeScript for all new code' - 'Follow React best practices' - 'Implement proper error handling' testing: unit: - 'Jest for unit tests' - 'React Testing Library for components' e2e: - 'Cypress for end-to-end testing' documentation: required: - 'README.md in each major directory' - 'JSDoc comments for public APIs' - 'Changelog updates for all changes'
# Advanced .clinerules Example project: name: 'Enterprise Application' compliance: - 'GDPR requirements' - 'WCAG 2.1 AA accessibility' architecture: patterns: - 'Clean Architecture principles' - 'Domain-Driven Design concepts' security: requirements: - 'OAuth 2.0 authentication' - 'Rate limiting on all APIs' - 'Input validation with Zod'
# State Management Standards for HTMX This document outlines coding standards for managing state in HTMX applications. It emphasizes maintainability, performance, and security. It focuses on approaches to managing application state, data flow, reactivity, and how these principles apply to HTMX specifically. ## 1. Understanding State in HTMX Applications ### 1.1 What is State? State refers to the data an application uses to operate. In web applications, this can range from simple UI elements (like a button's disabled status) to complex server-side data. In HTMX, state management revolves around how data is fetched, displayed, updated, and persisted across HTTP requests and responses. ### 1.2 Challenges of State Management with HTMX HTMX, by design, pushes complexity to the server-side by leveraging the backend to handle significant parts of application logic. This means effective state management often involves: * Seamlessly synchronizing client-side UI with server-side data changes. * Minimizing unnecessary server round trips to improve performance. * Handling complex data relationships and dependencies efficiently. * Implementing robust error handling and data validation. ## 2. Core Principles for State Management ### 2.1 Server-Driven State * **Do This:** Centralize the source of truth for application state on the server. Use HTMX to request and render only the necessary UI fragments based on the server's state. * **Don't Do This:** Avoid excessive client-side state, especially for critical data. Relying heavily on client-side JavaScript to manage core application state negates the benefits of HTMX. * **Why:** Ensures data consistency, simplifies updates, and improves security by keeping critical logic on the server. ### 2.2 Minimal Client-Side State * **Do This:** Use client-side state sparingly, primarily for transient UI concerns like local form validation or temporary UI effects. HTMX's ability to update specific UI elements via AJAX requests reduces the need for elaborate client-side state management. * **Don't Do This:** Store persistent data like user IDs or session tokens in client-side JavaScript variables or local storage without proper security measures. * **Why:** Reduces complexity, minimizes the risk of client-side vulnerabilities, and leverages the server for data integrity. ### 2.3 Idempotent Requests * **Do This:** Design HTMX endpoints to be idempotent where possible. This means that making the same request multiple times has the same effect as making it once. For example, a "toggle" button should be handled on the server in a way that consistently flips the state, regardless of how many times the request is sent. * **Don't Do This:** Implement endpoints that rely on request order for correct state updates, as network conditions can cause out-of-order requests. * **Why:** Improves resilience and simplifies error handling. If a request fails, it is safe to retry it without causing unintended side effects. ### 2.4 Optimistic Updates * **Do This:** For immediate UI feedback, consider optimistic updates – updating the UI as if the request will succeed, then reverting the UI if an error occurs. Use "hx-swap" modifiers like "settle" to manage UI transitions smoothly. * **Don't Do This:** Optimistically update the UI without implementing proper error handling and rollback mechanisms. * **Why:** Improves user experience by providing instant feedback, but requires careful error management to prevent data inconsistencies. ### 2.5 Data Contracts * **Do This:** Define clear data contracts between the client and server. Use shared schemas (e.g., JSON Schema, OpenAPI) to ensure both sides understand the structure of requests and responses. * **Don't Do This:** Make implicit assumptions about data formats or types. This can lead to unexpected errors and data corruption. * **Why:** Improves maintainability, reduces integration errors, and provides clear documentation for developers. ## 3. Implementing State Management Techniques ### 3.1 Server-Side Sessions * **Standard:** Use server-side sessions for managing user authentication, authorization, and persistent data. HTMX interacts with session data indirectly through HTTP requests and responses. * **Do This:** Store user-specific data in session variables or cookies. Authenticate users and authorize based on server-side session data. * **Don't Do This:** Expose sensitive session data directly to the client. """html <!-- Example: Displaying user-specific data based on session data --> <div id="user-info" hx-get="/user/profile" hx-trigger="load"> <!-- Content will be loaded from /user/profile --> </div> """ """python # Example (Python/Flask): Server endpoint for user profile from flask import Flask, session, render_template app = Flask(__name__) app.secret_key = 'your_secret_key' # Change in production! @app.route("/user/profile") def user_profile(): if 'user_id' in session: user_id = session['user_id'] # Fetch user data from database based on user_id user_data = get_user_data(user_id) # Assume get_user_data is a function to fetch from DB return render_template('user_profile.html', user=user_data) else: return "<p>Please log in.</p>" """ ### 3.2 "hx-vals" for Passing Client-Side Data * **Standard:** Use "hx-vals" to pass context directly from the client to the server alongside requests. This is helpful for including simple form data or UI state (avoid complex client objects). * **Do This:** Use JSON syntax to encode complex data structures in "hx-vals". Keep the data minimal and specific to the current request. * **Don't Do This:** Include large or sensitive data in "hx-vals". Always validate data received from the client on the server. """html <!-- Example: Passing form data with hx-vals --> <form hx-post="/submit" hx-target="#result"> <input type="text" name="username" id="username" value="default_user"> <button hx-vals='{"theme": "dark", "priority": "high"}'>Submit</button> </form> <div id="result"></div> """ """python # Example (Python/Flask): Server endpoint handling hx-vals data from flask import Flask, request app = Flask(__name__) @app.route("/submit", methods=['POST']) def submit_form(): username = request.form.get('username') theme = request.values.get('theme') # access data sent in hx-vals priority = request.values.get('priority') # Process the form data and theme/priority result_message = f"Username: {username}, Theme: {theme}, Priority: {priority}" return f"<p>{result_message}</p>" """ ### 3.3 Hidden Inputs for Carrying State * **Standard:** Use hidden input fields to maintain state across multiple HTMX requests, especially when dealing with multi-step forms or complex UI flows. * **Do This:** Update hidden input fields using HTMX's "hx-swap="outerHTML"" or "hx-swap="innerHTML"" to ensure they contain the latest state. * **Don't Do This:** Rely solely on URL parameters for state, as they can become unwieldy and difficult to manage. """html <!-- Example of using hidden input to maintain state across requests --> <div id="myForm"> <p>Step 1: Enter your name</p> <input type="text" name="name" hx-post="/step2" hx-target="#myForm" hx-swap="outerHTML"> <input type="hidden" id="currentStep" name="currentStep" value="1"> </div> """ """python # Python/Flask example server side: from flask import Flask, request, render_template app = Flask(__name__) @app.route("/step2", methods=['POST']) def step2(): name = request.form['name'] current_step = int(request.form['currentStep']) next_step = current_step + 1 return render_template('step2.html', name=name, current_step=next_step) """ """html <!-- step2.html --> <div id="myForm"> <p>Step 2: Confirm your name</p> <p>Name: {{ name }}</p> <input type="hidden" id="currentStep" name="currentStep" value="{{ current_step }}"> <button hx-post="/submitForm" hx-target="#result" hx-swap="outerHTML">Submit</button> </div> <div id="result"></div> """ ### 3.4 URL-Based State * **Standard:** Use URL parameters or the fragment identifier (hash) to represent shareable or bookmarkable application state. * **Do This:** Use "hx-push-url" to update the browser's URL when the application state changes. Consider using a utility library to parse and serialize URL parameters. * **Don't Do This:** Store sensitive data in URL parameters as they are visible in browser history and can be easily shared. """html <!-- Example: Updating the URL with hx-push-url --> <button hx-get="/items?page=2" hx-target="#items" hx-push-url="true">Next Page</button> <div id="items"> <!-- Items will be loaded here --> </div> """ ### 3.5 Client-Side Data Storage (Use Sparingly) * **Standard:** Use browser-based storage (localStorage or sessionStorage) only for non-sensitive, short-lived data. Use it judiciously as it adds complexity to the client-side. * **Do This:** Encrypt sensitive data before storing it in localStorage. Always validate data retrieved from localStorage before using it. Limit the amount of data stored in localStorage to avoid performance issues. * **Don't Do This:** Store sensitive information like passwords or API keys directly in localStorage. *Important: Storing sensitive data, even encrypted, on the client-side comes with inherent risks. Avoid it if possible.* """javascript // Example (JavaScript): Using localStorage to store theme preference function setTheme(theme) { localStorage.setItem('theme', theme); document.documentElement.className = theme; } function getTheme() { return localStorage.getItem('theme') || 'light'; // Default to light } // On page load: document.addEventListener('DOMContentLoaded', () => { setTheme(getTheme()); }); """ """html <!-- HTML implementation to toggle themes --> <button onclick="toggleTheme()">Toggle Theme</button> <script> function toggleTheme() { const currentTheme = localStorage.getItem('theme') || 'light'; const newTheme = currentTheme === 'light' ? 'dark' : 'light'; setTheme(newTheme); // Using the setTheme function from the previous example } </script> """ ### 3.6 Websockets for Real-Time Updates * **Standard:** Use WebSockets for real-time updates and bidirectional data flow. Integrate with HTMX to dynamically update UI elements based on WebSocket messages. * **Do This:** Use a well-established WebSocket library (e.g., Socket.IO, SockJS). Ensure WebSocket connections are properly authenticated and authorized. * **Don't Do This:** Abuse WebSockets for simple, infrequent updates that can be handled with regular HTTP requests. """html <!-- Example of using WebSockets with HTMX --> <div id="realtime-data"> <!-- Data will be updated via WebSocket --> Loading... </div> <script> // Example (JavaScript): Connecting to a WebSocket and updating the UI const socket = new WebSocket('ws://localhost:8000/ws'); socket.onmessage = function(event) { const data = JSON.parse(event.data); document.getElementById('realtime-data').innerHTML = data.message; }; </script> """ ### 3. 7 "hx-ext": WebSockets Extension HTMX provides a websocket extension - "hx-ext="ws"". This extension simplifies websocket connection and updates and allows you to use HTMX attributes to control the websocket connection and UI updates. * **Standard:** Use the "ws" extension is often preferable to manually managing websocket connections in javascript as in the previous example * **Do This:** Use attributes like "ws-connect", "ws-send", and "ws-swap". * **Don't Do This:** Mix manual Javascript websocket connection handling with the "ws" extension for the same element. """html <!-- Connect to websocket --> <div id="myDiv" ws-connect="/ws"> Websocket Not Connected. </div> <!-- After connection, the DIV will automatically be populated by the server --> <!-- Send data to the server --> <input type="text" ws-send="keyup" /> """ ## 4. Common Anti-Patterns ### 4.1 Over-reliance on Client-Side JavaScript * **Anti-Pattern:** Using JavaScript to manage core application state that should be handled on the server. * **Solution:** Refactor the application to move state management logic to the server. Use HTMX to request and render only the necessary UI fragments. ### 4.2 Inconsistent Data Validation * **Anti-Pattern:** Performing data validation only on the client-side, without server-side validation. * **Solution:** Always validate data on both the client and server. Client-side validation provides immediate feedback, while server-side validation ensures data integrity. ### 4.3 Mixing Concerns * **Anti-Pattern:** Combining data fetching, state management, and UI rendering logic in a single component. * **Solution:** Separate concerns by using dedicated components or services for each task. This improves testability and maintainability. ### 4.4 Neglecting Error Handling * **Anti-Pattern:** Neglecting to handle errors gracefully, especially when performing optimistic updates. * **Solution:** Implement comprehensive error handling mechanisms to ensure that the UI is updated correctly, even when requests fail. ## 5. Security Considerations ### 5.1 Input Sanitization * **Standard:** Sanitize all user inputs on the server to prevent XSS attacks. Use a well-established sanitization library or framework. * **Do This:** Use parameterized queries to prevent SQL injection attacks. * **Don't Do This:** Trust client-side data without proper validation and sanitization. ### 5.2 Authentication and Authorization * **Standard:** Implement robust authentication and authorization mechanisms to protect sensitive data and functionality. * **Do This:** Use server-side sessions to manage user authentication state. * **Don't Do This:** Expose sensitive data or functionality to unauthorized users. ### 5.3 CSRF Protection * **Standard:** Implement CSRF protection to prevent cross-site request forgery attacks. * **Do This:** Include a CSRF token in forms and AJAX requests. Validate the token on the server. ## 6. Performance Optimization ### 6.1 Minimize Network Requests * **Standard:** Reduce the number of HTTP requests by batching updates or using data compression techniques. * **Do This:** Use caching to store frequently accessed data on the server or client. * **Don't Do This:** Make unnecessary requests for data that is already available. ### 6.2 Optimize Rendering * **Standard:** Optimize UI rendering by using efficient DOM manipulation techniques. * **Do This:** Use HTMX's "hx-swap" modifiers to control how UI elements are updated. * **Don't Do This:** Re-render entire pages when only small updates are necessary. ### 6.3 Use Caching Strategically * **Standard:** Implement caching effectively at various levels—browser, CDN, server—to minimize latency and reduce server load. * **Do This:** Leverage HTTP caching headers (e.g., "Cache-Control", "ETag") to instruct browsers and CDNs on how to cache responses. Use server-side caching mechanisms (e.g., Redis, Memcached) for frequently accessed data. * **Don't Do This:** Cache sensitive or personalized data without proper security measures. Set excessively long cache durations, which can lead to stale data. * **Example:** Setting Cache-Control headers in Python (Flask) """python from flask import Flask, make_response app = Flask(__name__) @app.route('/cached_data') def cached_data(): data = fetch_expensive_data() # Assume this function fetches data that takes time response = make_response(data) response.headers['Cache-Control'] = 'public, max-age=3600' # Cache for 1 hour return response """ ## 7. Testing State Management ### 7.1 Unit Tests * **Standard:** Write unit tests to verify the behavior of individual components and functions involved in state management. ### 7.2 Integration Tests * **Standard:** Write integration tests to verify the interaction between different components and services. ### 7.3 End-to-End Tests * **Standard:** Write end-to-end tests to verify the overall behavior of the application, including state management. ## 8. Conclusion These coding standards provide a foundation for building maintainable, performant, and secure HTMX applications. By following these guidelines, developers can effectively manage state and leverage the full potential of HTMX while avoiding common pitfalls. Remember to adapt these standards to the specific needs of your project and stay up-to-date with the latest HTMX features and best practices.
# Core Architecture Standards for HTMX This document outlines the core architectural standards for building robust, maintainable, and scalable web applications using HTMX. It focuses on fundamental patterns, project structure, and organization principles, specifically within the context of HTMX's unique approach to front-end development. These standards are based on the latest version of HTMX and promote modern best practices. ## 1. Project Structure and Organization A well-defined project structure is crucial for maintainability and collaboration. This section defines the recommended file organization and component structure for HTMX projects. ### 1.1 Directory Structure **Do This:** Adopt a feature-oriented directory structure. Group related files (HTML templates, CSS, JavaScript – if needed - server-side logic) within feature-specific directories. **Don't Do This:** Create a structure based solely on file types (e.g., a single 'templates' directory, a single 'css' directory). This leads to scattering related code across multiple directories and makes features harder to locate and maintain. **Why:** Feature-oriented structure improves code discoverability and reduces cognitive load for developers. When a feature needs modification, all relevant files are located together. **Example:** """ my-project/ ├── backend/ # Server-side code (e.g., Python/Flask, Node.js/Express, etc.) ├── frontend/ # HTMX Specific files. This directory is served staticly │ ├── components/ # Reusable UI components │ │ ├── button/ │ │ │ ├── button.html # Template fragment │ │ │ ├── button.css # Styles (optional) │ │ │ └── button.js # Vanilla JS logic (only if absolutely necessary) │ │ ├── modal/ │ │ │ ├── modal.html │ │ │ └── modal.css │ ├── pages/ # Complete page templates │ │ ├── home.html │ │ ├── about.html │ ├── styles/ # Global CSS │ │ ├── main.css │ ├── scripts/ # Global Javascript (Use with caution) │ │ ├── main.js │ ├── images/ # Static Images if necessary. Prefer using base64 in HTML or remote URLs. │ ├── htmx.min.js # HTMX Library │ └── index.html # Main application entry-point / layout (if applicable) ├── README.md └── requirements.txt # Python dependencies (example) """ ### 1.2 Component-Based Architecture **Do This:** Design your UI as a collection of reusable components. Each component should encapsulate a specific piece of functionality (e.g., a search bar, a product card, a modal). **Don't Do This:** Create monolithic HTML pages with tightly coupled logic. This results in code duplication and makes it harder to maintain and reuse parts of the UI. **Why:** Component-based design promotes modularity, reusability, and testability. Components can be easily composed to build complex UIs, and changes to one component are less likely to affect other parts of the application. HTMX works perfectly with component-based design. **Example:** A reusable button component: """html <!-- frontend/components/button/button.html --> <button class="btn btn-primary" hx-get="{{ url }}" hx-target="{{ target }}" hx-swap="{{ swap }}"> {{ text }} </button> """ Usage in a page: """html <!-- frontend/pages/home.html --> <!DOCTYPE html> <html> <head> <title>Home</title> <link rel="stylesheet" href="/styles/main.css"> <script src="/htmx.min.js"></script> </head> <body> <h1>Welcome!</h1> {% include "components/button/button.html" with context={"url": "/load-data", "target": "#data-container", "swap": "innerHTML", "text": "Load Data"} %} <div id="data-container"> <!-- Data will be loaded here --> </div> </body> </html> """ ### 1.3 Separation of Concerns **Do This:** Keep HTML templates focused on structure and presentation. Move complex logic to the server-side, or, *only when necessary* to small, well-contained JavaScript modules. **Don't Do This:** Embed large amounts of JavaScript directly within HTML templates or overuse inline styles. **Why:** Separation of concerns improves code readability, maintainability, and testability. It also makes it easier to change the presentation without affecting the application's logic and vice versa. HTMX strongly encourages leveraging server-side rendering for the majority of the application's logic. **Example:** Correct Separation of Concerns: """html <!-- frontend/components/product-card/product-card.html --> <div class="product-card"> <h2>{{ product.name }}</h2> <p>{{ product.description }}</p> <button hx-post="/add-to-cart" hx-target="#cart-items" hx-swap="beforeend" hx-vals='{"product_id": "{{ product.id }}"}'> Add to Cart </button> </div> """ Anti-Pattern (Mixing presentation and excessive JavaScript): """html <!-- frontend/components/product-card/product-card.html (BAD) --> <div class="product-card"> <h2>{{ product.name }}</h2> <p>{{ product.description }}</p> <button onclick="addToCart('{{ product.id }}')">Add to Cart</button> </div> <script> function addToCart(productId) { // Complex logic here...Avoid please. fetch('/add-to-cart', { method: 'POST', body: JSON.stringify({product_id: productId}), headers: {'Content-Type': 'application/json'} }) .then(response => response.text()) .then(data => { document.getElementById('cart-items').insertAdjacentHTML('beforeend', data); }); } </script> """ ### 1.4 Single Responsibility Principle (SRP) with HTMX **Do This:** Ensure that each HTML component, especially those targeted by HTMX requests, has a *single, well-defined reason to change*. This directly relates to the component's responsibility within the application. **Don't Do This:** Create "god components" that handle multiple unrelated functions or display diverse data sets. This leads to complex templates, bloated server-side code, and increased difficulty in maintaining the application. **Why:** Adhering to SRP improves the modularity, readability, and maintainability of your HTMX application. It makes testing easier, reduces the impact of changes, and improves the reusability of components. **Example:** Imagine a component that displays user information and also handles user deletion. This violates SRP. Instead, split it into two components: one for displaying user details and another (likely a button or link) for initiating the delete action. **Good:** """html <!-- frontend/components/user-details.html --> <div id="user-{{user.id}}"> <h2>{{ user.name }}</h2> <p>{{ user.email }}</p> <!-- Delete User component will go here --> </div> """ """html <!-- frontend/components/delete-user-button.html --> <button hx-delete="/users/{{user.id}}" hx-target="#user-{{user.id}}" hx-swap="outerHTML" class="btn btn-danger"> Delete User </button> """ **Anti-Pattern (Violates SRP):** """html <!-- frontend/components/user.html (BAD) --> <div id="user-{{user.id}}"> <h2>{{ user.name }}</h2> <p>{{ user.email }}</p> <button hx-delete="/users/{{user.id}}" hx-target="#user-{{user.id}}" hx-swap="outerHTML" class="btn btn-danger"> Delete User </button> {% if show_admin_options %} <button hx-get="/users/{{user.id}}/edit" hx-target="#user-{{user.id}}" hx-swap="outerHTML">Edit User</button> {% endif %} </div> """ In the anti-pattern, the component handles both displaying user information and potentially admin-related actions like editing, depending on the "show_admin_options" variable. This combines different responsibilities into a single component, making it more complex and harder to test. The better approach is to separate the admin-related actions into distinct components, conditionally included on the page based on the user's role. ## 2. Architectural Patterns for HTMX This Section outlines common architectural patterns for creating Single Page Applications (SPAs) and Multi-Page Applications using HTMX. ### 2.1 Progressive Enhancement **Do This:** Build your application with standard HTML forms and links first. Then, use HTMX to progressively enhance the user experience by adding AJAX functionality without requiring a full page reload. **Don't Do This:** Rely *solely* on HTMX from the start, creating an application that is unusable without JavaScript. **Why:** Progressive enhancement ensures that your application is accessible to users with JavaScript disabled or limited network connectivity. It also provides a solid foundation for search engine optimization (SEO). **Example:** Standard HTML form (works without JavaScript): """html <form action="/search" method="GET"> <input type="text" name="query" id="search-input" placeholder="Search..."> <button type="submit">Search</button> </form> <div id="search-results"> <!-- Search results will be displayed here --> </div> """ Progressively enhanced with HTMX: """html <form action="/search" method="GET" hx-get="/search" hx-target="#search-results" hx-indicator="#search-indicator"> <input type="text" name="query" id="search-input" placeholder="Search..."> <button type="submit">Search</button> <img id="search-indicator" class="htmx-indicator" src="/images/spinner.gif"> </form> <div id="search-results"> <!-- Search results will be displayed here --> </div> """ In this example the submit button will do the default browser behavior if javascript is disabled. With javascript enabled, the HTMX form will intercept the form, and do an AJAX request. ### 2.2 Server-Driven UI **Do This:** Embrace server-side rendering for most of your UI. Use HTMX to fetch and update small fragments of HTML from the server in response to user interactions. **Don't Do This:** Create a client-side JavaScript application and use HTMX only for data fetching. If you're doing this, you're likely missing the point of HTMX and should re-evaluate your architectural choices. **Why:** Server-driven UI simplifies development, improves initial page load performance, and reduces the amount of JavaScript required. It also leverages the server's resources for rendering and data processing. **Example** Implement a simple counter. """html <!-- frontend/pages/counter.html --> <!DOCTYPE html> <html> <head> <title>Counter</title> <script src="/htmx.min.js"></script> </head> <body> <h1>Counter</h1> <div id="counter"> {{ count }} </div> <button hx-post="/increment" hx-target="#counter" hx-swap="innerHTML">+</button> </body> </html> """ Server-side (Python/Flask Example): """python # backend/app.py from flask import Flask, render_template, request app = Flask(__name__) count = 0 @app.route('/') def index(): global count return render_template('counter.html', count=count) @app.route('/increment', methods=['POST']) def increment(): global count count += 1 return str(count) # Return just the updated count if __name__ == '__main__': app.run(debug=True) """ **Explanation:** The browser renders the initial HTML (including "htmx.min.js"). When the user clicks the "+" button: 1. **HTMX Intercepts:** HTMX intercepts the click event. 2. **AJAX Request:** HTMX performs a "POST" request to "/increment". 3. **Server-Side Logic:** The Flask server increments the count and returns the new count as plain text. 4. **HTML Update:** HTMX receives the response (e.g., "1", "2", etc.) and updates the content of the "#counter" element; by replacing the old text fragment by the new one fetched from the server. ### 2.3 Template Fragments and Composition **Do This:** Break down your UI into small, reusable template fragments. Use HTMX to fetch and compose these fragments dynamically to build complete pages or update existing content. **Don't Do This:** Return entire HTML pages for every request, even for small updates. This leads to unnecessary data transfer and slower response times. **Why:** Template fragments improve code reusability, reduce code duplication, and make it easier to update specific parts of the UI without reloading the entire page. **Example:** """html <!-- backend/templates/partials/product-list.html --> <ul> {% for product in products %} <li>{{ product.name }} - ${{ product.price }}</li> {% endfor %} </ul> """ """html <!-- backend/templates/pages/home.html --> <!DOCTYPE html> <html> <head> <title>Home</title> <script src="/htmx.min.js"></script> </head> <body> <h1>Products</h1> <div id="product-list"> {% include 'partials/product-list.html' %} </div> <button hx-get="/load-more-products" hx-target="#product-list" hx-swap="beforeend">Load More</button> </body> </html> """ ### 2.4 Utilizing HTMX Extensions **Do This:** Explore and utilize provided HTMX extensions (e.g., "morphdom", "ajax-header", "client-side-templates"). These extensions provide additional functionality and can simplify your code. Use them judiciously; don't add dependencies unless necessary. **Don't Do This:** Re-implement functionality that is already provided by HTMX extensions. **Why:** Extensions allow extending HTMX behavior in a declarative and maintainable way. They follow coding best practices and are tested by a wider community. **Example:** Using the "morphdom" extension: 1. Include extension """html <script src="https://unpkg.com/htmx.org/dist/ext/morphdom.js"></script> """ 2. Use the "morph:" modifier """html <div id="my-div"> <p>Some content</p> </div> <button hx-get="/new-content" hx-swap="morph:#my-div">Load New Content</button> """ The "morphdom" extension intelligently updates the DOM, preserving focus and state, leading to smoother transitions. ### 2.5 Idempotency and Safe Methods **Do This:** Ensure that your server-side endpoints are idempotent, especially those handling "POST", "PUT", and "DELETE" requests. The "GET" method has to be always idempotent, and should never change any state. Ideally, any endpoint that modify state should implement the POST-Redirect-GET pattern **Don't Do This:** Perform non-idempotent operations on "GET" requests. **Why:** Idempotency ensures that repeated requests have the SAME effect, preventing unintended side effects (e.g., duplicate orders, multiple deletions). HTMX, like any AJAX library, might retry requests under certain conditions (e.g., network errors). **Example:** """python # backend/app.py (Python/Flask Example) from flask import Flask, request, redirect, url_for app = Flask(__name__) items = {} # In-memory store (for demonstration purposes) next_item_id = 1 @app.route('/items', methods=['POST']) def create_item(): global next_item_id, items item_name = request.form.get('name') items[next_item_id] = item_name item_id = next_item_id next_item_id += 1 # POST-Redirect-GET pattern return redirect(url_for('get_items')) @app.route('/items', methods=['GET']) def get_items(): item_list = "<ul>" for id, name in items.items(): item_list += f"<li>{name} (ID: {id})</li>" item_list += "</ul>" return item_list if __name__ == '__main__': app.run(debug=True) """ In this example, creating an item creates it in the backend. The get items will get/display all items. ## 3. HTMX Specific Code Standards This section focuses specifically on HTMX attribute implementation best practices and details. ### 3.1 Consistent Attribute Usage **Do This:** Use consistent attribute naming and values throughout your application. Establish a standard for common HTMX attributes (e.g., "hx-target", "hx-swap", "hx-trigger"). **Don't Do This:** Use inconsistent attribute names or values across different parts of the application. This leads to confusion and makes it harder to maintain the code. **Why:** Consistency improves code readability and reduces the likelihood of errors. Enforce consistency through code reviews or linters. **Example:** Consistent "hx-swap" values: """html <button hx-post="/update" hx-target="#my-element" hx-swap="innerHTML">Update</button> <button hx-post="/delete" hx-target="#my-element" hx-swap="outerHTML">Delete</button> """ ### 3.2 "hx-vals" for Data Transmission **Do This:** Use the "hx-vals" attribute to send additional data to the server along with the HTMX request. This is especially useful for passing context or parameters required by your server-side logic. Use JSON format for complex data. **Don't Do This:** Rely solely on URL parameters or hidden form fields for transmitting data, especially for complex data structures. **Why:** "hx-vals" provides a clean and declarative way to associate data with an HTMX request. It promotes better organization and reduces the risk of errors. **Example:** """html <button hx-post="/update-item" hx-target="#item-details" hx-swap="innerHTML" hx-vals='{"item_id": 123, "quantity": 5}'> Update Item </button> """ ### 3.3 Targeting Strategies **Do This:** Choose the appropriate "hx-target" strategy based on the desired update behavior. Use CSS selectors for precise targeting of elements within the DOM. Keep selectors as specific as possible to avoid unexpected updates elsewhere. **Don't Do This:** Use overly broad CSS selectors that might inadvertently target unintended elements. Avoid targeting the "<body>" element unless you intend to replace the entire page content. **Why:** Precise targeting prevents unexpected UI updates and ensures that only the intended elements are modified. **Example:** Targeting a specific element by ID: """html <div id="my-container"> <h2>Title</h2> <p id="content">Some content</p> </div> <button hx-get="/load-new-content" hx-target="#content" hx-swap="innerHTML">Load New Content</button> """ ### 3.4 Swap Modifiers **Do This:** Effectively use swap modifiers (e.g. "beforeend", "afterend", "morph") to control how HTMX updates the DOM,. **Don't Do This:** Default to "innerHTML" blindly. Evaluate swapping strategies for optimal performance. **Why:** Choosing the right swap option ensures optimal UI updates, improves performance, and reduces the likelihood of unexpected side-effects. **Example:** """html <!-- Using afterend to insert content after an element --> <ul id="my-list"> <li>Item 1</li> <li>Item 2</li> </ul> <button hx-get="/add-item" hx-target="#my-list" hx-swap="beforeend">Add Item</button> <!-- Using morph to perform a smart diff of the new HTML and the old HTML --> <script src="https://unpkg.com/htmx.org/dist/ext/morphdom.js"></script> <div id="my-element"> <p>Some Text</p> </div> <button hx-get="/get_new_element" hx-swap="morph:#my-element /> """ ### 3.5 Trigger Management **Do This:** Employ a consistent and well-documented approach to event triggering. Use modifiers like "once", "throttle", and "debounce" to control the frequency of requests. Use "hx-trigger" effectively. **Don't Do This:** Overuse polling or create unnecessary request traffic **Why:** Correct trigger improves application performance and reduces server load. **Example:** """html <!-- Throttle a search request to be sent at most once every 200ms --> <input type="text" hx-get="/search" hx-target="#results" hx-trigger="keyup changed delay:200ms" name="q"> <!-- Trigger an event once --> <button hx-get="/login" hx-target="#login-form" hx-trigger="once">Login</button> """ ## 4. Performance Considerations Building performant applications is important. This rule helps deliver great experience. ### 4.1 Minimize DOM Updates **Do This:** Target the smallest possible DOM element that needs updating, and use the most efficient "hx-swap" strategy for the update use "outerHTML swap:none" to avoid the "double request problem with hx-boost. **Don't Do This:** Update large sections of the DOM unnecessarily, or use inefficient "hx-swap" strategies like "innerHTML" when "outerHTML" or "morph" would suffice. **Why:** Minimizing DOM updates reduces browser reflow and repaint operations, which can significantly improve performance, especially on complex pages. **Example:** Instead of replacing an entire list: """html <ul id="item-list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> <button hx-post="/add-item" hx-target="#item-list" hx-swap="innerHTML">Add Item</button> <!-- Inefficient --> """ Append only the new item: """html <ul id="item-list"> <li>Item 1</li> <li>Item 2</li> <li>Item 3</li> </ul> <button hx-post="/add-item" hx-target="#item-list" hx-swap="beforeend">Add Item</button> <!-- Efficient --> """ ### 4.2 Optimize Server Responses **Do This:** Ensure that your server generates HTML fragments quickly. Use caching strategies where appropriate to reduce database load and response times. Compress responses with Gzip or Brotli. **Don't Do This:** Generate HTML fragments slowly on the server, or neglect to cache frequently accessed data. **Why:** Slow server responses directly translate to a sluggish user experience. Optimizing server-side performance is critical for HTMX applications. ### 4.3 Lazy Loading and Pagination **Do This:** Implement lazy loading for images and other resources that are not immediately visible on the page. Use pagination to break up large datasets into smaller chunks. Add "hx-boost" to HTML elements, to persist them across pages. **Don't Do This:** Load all resources upfront, or display large datasets on a single page without pagination. **Why:** Lazy loading and pagination improve initial page load performance and reduce the amount of data transferred over the network. ### 4.4 Connection Pooling **Do This:** In backend implementations, ensure connection pooling is used to speed up database calls (if any) and/or connections to other downstream systems **Don't Do This:** Reestablish connections for every call. This is hugely inefficient. **Why:** Connection pools removes the overhead of establishing connections, improving performance significantly. """python # backend/app.py (Python/Flask Example with SQLAlchemy connection pooling) from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://user:password@host:port/database' app.config['SQLALCHEMY_POOL_SIZE'] = 5 # Number of connections in the pool app.config['SQLALCHEMY_MAX_OVERFLOW'] = 10 # Maximum overflow connections db = SQLAlchemy(app) # ... rest of your application code ... """ ## 5. Security Considerations It is important to follow best practices of Secure Development. ### 5.1 Input Validation and Output Encoding **Do This:** Validate all user input on the server-side to prevent injection attacks (e.g., XSS, SQL injection). Encode output properly before rendering it in HTML templates. **Don't Do This:** Trust user input blindly, or neglect to encode output properly. **Why:** Input validation and output encoding are essential for preventing security vulnerabilities. **Example:** Safe rendering, escaping HTML entities. """python # backend/app.py from flask import Flask, request, render_template, escape app = Flask(__name__) @app.route('/search') def search(): query = request.args.get('query') # Escape the user-provided query safe_query = escape(query) results = search_database(query) return render_template('search_results.html', query=safe_query, results=results) """ """html <!-- backend/templates/search_results.html --> <h1>Search Results for "{{ query }}"</h1> <!-- 'query' is already escaped --> <ul> {% for result in results %} <li>{{ result.title }}</li> {% endfor %} </ul> """ ### 5.2 CSRF Protection **Do This:** Implement CSRF (Cross-Site Request Forgery) protection for all state-changing requests. If a backend framework doesn't provide it, HTMX ships with the "ext/ajax-header" extension that simplifies this. Consider using appropriate headers to protect calls. **Don't Do This:** Disable CSRF protection, or rely solely on client-side validation. **Why:** CSRF protection prevents attackers from forging requests on behalf of authorized users. It also makes it easier to protect requests on the server. ### 5.3 Follow security best practices **Do This:** Always follow OWASP (Open Web Application Security Project) guidelines for security. **Don't Do This:** Disregard common known security mistakes, like keeping secrets on the front end. **Why:** Security best practices are well researched/vetted for security flaws. ## 6. Error Handling A well structured HTMX application will properly handle error conditions. ### 6.1 Specific Error Messages. **Do This:** Return specific and actionable error messages. **Don't Do This:** Return overly broad and not descriptive error messages. **Why:** Specific errors help when debugging. ### 6.2 Use hx-ext for error handling patterns **Do This:** Use the "hx-ext" for custom or shared error/alerting in HTMX **Don't Do This:** Reinvent the wheel and add more complex Javascript. **Why:** "hx-ext" extensions allow the extensions of HTMX, without lots of boilerplate code.
# Security Best Practices Standards for HTMX This document outlines security best practices for developing applications using HTMX. It provides guidance on mitigating common vulnerabilities and implementing secure coding patterns specifically within the HTMX context. ## 1. General Security Principles ### 1.1 Defense in Depth * **Do This:** Implement multiple layers of security controls. Don't rely on a single security measure. **Why:** If one security layer fails, other layers can still provide protection. **Example:** Combine input validation, output encoding, and Content Security Policy (CSP) to protect against XSS. * **Don't Do This:** Assume that your server-side framework or HTMX automatically handles all security concerns. **Why:** While frameworks provide helpful tools, you must configure and use them correctly. ### 1.2 Least Privilege * **Do This:** Grant users and processes only the minimum necessary permissions to perform their tasks. **Why:** Limits the potential damage from compromised accounts or processes. **Example:** Ensure database queries only have read access if they only need to fetch data. * **Don't Do This:** Run your application with root privileges or grant all users administrative access. **Why:** Exposes your entire system if compromised. ### 1.3 Input Validation * **Do This:** Validate all user inputs, both on the client-side (for improved UX) and, *critically*, on the server-side (for security). Server-side validation is MANDATORY. **Why:** Prevents malicious or malformed data from entering your system. **Example:** """html <input type="text" name="name" id="name" required minlength="3" maxlength="50"> """ """python # Server-side (Python/Flask example) from flask import request, jsonify import bleach @app.route('/update_name', methods=['POST']) def update_name(): name = request.form.get('name') if not name or len(name) < 3 or len(name) > 50: return jsonify({'error': 'Invalid name'}), 400 # Sanitize using bleach before storing sanitized_name = bleach.clean(name) # Store the sanitized_name in the database or process it # ... return jsonify({'message': 'Name updated successfully'}) """ * **Don't Do This:** Rely solely on client-side validation. It can easily be bypassed. **Why:** Client-side validation is only for user experience. Actual input scrubbing must be performed server-side. ### 1.4 Output Encoding * **Do This:** Encode all data before displaying it to the user. **Why:** Prevents XSS attacks by treating user-supplied data as plain text. **Example:** Use your server-side templating engine's escaping features (e.g., "{{ variable }}" in Jinja2, "@Html.Encode(variable)" in ASP.NET). Also use HTMX's built-in functionalities where appropriate. * **Don't Do This:** Directly insert user-provided data into HTML without encoding. **Why:** This is a direct path to XSS vulnerabilities. ### 1.5 Regular Security Assessments * **Do This:** Regularly perform security testing, code reviews, and penetration testing. **Why:** Identifies vulnerabilities early in the development process, before they can be exploited. * **Don't Do This:** Assume your application is secure just because it hasn't been attacked yet. **Why:** Security is an ongoing process, not a one-time fix. ## 2. HTMX-Specific Security Considerations ### 2.1 XSS Attacks * **Do This:** Use parameterized queries or ORMs to prevent SQL injection when interacting with databases. Critically, use output encoding in *all* responses that contain user-provided data. If using HTMX to update parts of the page, ensure the updates are correctly encoded. **Why:** Prevents attackers from injecting malicious SQL code into database queries. **Example:** """python # Using SQLAlchemy (Python) from flask import request, jsonify from sqlalchemy import text @app.route('/search', methods=['POST']) def search(): query = request.form.get('query') # NEVER do this: db.execute(f"SELECT * FROM items WHERE name LIKE '%{query}%'") # ALWAYS parametrize! result = db.execute(text("SELECT * FROM items WHERE name LIKE :query"), {'query': f"%{query}%"}) items = [dict(row) for row in result] # Convert to a list of dictionaries return jsonify(items) # Using htmx to update a part of the UI @app.route('/display', method=['POST']) def display() { user_string = request.form.get('user_string') sanitized_string = bleach.clean(user_string) # or equivalent escaping function for your language. return f"<p>{sanitized_string}</p>" # returning html, needs to be sanitized } """ * **Don't Do This:** Construct SQL queries by directly concatenating user-supplied strings. **Why:** This makes your application vulnerable to SQL injection attacks. * **Do This:** Employ proper escaping whenever using "hx-on" attributes to execute JavaScript snippets based on server response. Verify that you need to execute client-side script at all since this greatly increases complexity (and attack surface). Server Events may be a better option. **Why:** Protects against XSS vulnerabilities from responses. """html <div hx-get="/data" hx-trigger="click" hx-target="#result" hx-on::after-request="console.log('Request Complete: ' + event.detail.elt.innerHTML)"> Get Data </div> """ If the "innerHTML" contained injected code, it would be interpretted by the browser. ### 2.2 CSRF Attacks * **Do This:** Implement CSRF protection for all state-changing requests, especially those triggered by HTMX. Many frameworks provide built-in CSRF protection. **Why:** Prevents attackers from forging requests on behalf of authenticated users. **Example:** """html <form hx-post="/update_profile" hx-target="#profile-details"> <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"> <input type="text" name="name" value="{{ user.name }}"> <button>Update</button> </form> """ """python # Server-side (Flask example) from flask import request, jsonify, session from functools import wraps import secrets def generate_csrf_token(): token = secrets.token_urlsafe(16) session['csrf_token'] = token return token def validate_csrf_token(f): @wraps(f) def decorated_function(*args, **kwargs): token = request.form.get('csrf_token') if not token or token != session.get('csrf_token'): return jsonify({'error': 'CSRF token invalid'}), 400 return f(*args, **kwargs) return decorated_function @app.route('/update_profile', methods=['POST']) @validate_csrf_token def update_profile(): name = request.form.get('name') # Update the user's profile return jsonify({'message': 'Profile updated successfully'}) @app.route('/csrf_token') def get_csrf_token(): return jsonify({'csrf_token': generate_csrf_token()}) """ * **Don't Do This:** Disable CSRF protection or fail to validate the CSRF token. **Why:** Leaves your application vulnerable to CSRF attacks. ### 2.3 Open Redirects * **Do This:** Avoid redirecting users to URLs provided in request parameters. If a redirect is absolutely necessary, validate and sanitize the URL before redirecting. **Why:** Prevents attackers from redirecting users to malicious websites. **Example:** """python # Server-side (Python/Flask example) from flask import request, redirect from urllib.parse import urlparse @app.route('/redirect') def redirect_to(): next_url = request.args.get('next') if not next_url: return "Missing 'next' parameter", 400 parsed_url = urlparse(next_url) # Check if the hostname is in an allowed list allowed_hosts = ['example.com', 'safe-domain.com'] # Define safe domains if parsed_url.netloc not in allowed_hosts: return "Invalid 'next' URL", 400 return redirect(next_url) """ * **Don't Do This:** Unconditionally redirect users to URLs in request parameters. **Why:** Attackers can use this to redirect users to phishing sites or other malicious destinations. ### 2.4 HTMX and "HX-Location" Header The "HX-Location" header is a powerful HTMX feature for redirecting the browser. However, it requires careful handling to avoid security vulnerabilities. * **Do This:** Validate URLs specified in the "HX-Location" header on the server side before sending them to the client. Use a whitelist of allowed origins. Log all redirects for auditing. Never blindly trust user input for constructing the "HX-Location". **Why:** Prevents malicious redirects. User input can be tampered with and cause the user to be redirected to an attack site. **Example:** """python from flask import Flask, request, jsonify, make_response from urllib.parse import urlparse app = Flask(__name__) ALLOWED_DOMAINS = ['trusted.com', 'trusted.net'] #Add allowed domains in production @app.route('/redirect-user', methods=['POST']) def redirect_user(): target_url = request.form.get('url') if not target_url: return jsonify({'error': 'Missing URL parameter'}), 400 # Validate that URLs within the domain # Parse the URL to get the domain parsed_url = urlparse(target_url) domain = parsed_url.netloc # Check if the extracted domain is in the allow Domains list if domain not in ALLOWED_DOMAINS: return jsonify({'error': 'Invalid or illegal domain'}), 400 # Create a response response = make_response(jsonify({'success': 'Redirecting...'})) response.headers['HX-Location'] = target_url # Set Header to redirect # Log redirect for Auditing app.logger.warning(f"Redirected to url: {target_url}") return response """ **Don't Do This:** Directly use user-provided data to set the URL. ### 2.5 Client-Side Template Injection * **Do This:** Avoid using client-side templating libraries with HTMX if you are displaying user-provided data as it can potentially lead to client-side template injection attacks. If you must use them, properly escape and sanitize data before rendering it into templates. Server-side rendering with proper sanitization is highly recommended. **Why:** Attackers could inject malicious code into the template that gets executed in the client's browser. **Example (Avoid if possible):** """javascript //Example of a Vulnerable Code Snippet //This example passes user unvalidated data into a template //Avoid this approach as it can be exploited const userData = '{{user.name}}'; //Assume this is user data const template = "<div>Hello, ${userData}</div>" //Vulnerable document.getElementById('user-info').innerHtml = template; //Solution Approach const userData = "{{user.name}}"; // data from server const template = '<div>Hello, <span id="username"></span></div>'; document.getElementById('user-info').innerHtml = template; document.getELementById('username').textContent = userData; //Safer approach: Set text content for rendering """ * **Don't Do This:** Implement input validation. Rely solely on client-side validation. It can easily be bypassed **Why:** Client-side validation is only for user experience. Actual input scrubbing must be performed server-side. Sanitizing input data is important to mitigate injection attacks. ### 2.6 Secure Configuration * **Do This:** Keep your HTMX library updated. Regularly review your dependencies and their security advisories. Patch software promptly. **Why:** Helps ensure that known vulnerabilities are addressed quickly, reducing security risks. * **Don't Do This:** Use outdated software. It may contain unfixed security vulnerabilities. ### 2.7 Data Encryption * **Do This:** Encrypt sensitive data both in transit (using HTTPS) and at rest (in databases or file systems). **Why:** Compromised data is unreadable without the encryption key. Prevents unauthorized access. * **Don't Do This:** Store sensitive data in plain text. **Why:** Easier to understand plaintext data than encrypted data without the key. ### 2.8 Rate Limiting and Abuse Prevention * **Do This:** Implement rate limiting to prevent abuse and denial-of-service attacks. **Why:** Limits the number of requests a user or IP address can make within a given period. **Example:** Use a middleware to limit requests to a specific endpoint. """python # Server-side (Python/Flask example) from flask import Flask, request, jsonify from flask_limiter import Limiter from flask_limiter.util import get_remote_address app = Flask(__name__) # Rate limiting configuration: 10 requests per minute from the same IP address limiter = Limiter( get_remote_address, app=app, default_limits=["10 per minute"] ) @app.route('/search', methods=['POST']) @limiter.limit("10 per minute") # Apply rate limiting def search(): query = request.form.get('query') # Perform some search return jsonify({'results': []}) @app.errorhandler(429) def ratelimit_error(e): return jsonify({'error': 'Too many requests'}), 429 """ * **Don't Do This:** Allow unlimited requests to your API endpoints. **Why:** Makes your application vulnerable to abuse and denial-of-service attacks. ## 3. Security Headers * **Do This:** Configure your web server to send security-related HTTP headers. **Why:** Enhances security by enabling browser-side security features. **Examples:** * **Strict-Transport-Security (HSTS):** Enforces HTTPS connections. * **X-Frame-Options:** Prevents clickjacking attacks. * **X-Content-Type-Options:** Prevents MIME sniffing. * **Content-Security-Policy (CSP):** Controls the resources the browser is allowed to load. This is *critically* important when using HTMX. **Example:** """nginx # Nginx configuration add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"; add_header X-Frame-Options "DENY"; add_header X-Content-Type-Options "nosniff"; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://trusted-cdn.com; style-src 'self' https://trusted-cdn.com; img-src 'self' data:;"; """ * **Don't Do This:** Neglect to set security headers. **Why:** Leaves your application vulnerable to various attacks. ## 4. Handling Sensitive Data in HTMX * **Do This:** Avoid sending sensitive data (e.g., passwords, API keys, PII) in HTMX requests or responses if possible. Find alternative approaches if possible. If it is absolutely necessary to send sensitive data, encrypt it. **Why:** Reduces the risk of exposure through network sniffing or logging. * **Don't Do This:** Send sensitive data in clear text over HTTP. **Why:** Data can be intercepted by attackers. ### 4.1 API Keys * **Do This:** Never embed API keys directly in client-side code (HTML, JavaScript). Store and retrieve them securely on the server-side, and only expose the necessary functionality through your API endpoints. **WHY:** Embedding API keys in client-side exposes those keys to the outside world and can result in compromised services and unexpected bills. **Example:** """javascript // Never do this! // const apiKey = "YOUR_API_KEY"; //Insecure method // use fetch or axios to securely call API requests // Server-side (Node.js) app.get('/api', async (req, res) => { try { const apiKey = process.env.API_KEY; //Use in production, protect API keys //Other important code } catch (error) { console.error('Error fetching Data:', error); res.status(500).send(('Internal Server Error')); } }); """ * **Don't Do This:** Store API Keys directly in client-side code. This is extremely bad practice and a guaranteed security breach. ## 5. Monitoring and Logging * **Do This:** Implement comprehensive logging to record security-related events, such as authentication attempts, authorization failures, and input validation errors. Actively monitor these logs for suspicious activity. **Why:** Provides visibility into potential attacks and security breaches. Facilitates incident response. * **Don't Do This:** Disable logging or neglect to monitor logs. **Why:** Makes it difficult to detect and respond to security incidents. ## 6. Third-Party Libraries * **Do This:** Carefully evaluate the security of any third-party libraries or components you use in your HTMX project. Keep libraries up to date and promptly address any reported vulnerabilities. Use tools like "npm audit" (for Node.js) or "pip audit" (for Python) to scan for known vulnerabilities. **Why:** Third-party libraries can introduce vulnerabilities into your application. * **Don't Do This:** Blindly trust third-party components without security assessment. **Why:** Attackers may exploit vulnerabilities in third-party code. By adhering to these security best practices, you can significantly reduce the risk of vulnerabilities and build more secure HTMX applications. This document should be used as a starting point for ongoing security efforts, regularly reviewed and updated to address new threats and emerging best practices. Consistent application of these standards is paramount for robust web application security.
# Deployment and DevOps Standards for HTMX This document outlines the coding standards and best practices for deployment and DevOps related aspects of HTMX applications. Adhering to these standards will ensure maintainable, scalable, performant, and secure deployments. ## 1. Build Processes and CI/CD for HTMX ### 1.1. Standard: Automate Build and Deployment Processes **Do This:** Implement a CI/CD pipeline to automate building, testing, and deploying your HTMX application changes. **Don't Do This:** Manually build and deploy your application. This is error-prone and time-consuming. **Why:** Automation reduces errors, speeds up deployment, and ensures consistency across environments. **Example:** Consider a simple CI/CD pipeline using GitHub Actions: """yaml # .github/workflows/deploy.yml name: Deploy HTMX App on: push: branches: - main jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python 3.9 uses: actions/setup-python@v4 with: python-version: 3.9 - name: Install Dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run Tests run: pytest deploy: needs: build runs-on: ubuntu-latest steps: - name: Deploy to Production (Example) run: | # Replace with your actual deployment script echo "Deploying to Production..." # Example using SSH ssh user@your-server "bash deploy.sh" """ "deploy.sh" (example): """bash #!/bin/bash # Assumes a simple Flask or Django application cd /var/www/your-htmx-app git pull origin main # Example: restart gunicorn process if needed sudo systemctl restart your-app.service """ **Anti-Pattern:** Manual deployments are a primary source of errors and headaches in modern development. ### 1.2. Standard: Version Control All Code and Configuration **Do This:** Store all HTMX-related code (including HTML, CSS, JavaScript, backend application code, and infrastructure configuration) in a version control system like Git. **Don't Do This:** Store code or configuration locally without version control. **Why:** Version control provides a history of changes, enables collaboration, and allows for easy rollback to previous versions. **Example:** Using Git for version control: """bash git init git add . git commit -m "Initial commit" git remote add origin your-repo-url git push -u origin main """ **Anti-Pattern:** Failing to version control infrastructure-as-code (IaC) can lead to inconsistencies and difficulties in replicating environments. ### 1.3. Standard: Use Infrastructure as Code (IaC) **Do This:** Define your infrastructure using code (e.g., Terraform, AWS CloudFormation, Ansible). **Don't Do This:** Manually provision and configure infrastructure resources. **Why:** IaC promotes consistency, repeatability, and reduces the risk of configuration drift across environments. **Example:** Defining an AWS S3 bucket using Terraform: """terraform resource "aws_s3_bucket" "htmx_assets" { bucket = "your-htmx-assets-bucket" acl = "private" tags = { Name = "HTMX Static Assets Bucket" } } """ **Technology-Specific Details:** HTMX often interacts with backend servers. Using IaC to manage those backend resources is best practice. Cloud providers offer managed services (e.g., databases, message queues) fully integrable with IaC and backend systems. ### 1.4. Standard: Implement Automated Testing **Do This:** Include unit tests, integration tests, and end-to-end tests in your CI/CD pipeline. **Don't Do This:** Deploy code without running automated tests. **Why:** Automated testing helps catch bugs early, reduces the risk of regressions, and ensures that changes don't break existing functionality. **Example:** Using pytest for backend testing """python # tests/test_api.py import pytest from your_app import app @pytest.fixture def client(): with app.test_client() as client: yield client def test_htmx_endpoint(client): response = client.get('/htmx-endpoint', headers={'HX-Request': 'true'}) assert response.status_code == 200 assert b'This is an HTMX response' in response.data """ **Technology-Specific Details:** You can use tools like Cypress or Selenium to automate browser-level testing to specifically validate HTMX interactions. Include assertions to check for the presence of specific HTML elements after an HTMX request. """javascript // example Cypress test verifying content after HTMX request describe('HTMX interaction test', () => { it('Loads content after button click', () => { cy.visit('/your-page'); cy.get('#your-button').click(); cy.get('#target-element').should('contain', 'New content from HTMX'); }); }); """ ### 1.5. Standard: Use Containerization (Docker) **Do This:** Package your HTMX application (including backend and static assets) into Docker containers. **Don't Do This:** Deploy your application directly to a server without containerization. **Why:** Containerization provides isolation, portability, and consistency across different environments. **Example:** A simple Dockerfile """dockerfile FROM python:3.9-slim-buster WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["gunicorn", "--bind", "0.0.0.0:8000", "your_app:app"] """ **Technology-Specific Details:** For HTMX applications, consider using multi-stage Docker builds to optimize the size of your final image. A good practice is moving your static files to a CDN rather than packaging them in the image. This reduces image sizes and improves performance. ### 1.6. Standard: Implement Configuration Management **Do This:** Use environment variables or configuration files to manage application settings. **Don't Do This:** Hardcode sensitive information (e.g., API keys, database passwords) in your code. **Why:** Configuration management allows you to easily change application settings without modifying the code, promoting flexibility and security. **Example:** Using environment variables in Python: """python import os database_url = os.environ.get("DATABASE_URL") api_key = os.environ.get("API_KEY") """ **Technology-Specific Details:** When deploying HTMX applications, you might need specific environment variables for configuring the backend to handle requests from different domains or setting up the CSRF protection appropriately based on the reverse proxy setup. ## 2. Production Considerations for HTMX Applications ### 2.1. Standard: Optimize Static Asset Delivery **Do This:** Use a Content Delivery Network (CDN) to serve static assets like CSS, JavaScript, and images. Configure proper caching headers. **Don't Do This:** Serve static assets directly from your application server. **Why:** CDNs improve performance by caching assets closer to users, reducing latency. **Example:** Serving static assets from AWS S3 and CloudFront: 1. Upload static assets to an S3 bucket. 2. Create a CloudFront distribution pointing to the S3 bucket. 3. Configure caching headers in CloudFront (e.g., set "Cache-Control" header). """html <link rel="stylesheet" href="https://your-cloudfront-domain/styles.css"> <script src="https://your-cloudfront-domain/htmx.min.js"></script> """ **Technology-Specific Details:** Ensure the HTMX library itself and any custom JavaScript enhancements are delivered quickly. Consider using subresource integrity (SRI) tags for enhanced security when loading external resources like HTMX from a CDN. """html <script src="https://unpkg.com/htmx.org@1.9.12" integrity="sha384-wnFHo8H1YdJHRhmpEixFwQ2azwg9JjryKtE7WJ8k62iMQR13cHpQXu3ih/Kura48" crossorigin="anonymous"></script> """ ### 2.2. Standard: Implement Logging and Monitoring **Do This:** Implement comprehensive logging and monitoring to track application health, performance, and errors. **Don't Do This:** Rely solely on manual inspection of logs. **Why:** Logging and monitoring provide insights into application behavior, enable proactive problem detection, and facilitate debugging. **Example:** Using a logging framework in Python: """python import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) try: result = 10 / 0 except Exception as e: logger.exception("An error occurred: %s", e) """ **Technology-Specific Details:** Monitor critical HTMX-related metrics, such as the latency of HTMX requests, error rates specific to HTMX endpoints, and the performance impact of dynamically loaded content. Utilize server-side logging to track the origin (user, session) of HTMX requests, which aids in debugging complex user interactions. ### 2.3. Standard: Secure Your Application **Do This:** Implement security best practices to protect your application from common attacks. **Don't Do This:** Ignore security considerations. **Why:** Security is crucial to protect user data, prevent unauthorized access, and maintain application integrity. **Example:** Security measures * **CSRF Protection:** Implement CSRF protection to prevent cross-site request forgery attacks. * **Input Validation:** Validate user input to prevent injection attacks (e.g., SQL injection, XSS). * **HTTPS:** Always use HTTPS to encrypt communication between the client and server. * **Rate Limiting:** Implement rate limiting to prevent abuse and denial-of-service attacks. * **Regular Security Audits:** Conduct regular security audits to identify and address vulnerabilities. **Technology-Specific Details:** HTMX's dynamic nature can introduce specific XSS vulnerabilities if you don't properly sanitize server-side content before rendering it as HTML. Always use templating engines that automatically escape HTML. Pay extra attention to "hx-get" and "hx-post" attributes to ensure they point to legitimate endpoints and don't allow users to inject arbitrary URLs. Mitigate potentially excessive server load from HTMX requests by limiting the number of concurrent requests a user can make (using rate limiting.) ### 2.4. Standard: Implement Error Handling **Do This:** Implement robust error handling to gracefully handle exceptions and prevent application crashes. **Don't Do This:** Allow unhandled exceptions to crash your application. **Why:** Error handling improves application resilience, provides a better user experience, and facilitates debugging. **Example:** Using try-except blocks in Python: """python try: # Code that may raise an exception result = int(input("Enter a number: ")) except ValueError: print("Invalid input. Please enter a number.") except Exception as e: print(f"An error occurred: {e}") """ **Technology-Specific Details:** Use HTMX's error handling features ("hx-on") to provide feedback to the users when requests fail. Display user-friendly error messages and avoid exposing internal server errors. """html <div hx-get="/api/data" hx-target="#data-container" hx-on::after-request="console.log(event.detail)"> Load Data </div> <script> document.addEventListener('htmx:afterRequest', function(event) { if (event.detail.successful === false) { alert('An error occurred while fetching data!'); } }); </script> """ ### 2.5. Standard: Implement Database Connection Pooling **Do This:** Use database connection pooling to efficiently manage database connections. **Don't Do This:** Create a new database connection for each request. **Why:** Connection pooling reduces the overhead of creating and closing database connections, improving performance and scalability. ### 2.6. Standard: Use Cache Strategically **Do This:** Implement caching at various levels (e.g., browser cache, server-side cache) to reduce database load and improve response times. Avoid over-caching dynamic content. **Don't Do This:** Avoid caching or cache everything indiscriminately. **Why:** Caching can significantly improve performance by reducing the need to repeatedly fetch data from the database or other slow resources. **Example:** Using server-side caching with Redis: """python import redis from flask import Flask, request app = Flask(__name__) redis_client = redis.Redis(host='localhost', port=6379, db=0) @app.route('/data') def get_data(): key = request.args.get('key') cached_data = redis_client.get(key) if cached_data: return cached_data.decode('utf-8') # Simulate fetching data from a slow source import time time.sleep(2) # Simulate a slow operation data = f"Data for key: {key}" redis_client.set(key, data) redis_client.expire(key, 60) # Expire after 60 seconds return data """ **Technology-Specific Details:** Properly use HTMX's "hx-swap" attribute. For example, use "hx-swap="outerHTML"" for completely replacing an element, rather than re-rendering the whole container. Additionally leverage caching middleware to avoid repeated database calls for HTMX requests. ### 2.7. Standard: Load Balancing **Do This:** Use a load balancer to distribute traffic across multiple application server instances. **Don't Do This:** Rely on a single server instance to handle all traffic. **Why:** Load balancing improves availability and scalability by distributing traffic and preventing overload on any single server. ## 3. Monitoring and Alerting ### 3.1. Standard: Implement Real-time Monitoring **Do This:** Set up real-time monitoring dashboards to track key metrics such as request latency, error rates, and resource utilization. **Don't Do This:** Rely solely on historical data or infrequent checks. **Why:** Real-time monitoring allows you to quickly identify and respond to issues as they arise, minimizing downtime and impact on users. **Example:** Using tools like Prometheus and Grafana ### 3.2. Standard: Configure Alerting **Do This:** Configure alerts to notify you when critical metrics exceed predefined thresholds. **Don't Do This:** Fail to set up proper alerting. **Why:** Alerting ensures that you are promptly notified of issues that require attention, allowing you to take corrective action before they escalate. **Example:** Setting up alerts for high error rates or slow response times. ### 3.3. Standard: Automate Rollbacks **Do This:** Implement automated rollback procedures to quickly revert to a previous version of your application in case of deployment failures. **Don't Do This:** Rely on manual rollback processes, which are slow and error-prone. **Why:** Automated rollbacks minimize downtime and ensure that you can quickly recover from deployment issues.
# Code Style and Conventions Standards for HTMX This document outlines the code style and conventions standards for HTMX development. Following these guidelines ensures consistency, readability, maintainability, and ultimately, higher-quality HTMX applications. This document is intended to guide developers and inform AI coding assistants. ## 1. General Formatting and Style Adhering to a consistent style is crucial for code maintainability. These standards apply to all HTML, CSS, and JavaScript code interacting with HTMX. ### 1.1 HTML Formatting * **Do This:** Use consistent indentation (2 spaces preferred). Attribute order should be logical (e.g., "id", "class", "hx-*", "other attributes"). * **Don't Do This:** Inconsistent indentation, random attribute order. **Why:** Consistency improves readability and reduces visual noise. A logical attribute order contributes to faster code scanning. **Example:** """html <!-- Good --> <div id="user-profile" class="card" hx-get="/users/123" hx-trigger="click" hx-target="#profile-details"> <p>Click to load user profile</p> </div> <!-- Bad --> <div hx-get="/users/123" id="user-profile" hx-target="#profile-details" class="card" hx-trigger="click"> <p>Click to load user profile</p> </div> """ ### 1.2 CSS Formatting * **Do This:** Use consistent indentation (2 spaces preferred). Organize CSS properties logically (e.g., box model, typography, visual appearance). Consider using a CSS preprocessor (Sass, Less) for maintainability. * **Don't Do This:** Inconsistent indentation, random property order, overly long CSS files without clear structure. **Why:** A structured CSS codebase is easier to navigate and modify. Preprocessors enable features like variables, nesting, and mixins, which improve maintainability. **Example:** """css /* Good */ #user-profile { width: 300px; margin-bottom: 10px; font-family: sans-serif; font-size: 16px; background-color: #f0f0f0; border: 1px solid #ccc; } /* Bad */ #user-profile { font-size: 16px; background-color: #f0f0f0; border: 1px solid #ccc; width: 300px; margin-bottom: 10px; font-family: sans-serif; } """ ### 1.3 JavaScript Formatting * **Do This:** Use consistent indentation (2 spaces preferred). Follow a style guide (e.g., Airbnb, Google). Use ESLint and Prettier for automated formatting and linting. * **Don't Do This:** Inconsistent indentation, lack of semicolons, global variable pollution, overly complex logic. **Why:** A standardized JavaScript style improves readability and reduces errors. Linters and formatters automate the process and enforce consistency across the team. **Example:** """javascript // Good function handleClick(event) { event.preventDefault(); const target = event.target; fetch('/api/users') .then(response => response.json()) .then(data => { console.log('Users:', data); // Update DOM with data (using HTMX may be preferable) }); } // Bad function handleClick(event) { event.preventDefault() const target = event.target fetch('/api/users').then(response => response.json()).then(data => { console.log('Users:', data) }) } """ ## 2. HTMX Attribute Conventions HTMX relies heavily on HTML attributes for its functionality. Clear and consistent attribute usage is paramount. ### 2.1 Consistent Prefixing * **Do This:** Always use the "hx-" prefix for all HTMX attributes. * **Don't Do This:** Using custom, non-prefixed attributes for HTMX functionality. **Why:** The "hx-" prefix clearly identifies HTMX-related attributes and prevents naming collisions with other libraries or custom attributes. **Example:** """html <!-- Good --> <button hx-post="/comments" hx-target="#comments-section" hx-swap="beforeend">Add Comment</button> <!-- Bad --> <button post-to="/comments" target="#comments-section" swap="beforeend">Add Comment</button> """ ### 2.2 Attribute Ordering * **Do This:** Place HTMX attributes after "id" and "class", and before other custom attributes. A suggested order is: "id", "class", "hx-get/post/put/delete", "hx-trigger", "hx-target", "hx-swap", "hx-other", "other data attributes". * **Don't Do This:** Scattering HTMX attributes randomly throughout the element. **Why:** Logical attribute ordering improves readability and helps quickly identify the core HTMX behavior of an element. **Example:** """html <!-- Good --> <div id="comment-form" class="form-card" hx-post="/comments" hx-target="#comments-section" hx-swap="beforeend"> <!-- Form contents --> </div> <!-- Bad --> <div hx-post="/comments" id="comment-form" hx-target="#comments-section" class="form-card" hx-swap="beforeend"> <!-- Form contents --> </div> """ ### 2.3 Avoiding Redundancy * **Do This:** Leverage HTMX's features to minimize redundant code. Use "hx-include" to include data from multiple form fields. Use "hx-vals" to pass fixed values. Utilize CSS classes for styling instead of inline styles that can hinder HTMX updates. * **Don't Do This:** Manually constructing data payloads in JavaScript when HTMX attributes can handle it, using inline styles that will be overwritten with new content when HTMX performs a swap. **Why:** Reducing redundancy simplifies the code and makes it easier to maintain. **Example:** """html <!-- Good --> <form hx-post="/submit" hx-target="#result" hx-include="[name='field1'], [name='field2']"> <input type="text" name="field1"> <input type="text" name="field2"> <button type="submit">Submit</button> </form> <!-- Bad (requires JavaScript to collect and send data) --> <form id="myForm"> <input type="text" name="field1"> <input type="text" name="field2"> <button type="submit" onclick="submitForm()">Submit</button> </form> <script> function submitForm() { const form = document.getElementById('myForm'); const formData = new FormData(form); fetch('/submit', { method: 'POST', body: formData }) .then(response => response.text()) .then(data => { document.getElementById('result').innerHTML = data; }); } </script> """ **Example:** "hx-vals" is a newer feature that allows passing fixed values to the server: """html <button hx-post="/api/endpoint" hx-vals='{"status": "pending"}' hx-target="#status-display">Mark as Pending</button> """ ### 2.4 Proper Use of "hx-swap" * **Do This:** Choose the "hx-swap" strategy that best suits the update being performed. Understand the differences between "innerHTML", "outerHTML", "beforeend", "afterbegin", etc. Consider using "morph:" swaps for smoother transitions. Use "hx-swap="none"" when only side effects are needed and no DOM update is required. * **Don't Do This:** Blindly using "innerHTML" for all updates, ignoring potential performance and security implications (e.g., XSS). **Why:** Selecting the appropriate "hx-swap" strategy optimizes performance and prevents unexpected behavior. "morph:" swaps, when appropriate, provide a better user experience. "hx-swap="none"" prevents unnecessary re-renders. **Example:** """html <!-- Good (appending to a list) --> <ul id="comment-list" hx-target="this" hx-swap="beforeend"> <li>Existing Comment</li> </ul> <button hx-post="/comments" hx-request='{"comment": "New Comment"}' hx-target="#comment-list" hx-swap="beforeend">Add Comment</button> <!-- Good (replacing content with a morph) --> <div id="content"> <p>Old Content</p> </div> <button hx-get="/new-content" hx-target="#content" hx-swap="morph:outerHTML">Load New Content</button> <!-- Bad (potentially inefficient and risky) --> <div id="content"> <p>Old Content</p> </div> <button hx-get="/new-content" hx-target="#content" hx-swap="innerHTML">Load New Content</button> """ ### 2.5 Use of "hx-confirm" * **Do This:** Use "hx-confirm" for potentially destructive actions like deleting data, especially those triggered with short click events, to offer the user a confirmation dialog. * **Don't Do This:** Omitting confirmation dialogs for important destructive operatiions. **Why:** Prevent accidental execution of important destructive client-side requests. **Example:** """html <!-- Good --> <button hx-delete="/account" hx-confirm="Are you sure you want to delete your account?">Delete Account</button> <!-- Bad --> <button hx-delete="/account">Delete Account</button> """ ## 3. Naming Conventions Consistent naming makes code easier to understand and maintain. ### 3.1 Element IDs * **Do This:** Use descriptive and meaningful IDs. Use camelCase or kebab-case for IDs. Choose ONE and stick to it. * **Don't Do This:** Generic IDs like "button1", "div2". **Why:** Descriptive IDs make it easier to understand the purpose of an element and its role in the HTMX application. **Example:** """html <!-- Good --> <div id="userProfileSection">...</div> <div id="user-profile-section">...</div> <!-- Bad --> <div id="section1">...</div> """ ### 3.2 CSS Classes * **Do This:** Use a consistent naming convention (e.g., BEM, SUIT CSS, or a similar methodology) to create modular and reusable CSS classes. * **Don't Do This:** Long, unorganized CSS class names. **Why:** A well-defined CSS naming convention promotes maintainability and prevents naming collisions. **Example (BEM):** """html <!-- Good --> <div class="user-profile"> <h2 class="user-profile__name">...</h2> <p class="user-profile__bio">...</p> </div> <!-- Bad --> <div class="userProfile"> <h2 class="name">...</h2> <p class="bioText">...</p> </div> """ ### 3.3 HTMX Trigger Names * **Do This:** Use descriptive trigger names, especially for custom events. Prefix custom event names to avoid conflicts. * **Don't Do This:** Generic or ambiguous trigger names. **Why:** Clear trigger names enhance code understandability and prevent unexpected behavior. **Example:** """html <!-- Good --> <button hx-get="/data" hx-trigger="myCustomEvent">Load Data</button> <script> // Later in javascript: const button = document.querySelector('button'); button.dispatchEvent(new Event('myCustomEvent')); </script> <!-- Bad --> <button hx-get="/data" hx-trigger="event">Load Data</button> <script> // Later in javascript: const button = document.querySelector('button'); button.dispatchEvent(new Event('event')); </script> """ ## 4. Error Handling Robust error handling is crucial for a reliable HTMX application. ### 4.1 Client-Side Error Handling * **Do This:** Use "hx-on-*" attributes (introduced in newer HTMX versions) to handle events, including errors. Display user-friendly error messages in the UI, taking advantage of "hx-ext="response-targets"". * **Don't Do This:** Ignoring potential errors, displaying raw error messages to users. **Why:** Proper error handling ensures a graceful user experience and helps diagnose issues. **Example (Using "hx-on" and "response-targets" extension):** """html <div id="result" hx-ext="response-targets"> <button hx-get="/api/data" hx-target="#result" hx-on--htmx-after-request="handleRequest"></button> </div> <script> function handleRequest(event) { if (event.detail.successful) { console.log("Request was successful"); } else { console.error("Request failed:", event.detail.xhr.status, event.detail.xhr.responseText); // Display error message in the UI, e.g., by replacing the button with an error message. event.target.outerHTML = "<p class='error'>Error loading data.</p>"; } } </script> <!-- Example demonstrating usage of response-targets extension --> <div hx-get="/login" hx-target="#login-form" hx-ext="response-targets"> <div id="login-form"> <input type="text" name="username"> <input type="password" name="password"> <button type="submit">login</button> </div> <template hx-response-target="login-form"> <div> Logged in as <span id="username"></span> </div> </template> <template hx-response-target="error"> <div class="error"> Invalid username or password </div> </template> </div> """ ### 4.2 Server-Side Error Handling * **Do This:** Return appropriate HTTP status codes (e.g., 400, 404, 500) to indicate errors. Include informative error messages in the response body (e.g., in JSON format). * **Don't Do This:** Returning 200 OK for all requests, even when errors occur; sending vague or unhelpful error messages. **Why:** HTTP status codes allow HTMX to correctly identify and handle errors. Informative error messages help developers debug issues. **Example (Server-side - Python/Flask):** """python from flask import Flask, jsonify, request app = Flask(__name__) @app.route('/api/data', methods=['GET']) def get_data(): try: # Simulate an error raise ValueError("Simulated error") #return jsonify({'data': 'Some data'}) except ValueError as e: return jsonify({'error': str(e)}), 500 if __name__ == '__main__': app.run(debug=True) """ ## 5. Performance Optimization Optimizing performance is crucial for a responsive HTMX application. ### 5.1 Minimizing DOM Updates * **Do This:** Target only the necessary parts of the DOM with "hx-target". Use the most efficient "hx-swap" strategy. Avoid unnecessary re-renders. Leverage "hx-select" to extract the relevant content from responses. * **Don't Do This:** Targeting large sections of the DOM unnecessarily, using "innerHTML" for updates when a more specific swap strategy would suffice. **Why:** Minimizing DOM updates reduces browser overhead and improves responsiveness. **Example:** """html <!-- Good (targeting a specific element) --> <div id="container"> <span id="data-display">Initial Data</span> <button hx-get="/api/data" hx-target="#data-display" hx-swap="innerHTML">Load Data</button> </div> <!-- Bad (targeting the whole container) --> <div id="container"> <span id="data-display">Initial Data</span> <button hx-get="/api/data" hx-target="#container" hx-swap="innerHTML">Load Data</button> </div> """ ### 5.2 Caching * **Do This:** Implement server-side caching to reduce database load. Use browser caching (e.g., "Cache-Control" headers) for static assets. * **Don't Do This:** Fetching the same data repeatedly without caching. **Why:** Caching reduces server load and improves response times. ### 5.3 Network Optimization * **Do This:** Minimize the size of HTTP responses (e.g., by compressing content). Use a CDN for static assets. Optimize images. Consider using HTTP/2 or HTTP/3. * **Don't Do This:** Sending large, uncompressed responses over slow network connections. **Why:** Reducing network latency improves the perceived performance of the application. ### 5.4 Utilizing "hx-boost" Wisely * **Do This:** Use "hx-boost" on "<a>" and "<form>" tags to automatically convert them into HTMX requests. Be mindful of its impact on SEO (ensure server-side rendering or a fallback mechanism for search engines). * **Don't Do This:** Applying "hx-boost" indiscriminately to all links and forms without considering the potential consequences. **Why:** "hx-boost" reduces the amount of code needed and simplifies the update of content. **Example:** """html <!-- Good --> <a href="/users" hx-boost="true" hx-target="#content">Users</a> <form action="/search" hx-boost="true" hx-target="#results"> <input type="text" name="query"> <button type="submit">Search</button> </form> """ ## 6. Security Considerations Security is paramount. HTMX, like any web technology, requires careful attention to security best practices. ### 6.1 Preventing XSS * **Do This:** Sanitize user input on the server-side before rendering it in HTML. Use templating engines with automatic escaping. Be cautious when using "innerHTML" or "outerHTML" with untrusted data. "morph:" swaps are generally safer in this regard. * **Don't Do This:** Directly injecting user input into HTML without sanitization. **Why:** Preventing XSS vulnerabilities protects users from malicious scripts injected into the application. ### 6.2 CSRF Protection * **Do This:** Implement CSRF protection on all state-changing endpoints (POST, PUT, DELETE). Use a CSRF token in forms and AJAX requests. HTMX automatically handles CSRF tokens when posting forms. * **Don't Do This:** Disabling CSRF protection without a valid reason. **Why:** CSRF protection prevents attackers from forging requests on behalf of authenticated users. ### 6.3 Input Validation * **Do This:** Validate all user input on both the client-side and the server-side. Enforce data type, length, and format constraints. * **Don't Do This:** Trusting user input without validation. **Why:** Input validation prevents data corruption and security vulnerabilities. ### 6.4 HTTPS * **Do This:** Always use HTTPS to encrypt communication between the client and the server. Redirect HTTP requests to HTTPS. * **Don't Do This:** Serving sensitive content over HTTP. **Why:** HTTPS protects data in transit from eavesdropping and tampering. ## 7. Testing * **Do This:** Write unit tests, integration tests, and end-to-end tests to ensure the HTMX application functions correctly. Use a testing framework (e.g., Jest, Mocha, Cypress). * **Don't Do This:** Skipping testing or relying solely on manual testing. **Why:** Testing helps prevent bugs and ensures that the application meets its requirements. While HTMX itself might require less JavaScript, server-side code handling HTMX requests still needs comprehensive testing. Testing the integration between HTMX and the server is particularly important. For example, rendering using Jinja server-side (Python): """python from flask import Flask, render_template_string app = Flask(__name__) @app.route('/') def index(): return render_template_string(''' <div id="content"> Hello, HTMX! <button hx-get="/new_content" hx-target="#content">Load New Content</button> </div> ''') @app.route('/new_content') def new_content(): return "<h1>New Content Loaded!</h1>" if __name__ == '__main__': app.run(debug=True) """ ## 8. Modern HTMX Patterns and Techniques * **Progressive Enhancement:** Build core functionality with standard HTML first, and then add HTMX to progressively enhance the user experience. * **Server-Sent Events (SSE):** Use SSE with HTMX to create near-real-time updates in the UI. The "event" attribute can be used to listen to SSE events """html <div id="realtime-data" hx-get="/stream" hx-trigger="sse:update" hx-swap="innerHTML"> Waiting for updates... </div> """ * **WebSockets:** Integrate HTMX with WebSockets for full-duplex communication. Trigger changes based on messages received. """html <div id="websocket-data" hx-ext="ws" ws-connect="/ws" hx-on--ws-message="updateData"> Waiting for WebSocket data... </div> <script> function updateData(evt) { document.getElementById('websocket-data').innerHTML = evt.detail.data; } </script> """ * **Custom Extensions:** Create custom HTMX extensions to encapsulate reusable logic and functionality. This is often a better approach than very long "hx-on" handlers. """javascript htmx.defineExtension('my-extension', { onEvent: function(name, evt) { if (name === 'htmx:beforeRequest') { console.log("About to make a request!"); } } }); """ * **Use of "morph:" swaps:** Modern browsers implement optimized DOM diffing algorithms. Consider using "morph:" to reduce code and improve UX. """html <div id="parent-div"> <div>Change Me</div> </div> <button hx-get="/new-content" hx-target="#parent-div" hx-swap="morph:outerHTML"> Load New Content </button> """ The response from "/new-content" should contain new HTML for parent-div. * **Careful use of hx-boost:** While hx-boost can be very beneficial for initial development but remember that it effectively converts all links and forms to AJAX requests, which can cause issues with SEO and also history management. Use with caution! By adhering to these code style and conventions standards, development teams can create cleaner, more maintainable, and more secure HTMX applications.