<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="312811" data-post-id="312811">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="greven" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/greven/120/25004_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  greven
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Regarding the OP it’s really hard to answer. I have been there and ended up choosing LiveView for my current project (where it was only me as a web developer but right now we have another developer working with me). I will try to tell a brief story of my experience around the same decision I had to take.</p>
<p>My background for the last 10 years (well, till 2018) has been mostly SPA JavaScript applications (corporate oriented) with some sprinkles of Fullstack development (NodeJS and Django mostly) so when picking up the technologies for my new project (which I started in 2020) I was faced with this decision.<br>
I had React and VueJS experience from past gigs, I had written in-house component libraries for React and also VueJS for the respective projects but then I found Elixir.</p>
<p>Being frustrated with the Node ecosystem always breaking for any random reason and tired of the Python tooling and all (even though Django is great) I was looking into another Language and ecosystem with more guarantees, I found Elixir and fell in love. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>So I had Elixir for the backend (having some previous Functional Languages experience I picked it up fairly quickly) but this was around the time LiveView initially released, so being very new I decided my first draft/PoC would be Elixir Phoenix as the Backend but on the FE I would use a REST service with React (NextJS) on the FE side. The story around headless UI libraries wasn’t as great as it is today in JS land so that was also a bit of a challenge to change the design to match the style we went with in my project, but I ended up re-styling an existing UI library (Chakra UI if I recall correctly).</p>
<p>For a project of one (in the web side, I had someone else working on the data science part) I grew frustrated with managing the complexity of backend development plus all the duplication of logic in the REST API + NextJS. Also, NextJS is a bit more complex that just picking some “regular” SPA library like VueJS. But React was my choice because there were a lot more quality options in terms of libraries for it than for VueJS.</p>
<p>Because of this I started to explore other options and by now LiveView was consolidating as a nice option and with a new developer with me (that lacked experience with React, VueJS, etc), it was time for taking the final decision in what would serve us best.</p>
<p>So I decided to recreate some screens using LiveView in a weekend as a Proof of Concept, to see how fast I could port some screens we already had (we spent most of the time around business logic, backend and other details so the front end wasn’t that far along). I really loved how fast I could go with LiveView and decided to port all the FE to LiveView, dropped the REST service, dropped NextJS and went with LiveView! Life was simpler! Long live the monolith!</p>
<p>Was it a good decision? Yes it was, don’t regret it at all. But what was the challenging parts? Well, this was before Core Components and around LiveView 0.10.</p>
<ul>
<li>
<p>LiveView not being a 1.0 release and living on the edge has its drawbacks. There was quite a bit of refactoring when LEEX became HEEX, when the new Functional Components were released, etc, etc, etc. But it wasn’t that bad, maybe I spent 2-3 days tops working on re-writing code to port our user land code to the new versions of Phoenix and LiveView, still beats the complexity of maintaining a REST service and all the complexity of NextJS for me. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
</li>
<li>
<p>Yes, the lack of UI libraries was a bit of a challenge but we managed. More time than I would like was spent working on components, (like inputs, etc,), specially the more complex ones like Autocomplete, etc, but that was to price to pay, again, for adopting bleeding edge tech.</p>
</li>
<li>
<p>Forms with LiveView were a bit complex for my brain initially when managing a multi-step form with lots of state and validations, but after it clicked it all made sense. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
</li>
</ul>
<p>So in the end, this is a complex decision but there isn’t one day I regret betting on LiveView. Also it is quite exciting to see it develop and mature.<br>
While LiveView isn’t perfect (there are no silver bullet solutions), but taking into account complexity and speed of development, nowadays LiveView ranks pretty high on my list of frameworks I would default to whenever considering new product development.</p>
<p>I also started working on writing a UI component library for LiveView. I already re-started several times as I want to get the API right (taking several ideas from other libraries (from Elixir and JS land)).</p>
<p>This will for sure be an endeavour that will take several months, but I want to create something with quality, that hopefully will be a net positive in helping other people adopting Phoenix LiveView as a viable option for new projects.</p>
<p>My idea is to release a Headless UI component library and then a fully styled but customisable component library (probably using TailwindCSS).</p>
<p>Already have the name for the Headless UI one: <a href="https://hex.pm/packages/flint_ui" class="inline-onebox" rel="nofollow">flint_ui | Hex</a> (ignore it for now, still mostly empty and WIP).<br>
Flint, to help us start… fires! <img src="https://forum.elixirforum.com/images/emoji/apple/stuck_out_tongue.png?v=15" title=":stuck_out_tongue:" class="emoji" alt=":stuck_out_tongue:" loading="lazy" width="20" height="20"></p>
<p>Sorry for the very long post. <img src="https://forum.elixirforum.com/images/emoji/apple/confused.png?v=15" title=":confused:" class="emoji" alt=":confused:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312811" data-batch-url="/posts/batch_likers">
                        15
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/52">Post #51</a>
	                </div>
	            </div>
              <div id="likers-container-312811" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312811"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #51"></div>
  </section>
