cvkmohan

cvkmohan

Phoenix Svelte integration - how to handle forms?

Phoenix and Svelte look a very powerful combo. Now that we have endorsement from authorities on both sides via Rich Harris on X: “my annual reminder to try @elixirphoenix https://t.co/YF2PTpEadn also: congrats to our frenemies @htmx_org, i am definitely not mad about that 0.1% https://t.co/Px3Z9YQh3k” / X
and Chris McCord on X: “@Rich_Harris @elixirphoenix @htmx_org Phoenix and Svelte make a potent combo. Svelte with channels makes realtime apps trivial. Also check out LiveSvelte for some interesting higher level ideas with LiveView integration. Feel free to reach out when you start tinkering!” / X
May be we should really consider working with these two technologies as a combo.

Well, woutdp/live_svelte: Svelte inside Phoenix LiveView with seamless end-to-end reactivity (github.com) by @woutdp is a step in that direction. It worked great.
tonydangblog/liveview-svelte-pwa: Local-First LiveView Svelte ToDo App (github.com) by @tonydang is a great application combining both - including providing offline support for the app. However, when you go through the application - the setup looks very complex. I hope @tonydang gives a small overview on basic flow - so that we can dig deeper.
Then we have braynm/shadcn-svelte-phoenix-elixir: Using svelte + shadcn inside Phoenix (github.com) by @braynm - another integration application. This application demonstrates integrating the famed shadcn UI components into LiveView. However, it integrates only the Visual Components - but - not interactive components namely forms.
Which brings me to the main question for which I have opened this topic. How to handle forms in case of such integrations. The points to consider here are:

  1. I do not want to go into the extreme of moving entire form into frontend code. That brings encoding/decoding responses into JSON etc.
  2. At the same time, I want to take benefit of the great UI libraries that these frontend frameworks produced. Those animations - those ARIA attributes, responsive design everything.
    At this moment,
<.simple_form for={@form} id="login_form" action={~p"/users/log_in"} phx-update="ignore">
        <.input field={@form[:email]} type="email" label="Email" required />
        <.input field={@form[:password]} type="password" label="Password" required />

        <:actions>
          <.input field={@form[:remember_me]} type="checkbox" label="Keep me logged in" />
          <.link href={~p"/users/reset_password"} class="text-sm font-semibold">
            Forgot your password?
          </.link>
        </:actions>
        <:actions>
          <.button phx-disable-with="Logging in..." class="w-full">
            Log in <span aria-hidden="true">→</span>
          </.button>
        </:actions>
      </.simple_form>

is the code we use for user login - using LiveView form management. My question is:
Can we replace <.input></.input> with a svelte component? LiveSvelte supports the same syntax. All we have to do is create a file input.svelte - import the UI library input component and render it with these props. Does that work?
@chrismccord said that support for web components is in the pipeline post 1.0+ in Phoenix Liveview. Once that is done - probably there will be web components exactly meeting this need.
However, my question - can we use svelte components in similar lines?

First 10 of 21 Posts Switch mode

cvkmohan

cvkmohan OP

Zero responses. Maybe it is my mistake to combine resources and questions. :frowning:

Hermanverschooten

Hermanverschooten

I have never used svelte so I don’t know exactly what it does, only ever read the name.
But if it generates the HTML input field with the correct attributes, I do not see why it should not work.

kokolegorille

kokolegorille

The activity is less on the weekend…

I did not use LiveSvelte, but I used React for a Rich Text Editor as an input. So I guess it’s possible to replace an input with a JS input.

I remember passing json encoded data as attribute, and returning value as a json encoded string

cvkmohan

cvkmohan OP

Yeah. It occurred to me a bit lit - the weekend bit. I should have waited for Monday to post the question.
Thanks for sharing your experience. LiveSvelte and LiveVue introduced super convenient way to pass attributes and events just like you would for a normal phoenix component. That makes a real potent productivity enhancer in my view. So, was exploring about it. Before embarking on this path, I wanted to know from the experts if it is OK to tread on it. :slight_smile:

dsignr

dsignr

I use Svelte + Phoenix in production. At the moment, it is very complex handling the errors in .heex templates. I use a hack:
There is a <data> element in HTML where you can embed your code/data, say as an alternative to ouputting JSON via an API.

My Svelte components use that as the complete source of truth. The form bindings use phx-feedback-for attribute which unfortunately cannot attach itself to Svelte components. So, I render some inputs inside an invisible div and parse that to display it in my components. I know that’s definitely not the best way to go about it, but, in a previous application I was forced to write an entire API endpoint just for this use case, so this does seem like the easiest approach for now. Unfortunately. I also heard that Phoenix team have deprecated phx-feedback-for and have introduced a shim for it called phx-feedback-dom.js. I somehow feel that it may contain the answers to our problems. I will write a guide for getting Svelte into Phoenix (my workflow) working sometime this weekend and share here, too.

Edit, here is the source code. At a quick glance, I think we can use this to get the error bindings:

cvkmohan

cvkmohan OP

Thanks @dsignr for the inputs. With LiveSvelte we are already able to pass properties to the component. We can handle events also inside Phoenix LiveView itself. So, things have improved significantly is what my belief is.

<.input field={@form[:email]} type="email" label="Email" required /> has nothing Elixir specific in it. So, I guess, rendering a Svelte component with the same syntax also should be possible. The svelte component can call the def handle_event('validate',...) on change. def handle_event('submit'. ...) should have the values in each of the svelte components. If that happens, we are more or less sorted I guess.
I am hoping at some point @chrismccord will make some time and outline his views on how to integrate WebComponents into LiveView 1.0. That view will have most solutions for us.

