hotwired / turbo

The speed of a single-page web application without having to write any JavaScript
https://turbo.hotwired.dev
MIT License
6.54k stars 415 forks source link

The documentation does not mention that Stream Action tags can be rendered inside any HTML #1258

Open radanskoric opened 1 month ago

radanskoric commented 1 month ago

The way Turbo is currently implemented, stream tags will be processed and executed when they are rendered anywhere in HTML.

Here is a minimal example with a static HTML page:

<html>
  <head>
    <script src="https://unpkg.com/@hotwired/turbo"></script>
  </head>
  <body>
    <turbo-stream action="append" target="list">
      <template>
        <li>list element</li>
      </template>
    </turbo-stream>

    This list has an element added via the stream action:
    <ul id="list">
    </ul>
  </body>
</html>

This will work anywhere where stream tags are rendered into the page DOM:

Not all of those are smart ways to use it but I was surprised that the documentation makes no mention of the feature. At least I couldn't find any mention anywhere in the documentation or old release notes.

I am guessing that the reason is that this is a side-effect of how StreamElements are implemented: They are defined as customElements with the stream tag execution being triggered by the connectedCallback implementation of the StreamElement class.

Perhaps it's just me and most other people find this clear without being mentioned but I think it would still be worth adding a few sentences and a documentation and a test to cover it. This can be a very useful feature in some cases.

I'd be very happy to mention this in the documentation but wanted to first check if there is something I am missing?

Can someone confirm that this is an intentional Turbo feature that should be mentioned explicitly in the documentation? If not, can we make it an official feature. Considering how it's implemented, one would have to do add explicit hacks just to stop it from working.

seanpdoyle commented 1 month ago

Can someone confirm that this is an intentional Turbo feature that should be mentioned explicitly in the documentation?

I've personally relied on the behavior that you've described. For example, you can nest a <turbo-stream> element inside a <template> element, then append that content to the page after a <button> click (try it out on JSFiddle):

<script>
  addEventListener("click", ({ target }) => {
    const button = target.closest("button")
    const template = button.querySelector("template")
    document.body.append(template.content.cloneNode(true))
  })
</script>

<button type="button" id="call-to-action">
  <span>Click me to insert the template's contents after this button!</span>

  <template>
    <turbo-stream action="after" target="call-to-action">
      <template><p>You clicked the button!</p></template>
    </turbo-stream>
  </template>
</button>
radanskoric commented 1 month ago

I've personally relied on the behavior that you've described. For example, you can nest a <turbo-stream> element inside a <template> element, then append that content to the page after a <button> click (try it out on JSFiddle):

Glad to hear that. :) I've used, in production, stream tags inside frame response (for extra side-effects) and inside the initial page load HTML (for interacting with some legacy JS).

seanpdoyle commented 1 month ago

Can someone confirm that this is an intentional Turbo feature that should be mentioned explicitly in the documentation? If not, can we make it an official feature.

I think outlining these possibilities at a high level in the Streams Handbook section and in greater detail in Streams Reference section would be a big improvement!

radanskoric commented 1 month ago

Can someone confirm that this is an intentional Turbo feature that should be mentioned explicitly in the documentation? If not, can we make it an official feature.

I think outlining these possibilities at a high level in the Streams Handbook section and in greater detail in Streams Reference section would be a big improvement!

Great, I'll prepare something soon. 👍

radanskoric commented 1 month ago

@seanpdoyle I've opened two PRs to address this.

One to extend the documentation: https://github.com/hotwired/turbo-site/pull/192

And one to add a test ensuring no regressions of this functionality: https://github.com/hotwired/turbo/pull/1263

Happy to iterate on both based on feedback. :)