If you’re a developer looking for a way to build dynamic web applications without diving into JavaScript frameworks, HTMX is a lifesaver. Pairing it with PHP, using HTMX with PHP the OG of backend scripting gives you a lightweight, powerful toolset for creating interactive apps with minimal code.
In this tutorial, we’ll explore HTMX with PHP, concepts with practical examples. From sending AJAX requests to leveraging advanced features like polling, lazy loading, event handling, and out-of-band swaps, you’ll learn how to make your PHP backend shine while keeping the frontend simple and elegant.
In this article/blog we will be going through these things!
- What is HTMX?
- Why Pair HTMX with PHP?
- HTMX in Action: A Comprehensive Example
- Example Use Cases
- Wrapping Up
What is HTMX?
HTMX is a JavaScript library that lets you:
- Perform AJAX requests (
GET
,POST
,PUT
,DELETE
) directly in HTML. - Dynamically update specific parts of the page using HTML fragments returned by the server.
- Reduce reliance on heavy frontend frameworks (e.g., React, Vue).
- Add interactivity to your app without sacrificing simplicity.
By embedding HTMX attributes (hx-{get, post etc})
into your HTML, you can create dynamic components that communicate seamlessly with your server.
Why Pair HTMX with PHP?
PHP is a versatile, widely used scripting language for the web. When paired with HTMX, PHP becomes the perfect partner for:
- Lightweight apps: Create small, dynamic apps without introducing complex dependencies.
- Rapid development: Focus on building features instead of configuring frameworks.
- HTML-first approach: HTMX’s philosophy aligns with PHP’s server-side rendering capabilities.
HTMX in Action: A Comprehensive Example
Let’s dive into specific use cases to see the usage of HTMX with PHP.
1. Dynamic Content Updates: hx-get
Imagine you want to display a list of products that updates dynamically. Instead of loading the page, HTMX can fetch the content with a simple GET
request.
Frontend (HTML):
<div id="product-list" hx-get="products.php" hx-trigger="load" hx-swap="outerHTML">
<!-- Placeholder while data loads -->
<p>Loading products...</p>
</div>
Backend (PHP: products.php
):
<?php
$products = [
['name' => 'Laptop', 'price' => '$1000'],
['name' => 'Smartphone', 'price' => '$700'],
['name' => 'Tablet', 'price' => '$500'],
];
echo '<ul>';
foreach ($products as $product) {
echo "<li>{$product['name']} - {$product['price']}</li>";
}
echo '</ul>';
Explanation:
hx-get
: Fetches theproducts.php
endpoint.hx-trigger="load"
: Automatically triggers the request when the page loads.hx-swap="outerHTML"
: Replaces the#product-list
container with the server’s response.
2. Submitting Forms Without Reload: hx-post
Form submissions often require page reloads. With HTMX, you can submit a form and update part of the page without refreshing.
Frontend (HTML):
<form hx-post="submit.php" hx-target="#response" hx-swap="innerHTML">
<label for="name">Name:</label>
<input type="text" name="name" id="name" required>
<button type="submit">Submit</button>
</form>
<div id="response"></div>
Backend (PHP: submit.php
):
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = htmlspecialchars($_POST['name']);
echo "<p>Thank you, $name! Your submission was received.</p>";
}
Explanation:
hx-post
: Sends aPOST
request tosubmit.php
.hx-target
: Specifies where to place the response (#response
).hx-swap
: Defines how to insert the response (innerHTML
replaces the contents).
3. Polling for Real-Time Updates: hx-trigger="every"
For scenarios like live data updates (e.g., notifications, stock prices), HTMX can poll the server at regular intervals.
Frontend (HTML):
<div id="notification-count" hx-get="notifications.php" hx-trigger="every 10s" hx-swap="innerHTML">
Checking for notifications...
</div>
Backend (PHP: notifications.php
):
<?php
// Simulate fetching notification count
echo rand(0, 10); // Random notification count for demo purposes
Explanation:
hx-trigger="every 10s"
: Sends aGET
request every 10 seconds.hx-swap
: Updates the content dynamically.
4. Lazy Loading Content: hx-trigger="revealed"
HTMX supports lazy loading, which fetches content only when it becomes visible in the viewport.
Frontend (HTML):
<div hx-get="large-content.php" hx-trigger="revealed" hx-swap="outerHTML">
<p>Loading content...</p>
</div>
Backend (PHP: large-content.php
):
<?php
echo '<p>This is the large content that was loaded lazily.</p>';
Explanation:
hx-trigger="revealed"
: Fetches content when the element enters the viewport.- Useful for optimizing performance by delaying non-critical requests.
5. Inline Editing: hx-put
HTMX makes inline editing seamless by enabling direct updates to data.
Frontend (HTML):
<div>
<p id="username" hx-get="edit.php" hx-trigger="click" hx-swap="outerHTML">
Click to edit: HishuAniGami </p>
</div>
Backend (PHP: edit.php
):
<?php
echo '<form hx-put="update.php" hx-target="#username" hx-swap="outerHTML">
<input type="text" name="username" value="HishuAniGami
" required>
<button type="submit">Save</button>
</form>';
Explanation:
- Clicking the
#username
element swaps it with an inline form. - The form submission sends a
PUT
request to update data.
6. Event Handling: hx-on
HTMX allows you to listen for events like after swaps or request completions.
Frontend (HTML):
<div id="data-container" hx-get="data.php" hx-on="htmx:afterSwap">
<!-- Content loaded here -->
</div>
<script>
document.querySelector('#data-container').addEventListener('htmx:afterSwap', () => {
alert('Content updated!');
});
</script>
Explanation:
hx-on="htmx:afterSwap"
: Triggers custom JavaScript after the swap.
7. Error Handling with HTMX
Handling errors gracefully is critical. HTMX provides attributes like hx-on
for error-specific events.
Frontend (HTML):
<div id="error-demo">
<form hx-post="submit-error.php" hx-on="htmx:responseError">
<input type="text" name="data" required>
<button type="submit">Submit</button>
</form>
</div>
<script>
document.querySelector('#error-demo').addEventListener('htmx:responseError', () => {
alert('An error occurred while processing your request.');
});
</script>
Backend (PHP: submit-error.php
):
http_response_code(500);
echo "Something went wrong.";
Explanation:
htmx:responseError
triggers when the server returns a non-2xx status code.
If you want to learn more about PHP then PHP CRUD API Generator: Generate Your Own Dynamic API , Create a Dynamic PHP Routing System from Scratch . If you are into text to speech or speech to text then you can check out Building a Real Time Offline Speech to Text Program and Discord TTS Bot: Create Your Own TTS Bot for Discord
Example Use Cases
Given below are some use cases that you can add into your app using HTMX with PHP.
1. Tab Switching Without Reloads
Switch between tabs dynamically by loading content via hx-get
.
Frontend (HTML):
<div>
<button hx-get="tab1.php" hx-target="#tab-content" hx-swap="innerHTML">Tab 1</button>
<button hx-get="tab2.php" hx-target="#tab-content" hx-swap="innerHTML">Tab 2</button>
<button hx-get="tab3.php" hx-target="#tab-content" hx-swap="innerHTML">Tab 3</button>
</div>
<div id="tab-content">
<p>Select a tab to view content.</p>
</div>
Backend (PHP: tab1.php
, tab2.php
, tab3.php
):
// Example for tab1.php
echo '<h3>Welcome to Tab 1</h3><p>This is content for Tab 1.</p>';
Use Case: Improve user experience by eliminating full-page reloads when switching tabs.
2. Pagination
Dynamically load paginated data without refreshing the page.
Frontend (HTML):
<div id="pagination">
<div hx-get="page.php?page=1" hx-target="#page-content" hx-swap="innerHTML">Page 1</div>
<div hx-get="page.php?page=2" hx-target="#page-content" hx-swap="innerHTML">Page 2</div>
<div hx-get="page.php?page=3" hx-target="#page-content" hx-swap="innerHTML">Page 3</div>
</div>
<div id="page-content">
<p>Click a page to load its content.</p>
</div>
Backend (PHP: page.php
):
$page = $_GET['page'];
echo "<h3>Content for Page $page</h3><p>This is data for page $page.</p>";
Use Case: Load paginated content for blogs, product listings, or search results.
3. Search Suggestions
Create a live search bar that fetches suggestions as users type.
Frontend (HTML):
<input type="text" hx-get="search.php" hx-trigger="keyup changed delay:300ms" hx-target="#suggestions" hx-swap="innerHTML" placeholder="Search...">
<div id="suggestions"></div>
Backend (PHP: search.php
):
$query = $_GET['q'] ?? '';
$suggestions = ['apple', 'banana', 'cherry', 'date', 'elderberry' , 'istomatoafruit? '];
$results = array_filter($suggestions, fn($item) => stripos($item, $query) !== false);
echo '<ul>';
foreach ($results as $result) {
echo "<li>$result</li>";
}
echo '</ul>';
Use Case: Improve search usability with live suggestions.
4. File Uploads
Upload a file and display its details dynamically.
Frontend (HTML):
<form hx-post="upload.php" hx-target="#upload-result" hx-swap="innerHTML" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">Upload</button>
</form>
<div id="upload-result"></div>
Backend (PHP: upload.php
):
if ($_FILES['file']) {
$fileName = $_FILES['file']['name'];
move_uploaded_file($_FILES['file']['tmp_name'], "uploads/$fileName");
echo "<p>File '$fileName' uploaded successfully!</p>";
} else {
echo "<p>Error uploading file.</p>";
}
Use Case: Handle image or document uploads without reloading the page.
5. Dependent Dropdowns
Update a secondary dropdown based on the selection of the first dropdown.
Frontend (HTML):
<select hx-get="countries.php" hx-target="#states" hx-swap="innerHTML">
<option value="us">United States</option>
<option value="ca">Canada</option>
<option value="mars">Mars</option>
</select>
<select id="states">
<option>Select a country first</option>
</select>
Backend (PHP: countries.php
):
$country = $_GET['country'];
$states = [
'us' => ['California', 'New York', 'Texas'],
'ca' => ['Ontario', 'Quebec', 'British Columbia']
'mars' => ['Bro why are you even clicking on this']
];
echo '<option>Select a state</option>';
foreach ($states[$country] ?? [] as $state) {
echo "<option>$state</option>";
}
Use Case: Create cascading dropdowns for forms (e.g., country → state).
6. Real-Time Chat
Fetch new chat messages every few seconds.
Frontend (HTML):
<div id="chat-box" hx-get="chat.php" hx-trigger="every 5s" hx-swap="innerHTML">
<p>Loading chat...</p>
</div>
Backend (PHP: chat.php
):
$messages = [
'lil bro: Sup!',
'big bro: Sup lil man!',
'lil bro: W Frfr on god',
];
echo '<ul>';
foreach ($messages as $message) {
echo "<li>$message</li>";
}
echo '</ul>';
Use Case: Keep chat boxes updated in real-time without reloading.
7. Progress Bar
Update a progress bar dynamically based on server-side processing.
Frontend (HTML):
<div id="progress-bar" style="width: 0%; background: green; height: 20px;" hx-get="progress.php" hx-trigger="every 1s" hx-swap="style.outerHTML"></div>
Backend (PHP: progress.php
):
$progress = rand(0, 100); // Simulate progress percentage
echo "width: $progress%; background: green; height: 20px;";
Use Case: Visualize progress for long-running tasks.
8. Tooltip Content
Dynamically load content into a tooltip.
Frontend (HTML):
<button hx-get="tooltip.php" hx-trigger="hover" hx-target="#tooltip" hx-swap="innerHTML">
Hover me
</button>
<div id="tooltip" style="position: absolute; background: lightgray; padding: 5px; display: none;"></div>
Backend (PHP: tooltip.php
):
echo "<p>This is dynamic tooltip content.</p>";
Use Case: Provide additional information dynamically in tooltips.
Wrapping Up
HTMX simplifies web development by letting you build interactive, dynamic apps with minimal JavaScript. When paired up HTMX with PHP, you can create robust server-side applications without heavy dependencies. By mastering HTMX with PHP features like hx-get
, hx-post
, lazy loading, polling, event handling, and out-of-band swaps, you’ll elevate your web development game to the next level. Who needs a front-end developer when you can both front and back with this simple stack.
What’s next? Experiment with combining these techniques in real-world projects or dive deeper into HTMX’s advanced capabilities. Happy coding! 🎉