</div>
    <div class="postbit" id="312857" data-post-id="312857">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sodapopcan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/120/34668_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sodapopcan
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>One thing that came up a few times in this thread is the “we lost the internet” thing, ie, once you reopen your laptop (or unlock your phone) you’ll see that message and it will either take a very long time to reconnect of you just have to reload to get it to reconnect.</p>
<p>First off, I see this in development all the time.  Furthermore, I have a hobby project that a friend and I use almost daily that is running on a Fly hobby tier instance and this happens every single time without fail.  However, I recently deployed a project to a micro EC2 instance and it hasn’t been an issue at all.  You do see a flash of it while it reconnects but that’s obviously no big deal.  I’m thinking of putting a 500ms delay on showing it.</p>
<p>Anyway, I just wanted to throw that out there for anyone concerned about it, especially if you happen to be playing around with Fly’s hobby tier.  I should say that I have no idea if this is a Fly thing or a me thing <img src="https://forum.elixirforum.com/images/emoji/apple/person_shrugging.png?v=15" title=":person_shrugging:" class="emoji" alt=":person_shrugging:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312857" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/53">Post #52</a>
	                </div>
	            </div>
              <div id="likers-container-312857" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312857"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #52"></div>
  </section>
</div>
    <div class="postbit" id="312929" data-post-id="312929">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="TunkShif" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/TunkShif/120/24198_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  TunkShif
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I was trying to build a headless ui component library, because I really wish to have something like <a href="https://www.radix-ui.com/primitives" rel="noopener nofollow ugc">Radix UI</a> for phoenix framework. You can check it out here: <a href="https://forum.elixirforum.com/t/sprout-ui-unstyled-and-accessible-components-for-phoenix-framework/52360" class="inline-onebox" rel="nofollow">Sprout UI - unstyled and accessible components for Phoenix Framework</a> (it’s still WIP though). The main problems I had when implementing those components are:<br>
It’s not that easy to design a flexible and composible component API with heex template<br>
I’d like UI interactions just happen on the client side without an extra request to the server. I’ve seen a few examples of using LiveView to implement something like an accordion. It’s unnecessary to request to the server for just toggling a panel, and the UI feels not responsive at all.<br>
So a lot of user interactions and accessibility issues like aria attributes, focus management and keyboard navigation need to be addressed on the JS-side, but currently the LiveView JS command is still not enough for all of these, so it has to be achieved with JS, and involves client side DOM changes that does not play very well with LiveView DOM patch.<br>
But the biggest problem to stop me from using LiveView is just as <a class="mention" href="/u/sodapopcan" rel="nofollow">@sodapopcan</a> mentioned:</p>
<aside class="quote no-group" data-username="sodapopcan" data-post="53" data-topic="30001">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/48/34668_2.png" class="avatar"> sodapopcan:</div>
<blockquote>
<p>One thing that came up a few times in this thread is the “we lost the internet” thing, ie, once you reopen your laptop (or unlock your phone) you’ll see that message and it will either take a very long time to reconnect of you just have to reload to get it to reconnect.</p>
</blockquote>
</aside>
<p>I had a side project using LiveView deployed using Fly’s hobby tier. And I built a multi-step forms but users keeps complaining on connection lost and form state loss when switching apps on mobile, and it takes ages to reconnect.<br>
The LiveView development experience is actually pretty good but the user experience is not that good especially when users are in a slow or unstable network condition. And finally I ended up rewriting it using React, and just use Phoenix for API server.<br>
Currently, I’m quite interested in the concept of <a href="https://www.inkandswitch.com/local-first/" rel="noopener nofollow ugc">local first software</a> and hope that it can be combined with LiveView to solve the offline usability issues and get a more responsive user experience.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312929" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/54">Post #53</a>
	                </div>
	            </div>
              <div id="likers-container-312929" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312929"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #53"></div>
  </section>
