# Better interop with Javascript libraries (React, Svelte, etc.)

**URL:** <https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041>\
**Category:** Proposals: Ideas\
**Tags:** phoenix, vuejs, javascript-frameworks, react, liveview, angular, svelte, suggestions\
**Created:** [June 7, 2024, 3:27pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041 "2024-06-07T15:27:08Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![markevans](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/markevans/32/31985_2.png) [@markevans](https://forum.elixirforum.com/u/markevans)\
**Post date:** [June 7, 2024, 3:27pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/1 "2024-06-07T15:27:08Z")

</div>

Hi!

I feel like Phoenix is slightly missing a trick when it comes to front-end Javascript libraries like React, Svelte, etc.

I feel that Javascript framework components could be treated as even more of a first-class citizen than they currently are.

I realise that most, if not all, of what you need to do can be done just with LiveView, but there are times when you want a little bit more interactivity, or it doesn’t make sense to have some browser-related state in the LiveView process memory.  
In those cases rendering JS framework components (particularly just as leaf nodes) from LiveView is the perfect fit.

Yes, we can use hooks for that, and also yes, there are libraries that provide these hooks, but I believe it could be even easier if Phoenix did **half** the work for you, i.e. the non-framework-specific parts.

Currently, a library that helps to plug a JS framework component into LiveView has to:

1. provide elixir code, e.g. a function component, to render the component from the liveview
2. provide javascript hook code, to mount the JS framework component and update appropriately

If Phoenix did the non-framework-specific parts out of the box (1. and some of 2. above), then for a user to use components from any given JS framework they’d only need the adapter part of 2. above, which would likely live in a third-party npm package (i.e. no need for elixir code at all).

I’ve just released a simple library, [Komodo](https://github.com/hungry-egg/komodo) (see [Komodo - easily render React, Svelte, Vue, Angular, any JS framework component from Liveview](https://forum.elixirforum.com/t/komodo-easily-render-react-svelte-vue-angular-any-js-framework-component-from-liveview/64039)) that does (1) and (2) above, but it would be great if the generic parts weren’t even needed because Phoenix already did it (and had a standard interface for a “js component” that each library would adapt to).

To be specific, the Komodo library currently requires the user to do this in `app.js`:

```js
import { registerJsComponents } from "komodo";
import componentFromReact from "some-third-party-adapter-lib-for-react";
import SomeComponent from "path/to/some/react/component";

// ...

let liveSocket = new LiveSocket("/live", Socket, {
  hooks: {
   komodo: registerJsComponents({
     MyReactComponent: componentFromReact(SomeComponent)
   })
  }
  // ...
});

```

If Phoenix already did this, this would become, for example

```js
import componentFromReact from "some-third-party-adapter-lib-for-react";
import SomeComponent from "path/to/some/react/component";

// ...

let liveSocket = new LiveSocket("/live", Socket, {
  jsComponents: {
    MyReactComponent: componentFromReact(SomeComponent)
  }
  // ...
});

```

instead.

Anyway just throwing around a few thoughts - I hope that made at least some sense!

At the very least it would be great if Phoenix (i.e. HEEX) had built-in support for custom elements (i.e. native web components) that went as far as:

- allowing props that were more than just strings, e.g. arrays, objects
- allowing listening to custom events

without requiring the user to write an extra hook for this.  
Then at least people could always have the option of wrapping their framework component with a custom element if the above wasn’t feasible.

What do you think? Any thoughts welcome!

---

<div class="post-metadata">

**Author:** ![cmo](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/cmo/32/19618_2.png) [@cmo](https://forum.elixirforum.com/u/cmo)\
**Post date:** [June 7, 2024, 3:39pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/2 "2024-06-07T15:39:00Z")

</div>

> [@markevans](#):
>
> At the very least it would be great if Phoenix (i.e. HEEX) had built-in support for custom elements (i.e. native web components)

I believe Chris has mentioned that is one of the things he still wants to achieve.

---

<div class="post-metadata">

**Author:** ![superchris](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/superchris/32/23484_2.png) [@superchris](https://forum.elixirforum.com/u/superchris)\
**Post date:** [June 7, 2024, 4:24pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/3 "2024-06-07T16:24:02Z")

</div>

> [@markevans](#):
>
> At the very least it would be great if Phoenix (i.e. HEEX) had built-in support for custom elements (i.e. native web components) that went as far as:
> 
> - allowing props that were more than just strings, e.g. arrays, objects
> - allowing listening to custom events
> 
> without requiring the user to write an extra hook for this.  
> Then at least people could always have the option of wrapping their framework component with a custom element if the above wasn’t feasible.
> 
> What do you think? Any thoughts welcome!

Looks like our posts crossed 🙂 It’s great to hear these features requested, for custom elements I’ve implement exactly these in a library called [LiveElements](https://github.com/launchscout/live_elements). I reached out in a separate post to see if it would make more sense to integrate this kind of thing in LV proper, I’ve had suggestions from other folks that this would be a good thing and happy to help if this is desired.

---

<div class="post-metadata">

**Author:** ![markevans](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/markevans/32/31985_2.png) [@markevans](https://forum.elixirforum.com/u/markevans)\
**Post date:** [June 7, 2024, 11:23pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/4 "2024-06-07T23:23:28Z")

</div>

great that’s good to hear!

---

<div class="post-metadata">

**Author:** ![markevans](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/markevans/32/31985_2.png) [@markevans](https://forum.elixirforum.com/u/markevans)\
**Post date:** [June 7, 2024, 11:36pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/5 "2024-06-07T23:36:13Z")

</div>

> [@superchris](#):
>
> Looks like our posts crossed 🙂 It’s great to hear these features requested, for custom elements I’ve implement exactly these in a library called [LiveElements](https://github.com/launchscout/live_elements). I reached out in a separate post to see if it would make more sense to integrate this kind of thing in LV proper, I’ve had suggestions from other folks that this would be a good thing and happy to help if this is desired.

ah that’s great!  
Yeh I agree something in LV proper would be a good idea.  
If custom elements were supported more directly then an alternative to the suggestion I had above for React/Svelte/Vue/etc. of having a standard adapter interface would be to wrap the React/Svelte/Vue components in custom elements instead.  
I know that Svelte, Vue, Angular can actually all compile into custom elements anyway so that would also be an option, but if a user wants to use an off-the-shelf component it won’t usually be packaged as a custom element so they might need some kind of wrapper.

Out of interest, in LiveElements I see for listening to events it’s using the `phx-custom-event-hook` - what does this send as `parameters` to `handle_event`? Is it the CustomEvent event.detail? In the Komodo library I was umming and ahing about what to send back over the wire by default because I didn’t want accidental big payloads being sent back (e.g. the whole event object) so I ended up making the user be explicit about what gets sent as the payload, but not sure if that’s best. I guess also sometimes you might want event.clientX or something though that’s more for clicks so maybe event.detail is fine…

---

<div class="post-metadata">

**Author:** ![superchris](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/superchris/32/23484_2.png) [@superchris](https://forum.elixirforum.com/u/superchris)\
**Post date:** [June 9, 2024, 4:14pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/6 "2024-06-09T16:14:26Z")

</div>

> [@markevans](#):
>
> Out of interest, in LiveElements I see for listening to events it’s using the `phx-custom-event-hook` - what does this send as `parameters` to `handle_event`? Is it the CustomEvent event.detail? In the Komodo library I was umming and ahing about what to send back over the wire by default because I didn’t want accidental big payloads being sent back (e.g. the whole event object) so I ended up making the user be explicit about what gets sent as the payload, but not sure if that’s best. I guess also sometimes you might want event.clientX or something though that’s more for clicks so maybe event.detail is fine…

It had been a minute since I touched this code, so I had to go look to refresh my memory 🙂 For the payload of the event I send up to the phoenix channel, I take the custom element detail property and also merge in the element data set (any attributes that start with `data-`). This seems to give enough flexibility to do what I need to do in the cases I’ve encountered so far.

---

<div class="post-metadata">

**Author:** ![Sebb](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sebb/32/21818_2.png) [@Sebb](https://forum.elixirforum.com/u/Sebb)\
**Post date:** [June 9, 2024, 4:29pm UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/7 "2024-06-09T16:29:19Z")

</div>

> [@markevans](#):
>
> I feel that Javascript framework components could be treated as even more of a first-class citizen than they currently are.

We are just building an app with LV and solidjs.  
There is close to zero friction, working very nicely together.

---

<div class="post-metadata">

**Author:** ![markevans](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/markevans/32/31985_2.png) [@markevans](https://forum.elixirforum.com/u/markevans)\
**Post date:** [June 10, 2024, 8:56am UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/8 "2024-06-10T08:56:26Z")

</div>

> [@Sebb](#):
>
> We are just building an app with LV and solidjs.  
> There is close to zero friction, working very nicely together.

nice - what are you using to integrate them - a custom hook? or some library?  
I was going to write a solidjs adapter for komodo but didn’t want to have to support too many libraries myself (though would be super easy to do)

---

<div class="post-metadata">

**Author:** ![Jskalc](https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jskalc/32/35876_2.png) [@Jskalc](https://forum.elixirforum.com/u/Jskalc)\
**Post date:** [July 30, 2024, 11:38am UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/9 "2024-07-30T11:38:26Z")

</div>

Some time ago I’ve created [live\_vue](https://github.com/Valian/live_vue). Heavily inspired by LiveSvelte, it uses Vite instead of ESbuild for stateful hot reload & SSR bundling in development, also it’s easy to include all `.vue` files to app bundle by using [glob imports](https://vitejs.dev/guide/features#glob-import). We cannot use esbuild package as it doesn’t support plugins, and we need them to compile vue / svelte files.

All in all, I had very similar thoughts to you, as posted in this [twitter thread](https://x.com/jskalc/status/1785641000909836734). You need:

1. Server side function to render & sync props to your client side component (possibly with many performance optimizations like diffing props)
2. Client side hook to initialize / update props / pass events from your frontend framework to live view
3. Bundler configuration to support your framework of choice
4. SSR configuration - might be not trivial with code splitting, preloading etc.
5. Macro for creating shortcuts (eg. instead `<.vue v-component="Counter">` you can use `<.Counter>`)
6. Slots support

I’d say steps 2-4 are dependant on the frontend framework, but it’s not a “huge” difference. I’m considering creating a core library that would install individual frontend frameworks as plugins. So something very similar to what you’ve done with Komodo, just with more features provided. I don’t think it should be part of the LiveView itself, since using it is entirely optional and there are multiple opinions about framework of choice.

Btw, [Inertia.js does it in the right way](https://inertiajs.com/client-side-setup). I think doing something similar but for LiveView makes perfect sense.

---

<div class="post-metadata">

**Author:** ![Liam\_or](https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/l/8e7dd6/32.png) [@Liam\_or](https://forum.elixirforum.com/u/Liam_or)\
**Post date:** [December 7, 2024, 12:07am UTC](https://forum.elixirforum.com/t/better-interop-with-javascript-libraries-react-svelte-etc/64041/10 "2024-12-07T00:07:31Z")

</div>

I would also love to hear the approach you’re taking! Let us know if you can 😊
