Sam, I agree that Turbo Stream responses _can be_ (and indeed _should be_) HTML. I've updated the sample to use the exact same template for both HTML (`text/html`) and Turbo Stream (`text/vnd.turbo-stream.html`) response entity - only the `Content-Type` header value differs.

For me, as turbo.js knows it's making a request that may return a Turbo Stream (based on the context of how the request is made, e.g. `connectStreamSource()`) and could inspect a `text/html` response for any `<turbo-stream>` custom element and, if found, do its magic.

In this case, it means that a Turbo Stream response _is_ HTML, and it's only a Turbo Stream response because it happens to contain a `<turbo-stream>` custom element.

My thought (and conversation with DHH about Media Type on GitHub) is that while the use of a separate Media Type for requests is well-founded due to content negotiation, there is a good possibility to not need a separate Media Type for responses, and remove a lot of hoo-hah from the view template parsing process (at least on non-Rails servers).

Also, taking a look at my sample, with a well-crafted HTML template and with turbo.js parsing for `<turbo-stream>` in an HTML response it means there is actually no need for content negotiation (and no need for the custom Media Type in request `Accept` headers) - because the same action and same response can be used (making the "progressive enhancement" story even stronger.

CTO’s CTO. Angel. VP Technology @SecCodeWarrior Ex @Canva @Atlassian @ThoughtWorks

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store