dsignr

dsignr

Thanks Mohan, I looked into LiveSvelte before. My issue with it is for a component definition, you have to touch both backend and frontend code for each component which I am not a fan of. I understand the entire LiveView appeal is based on that to be fair, but that is not my cup of tea.
Also, the setup was complex (when I checked it out a while ago) and looks like it is still the case. This is not to say It is not a great approach or anything, but when you do a production app, with frontend devs and backend devs, it causes access problems - Frontend devs need access to backend code. FOR ME if not a good approach.
My approach is using a WebPack build for Svelte and all components reside inside the assets directory. Components are injected by ID of each HTML element. The only thing I am yet to add to the code is handling of form field errors to the Svelte components. And Chris’s snippet looks promising. My backend code is completely isolated from the frontend setup.

cvkmohan

cvkmohan OP

You mentioned a very important point @dsignr. I could not articulate it correctly. The component definition is an issue.
So, you are using Phoenix in API only mode? Then aren’t things easier? I mean - unless you want to provide reali time validation on the forms - You can continue like regular frontend-backend apps? No?
What integration are you seeking? Curious. Sorry for too many questions. I am working on an app that probably many would have done on something like next or sveltekit etc. I ventured into Phoenix - and - now - struggling a bit for the UI components etc. So, curious to note experiences.

dsignr

dsignr

No worries, so I have tried the following approaches:

  1. Pure Phoenix + LiveView
  2. Phoenix + API + JS frontend
  3. Phoenix + + Svelte
    1. is obviously the easiest choice. However, it does not scale well for complex frontends for example stuff like custom CMS. In my experience this also means frontend and backend code is very much intertwined with lots of handle_events. In 6 months, you don’t understand your own code, this was the biggest drawback for me with complex applications.
    1. This requires a tedious setup, potentially less secure as now you have to deal with access_tokens and what not, but gives the cleanest separation of frontend and backend code. I rarely use this approach unless my app really needs to have an API of some sort - maybe a Flutter application frontend. Not a fan of this approach for one person startups like mine. You have to deal with rate limiting the API, abuse, etc. This also has one downside where in you are forced to make additional queries most of the time for an object that already exists in the controller, which I am not a fan of.
    1. This is a mix of 1 and 2 in the sense that you use any JS frontend you like, say pure Svelte (without Sveltekit). You define a component inside your assets/js folder and then call it inside your .eex templates. In case of pre-loading data in a form, say for a route that is used for editing resources, you can pass your backend object as embedded JSON inside a <data> element. This can be fetched inside your onMount inside your Svelte component. I consciously mentioned .eex and not .heex because calling Svelte components inside .heex seems to cause a clash and throw errors.

The final option is to use something like LiveSvelte, I am a little afraid to use it because previously I had used something similar (not related to Svelte) called Surface, on paper it provided lot of benefits but since I adopted it during its early development phases, I kind of burned my finger and have decided to take a wait and see stance on such new products.

Obviously, native Svelte support from Phoenix would be the best way to go about this, it was great seeing those tweets from Rich and Chris on this front, but then it would also mean making the framework too opinionated if they took that direction (what happens if someone is into Vue/Angular, it is now more work for them to use Phoenix to decouple from Svelte first).

For now, I am going to go with 3) and try to see if the JS snippet Chris shared helps add form field validation directly into my components (seems like it would) and will share my progress here. Hope this helps!

cvkmohan

cvkmohan OP

Thanks for the detailing.
Not sure I can agree with your criticism of one. Lack of UI components is definitely one drawback - but - just handle_events becoming complex - I am not sure. Maybe I have not handled that big a project yet. :slight_smile:
Yes - two is definitely the least preferred choice. Most likely we are giving up all advantages that Phoenix as a framework gives.
I am curious to know how you implemented 3. I am wondering what is the big difference between 3 and 4 ( LiveSvelte). You might say the initial setup. But, once we move to vite for the entire setup - option 4 means only one setup - whereas option 3 needs to setups for handling assets.

Where Next?

Trending in Questions Top

jonnycharles
I’m in search of an Elixir library that offers PDF generation capabilities similar to Ruby’s Prawn. While there have been discussions abo...
New
spammy
I’m looking to build a personal workflow to quickly deploy web applications written in elixir/phoenix, for local consumption (ie not on t...
New
silverdr
Using Phoenix.LiveView.TagEngine as an EEx.Engine is deprecated! To compile HEEx, use Phoenix.LiveView.TagEngine.compile/2 instead. Sta...
New
dli
Before I dive in myself, did anyone successfully sprinkle Hologram into their existing LiveView app? Looking for hints regarding: Addi...
New
bottlenecked
Hi all, I wanted to ask how the community is dealing with post-release steps. Today we have Ecto migrations, which make sure that the db...
New
michallepicki
I am using Oban and occasionally, shortly after a deployment, a handful of jobs can fail because of dependency on other parts of the syst...
New
rahultumpala
Hello, I have an Elixir backend that implements a custom protocol over TCP. I want to load test the backend and assess the performance o...
New

Other Trending Topics Top

JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New
akoutmos
@hugobarauna and I (Alex Koutmos) have been hard at work on writing a book on Nerves that takes you from simply blinking LEDs to building...
New

We're in Beta

About us Mission Statement