jfpedroza

jfpedroza

Running LiveView inside a web component with shadow DOM

Hi.

We are considering offering web components to our customers so they can embed parts of our application in their website. I’m exploring using LiveView for that and have found some challenges. I’m aware of LiveState and have tested it, but I want to rule out LiveView first.

I managed to embed a LiveView in another page in a web component without shadow DOM and have it connect to the socket, everything works.

Using web components without shadow DOM has the issue of component styles interfering with the global style and vice versa. So I want to make it work with shadow DOM.

The problem is that then the shadow root is not visible in the JavaScript side of LiveView since it looks up everything
starting from document. I managed to connect the socket and detected the live view by simulating what
liveSocket.connect() does.

component.shadowRoot.querySelectorAll('[data-phx-session]:not([data-phx-parent-id])').forEach(rootEl => {
  let view = window.liveSocket.newRootView(rootEl)
  view.setHref(window.liveSocket.getHref())
  view.join()
  if(rootEl.hasAttribute("data-phx-main")){ this.main = view }
});
window.liveSocket.bindTopLevelEvents()
window.liveSocket.socket.connect()

With that, I get the log that says phx-some-id mount: but then it fails in attachTrueDocEl because it tries to find
that ID in document. So, I think explicit support in LiveView is necessary to do this. Maybe keeping in each view
which root to use for lookup, whether document or some shadow root set during the “join” phase.

What do you think? Is that something that could be supported by LiveView? Or maybe there are other technical challenges that complicate things.

Most Liked

adw632

adw632

I guess you can do it that way, although it means the page load requires some more round trips before it can display content.

I do think there is a valid use case for this, Phoenix should be able to do SSR for custom elements using the draft Declarative Shadow DOM. I think conditionally rendering in the Heex templates within a template element in the initial render would support hydration of custom elements as per the spec.

I honestly don’t think there is much of a gap to build web components in Elixir with the initial render being regular LiveView and the component is delivered with some elixir transpilation to JS like what Hologram does and this could completely eliminate any need to run node to support server side Javascript rendering and provide a rich UI all in Elixir.

bob

bob

So, I usually just lurk here, but I think I was one of the first to figure out how to build and launch cross-domain LiveView widgets >3 years ago in a production application (fintech space).

The approach I took was a custom element that defined a shadow, and its contents were an iframe. Load your LiveView URL into the iframe. It’s as easy as that. If you need to also have client-side (from the embedding side) interactions, you’ll be using postMessage. Phoenix hooks between your LiveView and your server just work like normal. No hacking LiveView required (but it did lead to a coworker submitting a patch to Phoenix to fix up an issue with private browsing sessions that’s now included).

The CTO even gave a talk showing off my work at ElixirConf — https://youtu.be/DA32q8kd9pA?feature=shared

If I’m understanding what you’re looking for, I would be happy to chat with you more about it if you would like (email/zoom). There’s a number of little things to get right with CSP and whatnot to make the experience smooth and easy for those consuming your widgets/components. I can be reached at my username at my domain.

kokolegorille

kokolegorille

Hello and welcome,

I have used web components with Phoenix socket and channels

It is simple because there is a npm phoenix package

https://www.npmjs.com/package/phoenix

It’s probably simpler than using Liveview socket, and can be used with shadow dom

Last Post!

adw632

adw632

Yes it would certainly be primarily for regular site use cases as the initial render is important for SSO.

However I can also see use cases that would allow the component author to ship a tiny shim component and dynamically load the content and the full component code on the first render. This would be a nice way to handle seamless server based upgrades.

Where Next?

Popular in Questions Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
hariharasudhan94
Lets say I have map like this fetching from my database %{"_id" => #BSON.ObjectId<58eb1a7a9ad169198c3dXXXX>, "email" => ...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40165 209
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement