<?php
echo "Hello ";
ob_flush();
flush();
sleep(5);
echo "World!";
Disclaimer: this summary is my understanding of how the team discovered this and thus if there are any inaccuracies, they are mine.
hx-multipart is an htmx extension that blends html streaming with htmx goodness.
It was observed about 10 years ago that html could be streamed to the browser to create a more dynamic feel to webpages.
Note:
php or another server side language can do html streaming, if buffering is turned off.
if there is a webserver involved, buffering may also need to be turned off.
the document will be appended to.
for example, output.php, results in 'Hello World!':
<?php
echo "Hello ";
ob_flush();
flush();
sleep(5);
echo "World!";
It is a content-type that allows streaming of various content.
supposedly created in 1992 to allow mixed content for email.
Christian Tanul from the htmx team discovered that it works over http as well.
ping-1.php doesn’t work. Compare with ping.php which works.
<?php /* *Purpose:* to test streaming html. *Author:* Marlon A. Griffith *Created:* Wed. 2026-09-09 *Modified:* */ header( 'HTTP/1.1 200 OK' ); header( 'Content-Type: multipart/mixed; boundary=...' ); echo <<<BODY --... Content-Type: text/html P --... Content-Type: text/html Po --... Content-Type: text/html Pon --... Content-Type: text/html Pong --...-- BODY;
Christian, Michael West and Carson Gross developed the htmx extension - hx-multipart, which provides the javascript shiv to read the stream and insert into the dom depending on the content type and target.
Motivation:
Why should only <a> & <form> be able to make HTTP requests?
Why should only click & submit events trigger them?
Why should only GET & POST methods be available?
Why should you only be able to replace the entire screen?
By removing these constraints, htmx completes HTML as a hypertext.
The last principle emphasizes locality of behaviour. To me this means grouping simple behaviour and styling together to create light html components directly in your html page. From https://htmx.org an example:
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.10/dist/htmx.min.js"
integrity="sha384-H5SrcfygHmAuTDZphMHqBJLc3FhssKjG7w/CeCpFReSfwBWDTKpkzPP8c+cLsK+V"
crossorigin="anonymous"></script>
<!-- Active Search -->
<input type="search" name="search"
hx-post="/search"
hx-trigger="input changed delay:200ms, keyup[key=='Enter'], load"
hx-target="#results"
hx-indicator=".htmx-indicator">
<tbody id="results"></tbody>
hx-multipart becomes a streaming process which allows an usable page, while images loaded, i.e. it is hydration using basic http. See the two sample files below:
htmx-multipart.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>HTMX Multipart/mixed Streaming Test</title>
<!-- Include µCSS from CDN -->
<link rel="stylesheet" href="https://unpkg.com/@digicreon/mucss/dist/mu.fuchsia.css">
<!-- from filesystem
<script src="htmx.min.js"></script>
<script src="hx-multipart.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/htmx.org@4.0.0/dist/htmx.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/bigskysoftware/htmx@four/src/ext/hx-multipart.min.js"></script>
</head>
<body>
<main>
<p>Converted from four.htmx.org for php using the hx-multipart extension.</p>
<button hx-get="ping.php">
Ping
</button>
<p id="para1">Paragraph 1</p>
<p id="para2">Paragraph 2</p>
<p id="para3">Paragraph 3</p>
<p id="para4">Paragraph 4</p>
<p id="notes">no Notifications here... move on.</p>
<p>Browser only call.</p>
<p>This is sent but is not updated by hx-multipart</p>
<button hx-get="ping-1.php">
Ping browser
</button>
</main>
</body>
</html>
ping.php
<?php
// from ai summary when I was researching Tues. 2026-09-15 night
// Works!
header('Content-Type: multipart/mixed; boundary="..."');
$boundary = "...";
$response = "--$boundary\r\n";
$response .= "Content-Type: text/html\r\n";
$response .= "HX-Target: #para1\r\n\r\n";
$response .= "P\r\n";
$response .= "--$boundary\r\n";
$response .= "Content-Type: text/html\r\n";
$response .= "HX-Target: #para2\r\n\r\n";
$response .= "o\r\n";
$response .= "--$boundary\r\n";
$response .= "Content-Type: text/html\r\n";
$response .= "HX-Target: #para3\r\n\r\n";
$response .= "n\r\n";
$response .= "--$boundary\r\n";
$response .= "Content-Type: text/html\r\n";
$response .= "HX-Target: #para4\r\n\r\n";
$response .= "g\r\n";
$response .= "--$boundary\r\n";
$response .= "Content-Type: text/html\r\n";
$response .= "HX-Target: #notes\r\n\r\n";
$response .= "Notification: all done.\r\n";
$response .= "--$boundary--"; // End the multipart response
echo $response;
Christian used it to build the prototype game hyperspace. It is sort of a 3D tetris built with hx-multipart, hx-live and a posgresql database.
sse can only send text, i.e. html, text or json.
consider a webpage like Pinterest or any other photogallery.
it can take a long time to load the page depending on how many images there are.
streaming allows partial functionality while the page loads.
hx-multipart has synchronous and asynchronous loading options.
the html and php code is very simple
see htmx-multipart.html and ping.php, above, as a hello world example.
Caveat:
this is one way streaming - from the server to the browser.
the line endings must be '\r\n'
This is another tool in htmx’s belt for updating the dom, along with:
| htmx Feature | Communication Model | Direction | Updates | Content Types |
|---|---|---|---|---|
hx-target and hx-select |
Single Request/Response |
Server → Browser |
Single id based |
text, html, svg and json |
out of band (oob) swaps |
Single Request/Response |
Server → Browser |
Multiple simple id based |
text, html, svg and json |
hx-multipart |
Single Request/Response |
Server → Browser |
Multiple complex |
text, html, svg, json, image, audio, video, etc. |
the |
Single Request/Response |
Continuous Server → Browser |
Multiple complex |
text, html, svg and json |
Server Sent Events |
Continuous Events |
One way Server → Browser |
Multiple complex |
text, html, svg and json |
Web Sockets |
Continuous Channel |
Bidirectional Server → Browser |
Multiple complex |
text, html, svg and json? |