</div>
    <div class="postbit" id="312931" data-post-id="312931">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sodapopcan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/120/34668_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sodapopcan
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>That’s good signal that this is a Fly hobby tier problem.  I should probably take a closer look at the docs to make sure this isn’t a known thing, but it seems strange.  It’s unfortunate regardless since Fly is very Elixir-centric and there are probably a lot of people who evaluate LiveView this way.</p>
<aside class="quote no-group" data-username="TunkShif" data-post="54" data-topic="30001">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tunkshif/48/24198_2.png" class="avatar"> TunkShif:</div>
<blockquote>
<p>I’d like UI interactions just happen on the client side without an extra request to the server. I’ve seen a few examples of using LiveView to implement something like an accordion. It’s unnecessary to request to the server for just toggling a panel, and the UI feels not responsive at all.</p>
</blockquote>
</aside>
<p>UI interactions in LiveView are meant to be done on the client with <a href="https://hexdocs.pm/phoenix_live_view/js-interop.html#client-hooks-via-phx-hook" rel="noopener nofollow ugc">JS hooks</a>.  This has been a feature since at least the second release (v0.1.1), so we were never really intended be using the server to store the state of accordions, menus, modals, etc.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312931" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/55">Post #54</a>
	                </div>
	            </div>
              <div id="likers-container-312931" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312931"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #54"></div>
  </section>
</div>
    <div class="postbit" id="312932" data-post-id="312932">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="TunkShif" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/TunkShif/120/24198_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  TunkShif
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="sodapopcan" data-post="55" data-topic="30001">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/48/34668_2.png" class="avatar"> sodapopcan:</div>
<blockquote>
<p>UI interactions in LiveView are meant to be done on the client with <a href="https://hexdocs.pm/phoenix_live_view/js-interop.html#client-hooks-via-phx-hook" rel="noopener nofollow ugc">JS hooks</a>.</p>
</blockquote>
</aside>
<p>I know that JS interop can be achieved through hooks and that’s what I’m using. The main problem is having to sync client side DOM changes with LiveView DOM patches.</p>
<aside class="quote no-group" data-username="sodapopcan" data-post="55" data-topic="30001">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/48/34668_2.png" class="avatar"> sodapopcan:</div>
<blockquote>
<p>so we were never really intended be using the server to store the state of accordions, menus, modals, etc.</p>
</blockquote>
</aside>
<p>Ideally, yes, we should use JS command or hooks to implement these interactions. But unfortunately I’ve seen some examples of using LiveView to do this, like the accordion in <a href="https://www.ash-hq.org" rel="noopener nofollow ugc">https://www.ash-hq.org</a> , the modal example in <a href="https://surface-ui.org/state_management" class="inline-onebox" rel="noopener nofollow ugc">Surface</a> , and the expandable sidebar menu in <a href="https://phoenix-storybook-demo.fly.dev/storybook/welcome" class="inline-onebox" rel="noopener nofollow ugc">Phoenix Storybook - Welcome Page</a> (no offense here, just trying to give a few examples I’ve seen). Due to my network conditions, it usually takes about a second for the UI to respond after I’ve clicked something <img src="https://forum.elixirforum.com/images/emoji/apple/smiling_face_with_tear.png?v=15" title=":smiling_face_with_tear:" class="emoji" alt=":smiling_face_with_tear:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312932" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/56">Post #55</a>
	                </div>
	            </div>
              <div id="likers-container-312932" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312932"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #55"></div>
  </section>
