Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

<teleport> element #9614

Open
CyberAP opened this issue Aug 18, 2023 · 7 comments
Open

<teleport> element #9614

CyberAP opened this issue Aug 18, 2023 · 7 comments
Labels
addition/proposal New features or enhancements needs concrete proposal Moving the issue forward requires someone to figure out a detailed plan

Comments

@CyberAP
Copy link

CyberAP commented Aug 18, 2023

It would be nice for HTML to provide a native <teleport> element that would render its contents at the target destination instead of in-place. This mostly applies to when the document is still streaming.

Motivation

Right now there's no mechanism to redirect the underlying document stream to another part of the document. This means you can only write to the end of the document. This is quite limiting because sometimes a part of the document can be computationally expensive to render on the server or could take long to serve to the client. In order to solve that we can show a temproary placeholder in place and replace it later as soon as we get the HTML. There are solutions that can solve this problem already but they have their limitations:

  1. Buffer the response (i.e. wait for element to fully be streamed from the server) and use JavaScript to manually replace placeholder with the streamed contents. The main problem here is that the response always has to be buffered, that means the client will not see any of the contents unless everything is fully fetched. This is a severe limitation because it leaves us without progressive rendering that HTML can offer and the user experience is limited by their internet connection (the slower your network the later you'll see any content).
  2. Attach a new document stream. This solves the problem more effectively at the cost of running another HTTP request to the server. This is also limiting because it might take longer to get a new response from server than stream it right away with the first document stream. This solution involves JavaScript as well. Another downside here is that we can't execute JavaScript with that solution (<script> rendered within a new document stream does not execute).

With a <teleport> element we shouldn't have any of the downsides listed above and it would also siginficantly simplify current solutions to the problem that involve complex code on either a client or a server. The introduction of this element should also open up a new class of streaming-first solutions to web apps.

@keithamus
Copy link
Contributor

Sounds a bit like slots:

<body>
  <tele-port>
    <template shadowrootmode="open">
      <slot name="replace"></slot>
      <slot></slot>
    </template>
    <div class="body">
      <h1>The rest of my web page goes here</h1>
    </div>

    <!-- a bunch of async ops -->

    <div slot="replace">new content gets streamed out-of-order!</div>

  </tele-port>
</body>

@annevk
Copy link
Member

annevk commented Aug 18, 2023

Hey @CyberAP, I'd recommend focusing on 1 and 2 of https://whatwg.org/faq#adding-new-features for now and to try and flush those out. A new element needs quite a bit of justification and ideally there's ample precedent for it in userland.

@CyberAP
Copy link
Author

CyberAP commented Aug 26, 2023

Thank you @annevk! This makes sense, sorry for not paying attention to the FAQ first, I've tried to address your concern.

@CyberAP
Copy link
Author

CyberAP commented Aug 26, 2023

@keithamus good point! The problem with this solution is that you basically have to wrap your whole app within a Web Component and you also have to know where to place the slots in advance, which is not possible in some cases. I did not manage to test whether declarative shadow root contents get replaced without buffering though.

Edit: it works! Though the limitations mentioned above still apply.

@0xdevwrite
Copy link

@CyberAP Would using iframes help solve this problem for you? If async rendering is enough of a concern for you application to solve for (due to computationally expensive parts) then perhaps this hinting that those particular pieces should be considered separate resources with their own URL on your server.

For example:

<body>
  <div>start of content here</div>
  <iframe src="computationally-expensive"></iframe>
  <div>rest of content</div>
</body>

Are there constraints you see this imposing that wouldn't work for you case?

@brandonmcconnell
Copy link

brandonmcconnell commented Oct 2, 2023

thoughts re iframe workaround

I don't think iframes would be a fix for this. There are many cases where the iframe content would need to be sized dynamically, which then requires using window.parent.postMessage for the frame to declare its own minimum height given a width so the parent and child frames can display the frame as a seamless piece of the UI.

This same limitation also plays into any bit of data that both frames need to share with each other.

thoughts re slot workaround

And for the same limitations that @CyberAP mentioned, I don't personally like the "slot" idea either if it would require wrapping the entire app in a web component, thereby suppressing the entire app into the ShadowDOM, which comes with a number of limitations on its own, and many frameworks have difficulty working within the ShadowDOM without the use of a tool like react-shadow-scope.

general supporting argument and field research (re existing JS-based solutions)

This <teleport> element is a very common and necessary piece of most if not all JS frameworks (typically referred to as "portals"), and having something like this in native HTML would be a huge win.

@keithamus
Copy link
Contributor

basically have to wrap your whole app within a Web Component

You could use a <div> instead of <tele-port>.

suppressing the entire app into the ShadowDOM, which comes with a number of limitations on its own

Could you describe some of these?

and many frameworks have difficulty working within the ShadowDOM without the use of a tool like react-shadow-scope.

As far as I understand it any new element would have similar issues with pre-existing tooling and libraries. I’m struggling to see how creating a new element would not suffer from the same issues.

I’m not advocating for using ShadowDOM for this case, but I am curious what the specific barriers are; it would help establish motivation/justification for a specific solution to this use case, as well as help establish some criteria/constraints.

@keithamus keithamus added addition/proposal New features or enhancements needs concrete proposal Moving the issue forward requires someone to figure out a detailed plan labels Nov 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
addition/proposal New features or enhancements needs concrete proposal Moving the issue forward requires someone to figure out a detailed plan
Development

No branches or pull requests

6 participants
@keithamus @CyberAP @annevk @brandonmcconnell @0xdevwrite and others