</div>
    <div class="postbit" id="312936" data-post-id="312936">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="adw632" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  adw632
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>These are the many reasons I’ve decided that the solution has to be a design system and web components first.</p>
<p>Then whether you use a JS framework on the client or server rendered LiveView is second. Either way the UI experience doesn’t really change much.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312936" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/57">Post #56</a>
	                </div>
	            </div>
              <div id="likers-container-312936" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312936"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #56"></div>
  </section>
</div>
    <div class="postbit" id="312957" data-post-id="312957">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="sodapopcan" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/sodapopcan/120/34668_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  sodapopcan
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Ah, ya, when there are examples out there that do this that makes it a bit harder for people to know what to do.  It does depends on the content of these things—like if a request needs to be to grab the data anyway, then I can see storing state on the server, but it would still be nicer to show a modal with a loader then bring the content in.  This kind of thing isn’t as prevalent in LiveView, though, though hopefully will become more-so with <code>assign_async</code>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312957" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/58">Post #57</a>
	                </div>
	            </div>
              <div id="likers-container-312957" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312957"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #57"></div>
  </section>
</div>
    <div class="postbit" id="312965" data-post-id="312965">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="greven" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/greven/120/25004_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  greven
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="TunkShif" data-post="54" data-topic="30001">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tunkshif/48/24198_2.png" class="avatar"> TunkShif:</div>
<blockquote>
<p>pe that it can be combined with LiveView to solve the offline usability issues and get a more responsive user experi</p>
</blockquote>
</aside>
<p>Your exploration with SproutUI is a good one in terms of API design, I’ve seen your code and took some ideas, mixed with what I’ve done on my current project.<br>
I have to agree with you. Most of the components I wrote after the LiveView.JS came out are a mix of that and Hooks and they became a bit of a mess. <img src="https://forum.elixirforum.com/images/emoji/apple/confused.png?v=15" title=":confused:" class="emoji" alt=":confused:" loading="lazy" width="20" height="20"><br>
For a component library I think the JS command should be basically ignored unless used for dispatching events of course.</p>
<p>The make it or break it for a components library is really to implement a typeahead / autocomplete / combobox component that performs well and that is for sure a challenge in LiveView if mixing Client and Server side for the reasons you mentioned.</p>
<p>I love LiveView but I agree that for the underlying base components the experience needs to be client first and server interactions should be limited to fetching data.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312965" data-batch-url="/posts/batch_likers">
                        4
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/59">Post #58</a>
	                </div>
	            </div>
              <div id="likers-container-312965" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312965"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #58"></div>
  </section>
</div>
    <div class="postbit" id="312982" data-post-id="312982">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="krishandley" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/krishandley/120/27199_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  krishandley
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>You could potentially use parts of Vue inside LiveView hooks…</p>
<p>I currently have a small alpine-esque utility system to bind text, attributes, classes, events, etc</p>
<p>Here is a small sample of syncing attributes from LiveView to the internal state.</p>
<p>So far this experiment is working quite well. If you don’t mind the extra 20ish kb for importing ref and watch.</p>
<pre data-code-wrap="js"><code class="lang-js">import { ref, watch } from "vue";

const fromAttr = (vm, el, attr, type, def) =&gt; {
  const fn = () =&gt; {
    if (type == "string") return el.getAttribute(attr) || def;
    if (type == "boolean") return el.hasAttribute(attr) || def;
    if (type == "array") return JSON.parse(el.getAttribute(attr) || "[]");
  };
  const _ref = ref(fn());
  vm._updates.push(() =&gt; (_ref.value = fn()));
  return _ref;
};

export default {
  mounted() {
    this._updates = []

    const $open = ref(false);

    const $value = fromAttr(this, this.el, 'data-value', 'string', '')
    
    watch($open, () =&gt; {
      // Do something when open changes
    });

    watch($value, () =&gt; {
      // Do something when value changes
    });
  },

  updated() {
    this._updates.forEach((f) =&gt; f())
  },

  reconnected() {
    this._updates.forEach((f) =&gt; f())
  },
}
</code></pre> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312982" data-batch-url="/posts/batch_likers">
                        2
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/60">Post #59</a>
	                </div>
	            </div>
              <div id="likers-container-312982" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312982"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #59"></div>
  </section>
</div>
    <div class="postbit" id="312988" data-post-id="312988">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="adw632" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  adw632
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="TunkShif" data-post="54" data-topic="30001">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/tunkshif/48/24198_2.png" class="avatar"> TunkShif:</div>
<blockquote>
<p>I was trying to build a headless ui component library, because I really wish to have something like <a href="https://www.radix-ui.com/primitives" rel="noopener nofollow ugc">Radix UI</a> for phoenix framework.</p>
</blockquote>
</aside>
<p>I like the Radix approach but even more I like the <a href="https://www.bits-ui.com/docs/introduction" rel="noopener nofollow ugc">Bits UI</a> approach that took the learnings from Radix and applied it to Svelte using <a href="https://melt-ui.com/" rel="noopener nofollow ugc">Melt UI</a> as a headless UI component builder.</p>
<p><a href="https://www.shadcn-svelte.com/" rel="noopener nofollow ugc">Shadcn Svelte</a> is a component library built on Bits UI and provides tailwind based styling and a basic theme system for consistent UI style. It’s intended to be a copy and paste component collection to avoid being a framework and to provide code ownership.</p>
<aside class="quote no-group" data-username="krishandley" data-post="60" data-topic="30001">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/krishandley/48/27199_2.png" class="avatar"> krishandley:</div>
<blockquote>
<p>You could potentially use parts of Vue inside LiveView hooks…</p>
</blockquote>
</aside>
<p>I have been experimenting with a very similar approach using Carbon Web Components v11 to avoid any kind of front end JS framework and the LiveElements library to provide some Phoenix component wrappers for custom elements to help with event forwarding to LiveView.</p>
<p>If I continue with LiveView I will need to extend the idea to handle some additional aspects like attrs and slots on custom elements,  most probably using a generator approach given Phoenix doesn’t appear to provide a way to <em>dynamically</em> register a function component with attributes and slots at compile time with the way the attr and slot macros work. If anyone knows how to do ths please chime in.</p>
<p>Using the Svelte Bits UI as web components would provide a streamlined semantic headless UI component library with accessibility baked in.</p>
<p>For a themed and styled component library using tailwind <a href="https://www.shadcn-svelte.com/" rel="noopener nofollow ugc">Shadcn Svelte</a> would be almost identical effort and adhering to the bits UI headless contract.</p>
<p><a href="https://svelte.dev/docs/custom-elements-api" rel="noopener nofollow ugc">Svelte web components</a> only requires setting the <code>customElement: true</code> compiler option to generate first class custom elements for use in any web page.  Because the “framework” compiles away to a tiny 2.7Kb (that’s kilobytes) support bundle size it is basically framework free at that point, allowing use of those custom elements with LiveView, dead views, or any front end framework.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="312988" data-batch-url="/posts/batch_likers">
                        3
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/help-me-choose-between-liveview-and-vue/30001/61">Post #60</a>
	                </div>
	            </div>
              <div id="likers-container-312988" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="312988"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #60"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/30001/load_more?page=7">Load more posts (1 remaining)</a>
</div></template></turbo-stream>