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


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="22" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>With the web frameworks, it’s exactly the same problem. A React controlled component executes its JS in lock-step with the DOM, preventing you from observing an inconsistent state. But a LiveView app cannot <em>do</em> that, because the latency would be too high.</p>
</blockquote>
</aside>
<p>Yes JS in some cases can actually do things in lockstep. But I do remember all the aweful input mask javascript code of the past, which was not at all better in breaking peoples ability to properly write in an input field.</p>
<p>Personally I consider the other direction a much more useful one. All those tools deal with similar complexities, just under different latency and access to optimizations. As soon as you do anything async in js you’re back to “no longer in lockstep” anyways.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="371931" 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/does-hologram-support-two-way-data-binding/72121/23">Post #22</a>
	                </div>
	            </div>
              <div id="likers-container-371931" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="371931"
                     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 #22"></div>
  </section>
</div>
    <div class="postbit" id="371933" data-post-id="371933">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="LostKobrakai" data-post="23" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>But I do remember all the aweful input mask javascript code of the past, which was not at all better in breaking peoples ability to properly write in an input field.</p>
</blockquote>
</aside>
<p>I see where you’re coming from here, but this is strictly an interface design problem and orthogonal to the topic of controlled components.</p>
<p>Allowing the framework (JS or not) to take complete control of the state is necessary to build complex interfaces. As a simple example, we discussed default values and form resets above, but for a complex UI you would probably want to implement those things yourself with specific business logic. I.e. which inputs are reset, to what values, how do they interact with each other? Etc.</p>
<p>There was a thread on here the other day where somebody had a form with two inputs that updated <em>each other</em> and they were having trouble making that work with LiveView. I didn’t reply because I actually cannot think of a way to do that properly in LV. You literally <em>have</em> to write a hook.</p>
<aside class="quote no-group" data-username="LostKobrakai" data-post="23" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>As soon as you do anything async in js you’re back to “no longer in lockstep” anyways.</p>
</blockquote>
</aside>
<p>This doesn’t mean you can’t provide a framework with useful guarantees. Post-fiber React, for example, is asynchronous under the hood (to avoid blocking the render thread too long) but the engine is still carefully designed not to tear the UI when updating and to execute updates in the proper order.</p>
<p>Analogously, a well-designed distributed database can still offer strict serializability (Spanner, FDB) even if there are many poorly designed databases which do not (every single Spanner derivative for some reason).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="371933" 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/does-hologram-support-two-way-data-binding/72121/24">Post #23</a>
	                </div>
	            </div>
              <div id="likers-container-371933" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="371933"
                     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 #23"></div>
  </section>
</div>
    <div class="postbit" id="371934" data-post-id="371934">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="garrison" data-post="24" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>There was a thread on here the other day where somebody had a form with two inputs that updated <em>each other</em> and they were having trouble making that work with LiveView. I didn’t reply because I actually cannot think of a way to do that properly in LV. You literally <em>have</em> to write a hook.</p>
</blockquote>
</aside>
<p>You don’t need to write a hook. You can still go the route of “my framework controls the input” by forcing an update to the ID of the input, which makes morphdom consider the input a new one and force overwriting the input text. If that’s a good idea is a different question though and that’s where a hook becomes interesting again.</p>
<aside class="quote no-group" data-username="garrison" data-post="24" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>Post-fiber React, for example, is asynchronous under the hood (to avoid blocking the render thread too long) but the engine is still carefully designed not to tear the UI when updating and to execute updates in the proper order.</p>
</blockquote>
</aside>
<p>And that’s exactly where e.g. electric-closure comes in and compiles applications not just for the client, but the combo of client and server – extending the underlying ideas to work across the network gap. Latency won’t go away, but it doesn’t mean ideas cannot extend beyond the latency. In the end it doesn’t matter if you get 60ms of latency because you’re on a cheap old android or because you’re talking to the next datacenter.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="371934" 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/does-hologram-support-two-way-data-binding/72121/25">Post #24</a>
	                </div>
	            </div>
              <div id="likers-container-371934" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="371934"
                     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 #24"></div>
  </section>
</div>
    <div class="postbit" id="371945" data-post-id="371945">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>The <a href="https://forum.elixirforum.com/t/liveview-form-events-race/72116" rel="nofollow">particular case</a> was a bit trickier than that. And, ahem, <em>you</em> were the one to suggest a hook <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>But the underlying problem there is a consistency problem: the state the client receives back from the server is out of date (user has typed more) since it was sent. The bit about debouncing is actually a red herring.</p>
<aside class="quote no-group" data-username="LostKobrakai" data-post="25" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>And that’s exactly where e.g. electric-closure comes in and compiles applications not just for the client, but the combo of client and server</p>
</blockquote>
</aside>
<p>This framework came up before in another similar discussion (it might have even been me who brought it up, I can’t recall) but I still haven’t taken a proper look yet. I really need to do so, it sounds very interesting.</p>
<p>BTW, for anyone trying to search it’s <a href="https://github.com/hyperfiddle/electric" rel="noopener nofollow ugc">Electric <em>Clojure</em></a>.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="371945" 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/does-hologram-support-two-way-data-binding/72121/26">Post #25</a>
	                </div>
	            </div>
              <div id="likers-container-371945" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="371945"
                     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 #25"></div>
  </section>
</div>
    <div class="postbit" id="371947" data-post-id="371947">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Cool, thanks for sharing the link. Looks like it has some similarities to the approach Hologram is taking though maybe pushed to another level with its <code>client</code> and <code>server</code> blocks in the same function and its DOM approach. Also reminds me a bit of Meteor’s isomorphism.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="371947" 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/does-hologram-support-two-way-data-binding/72121/27">Post #26</a>
	                </div>
	            </div>
              <div id="likers-container-371947" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="371947"
                     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 #26"></div>
  </section>
</div>
    <div class="postbit" id="371955" data-post-id="371955">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="bartblast" data-post="10" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<p>Based on the feedback here, I’ll definitely avoid “two-way binding” or “bidirectional binding” since these don’t accurately describe what Hologram does and have historical baggage.</p>
<p>I’m considering these alternatives:</p>
<ul>
<li>“Controlled Inputs” - familiar to React developers</li>
<li>“State-Synchronized Inputs” - descriptive for newcomers</li>
<li>“Input Synchronization” - focuses on the key benefit</li>
</ul>
<p>(or “Form Elements” instead of “Inputs”)</p>
<p>The core concept is that Hologram maintains unidirectional data flow while solving the DOM synchronization problem that LiveView can’t address.</p>
<p>What do you think would be the clearest terminology? I want to get this right since it’ll be used throughout the documentation and forum discussions.</p>
</blockquote>
</aside>
<p>FWIW I would characterize this as an instance of “client-side local state reconciliation”. I think “reconciliation” is a better term than synchronization in this domain as the former is associated with network boundaries and netsplits, which is different from what the Hologram user’s experience is (Hologram owns the network hop for you, then does reconciliation between the new client-local state and the existing DOM-owned client-local state, if I understand things correctly).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="371955" 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/does-hologram-support-two-way-data-binding/72121/28">Post #27</a>
	                </div>
	            </div>
              <div id="likers-container-371955" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="371955"
                     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 #27"></div>
  </section>
</div>
    <div class="postbit" id="371999" data-post-id="371999">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group quote-modified" data-username="dimitarvp" data-post="20" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/dimitarvp/48/38664_2.png" class="avatar"> dimitarvp:</div>
<blockquote>
<aside class="quote no-group" data-username="bartblast" data-post="19" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<p>You can’t have DOM/server synchronization issues when the DOM’s stateful nature and application state are managed in the same execution context.</p>
</blockquote>
</aside>
<p>…means that your entire app in this case will be Elixir transpiled to Javascript, living in the browser in its entirety and thus avoiding to sync up with a server in the first place?</p>
<p>I am very not sure I am getting this right – likely not – but your analysis intrigued me, though I have near-zero context on Hologram. Still, if you are willing to expand on the “same execution context” and why does it avoid the sync / distribution problems exactly, it would be illuminating.</p>
</blockquote>
</aside>
<p>Hologram transpiles your Elixir UI components to JavaScript that runs entirely in the browser. When you write:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">&lt;input type="text" value={@age} $change="update_age" /&gt;

def action(:update_age, %{event: %{value: age}}, component) do
  put_state(component, age: age)
end
</code></pre>
<p>This becomes JavaScript that executes locally in the browser. So when a user types:</p>
<ol>
<li>DOM updates immediately (user sees their input)</li>
<li>Hologram’s transpiled Elixir code updates component state immediately</li>
<li>Both happen in the same JavaScript execution context - no network involved</li>
</ol>
<p>The “same execution context” means both the DOM manipulation and your Elixir state management logic are running as JavaScript in the browser, so there’s no distributed system to coordinate. No server roundtrips, no network latency, no consistency gaps.</p>
<p>You still have a server for your backend logic, but here’s the key: Hologram automatically determines what needs to run on the client (UI components, event handlers, state management) and transpiles only that code to JavaScript. Your database queries, business logic, etc. stay on the server as regular Elixir.</p>
<p>So you write everything in Elixir, and Hologram figures out the client/server boundary for you - transpiling just the UI parts to JS while keeping the rest as server-side Elixir.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="371999" 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/does-hologram-support-two-way-data-binding/72121/29">Post #28</a>
	                </div>
	            </div>
              <div id="likers-container-371999" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="371999"
                     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 #28"></div>
  </section>
</div>
    <div class="postbit" id="372006" data-post-id="372006">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="bartblast" data-post="29" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<p>You still have a server for your backend logic, but here’s the key: Hologram automatically determines what needs to run on the client (UI components, event handlers, state management) and transpiles only that code to JavaScript. Your database queries, business logic, etc. stay on the server as regular Elixir.</p>
</blockquote>
</aside>
<p>Key insight. Thanks a bunch.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="372006" 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/does-hologram-support-two-way-data-binding/72121/30">Post #29</a>
	                </div>
	            </div>
              <div id="likers-container-372006" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="372006"
                     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 #29"></div>
  </section>
</div>
    <div class="postbit" id="372064" data-post-id="372064">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group quote-modified" data-username="LostKobrakai" data-post="21" data-topic="72121" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<aside class="quote no-group" data-username="bartblast" data-post="19" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/48/17647_2.png" class="avatar"> bartblast:</div>
<blockquote>
<p>The key difference: LiveView must continuously <strong>resolve</strong> state inconsistencies between the inherently stateful DOM and server, while Hologram <strong>prevents</strong> state inconsistencies from occurring in the first place.</p>
</blockquote>
</aside>
<p>That’s not fully true though. Yes there’s no network boundry and latency, but hologram is also a separate stateful system next to the dom trying to ensure the dom looks to it’s liking – just like the very same is true for react or whatever else sits in the same category. None of those can prevent the dom from changing underneight their feet, they can only correct it to match their state. If you go and e.g. do <code>someElement.innerHTML = "abc"</code> in the console – the more common case of that would be browser plugins – that won’t be corrected until some other side effect triggers the reconsiler in react or changes the signal in solid.js again. I haven’t looked at hologram that deeply yet, but I would also expect you’d only adjust the dom again if the hologram state changes again to some degree.</p>
<p>I do agree that LVs method of reconciliation is not optimal, but it’s certainly not just a matter of network boundary.</p>
<p>You can look at electric-closure it’s compiling reactive applications across both server and client. The react reconciler inspired the usegpu library, which does reactive/declarative programming for webgpu, a domain usually handled quite differently – so it’s not some trivial piece of code either.</p>
</blockquote>
</aside>
<p>Looking at this discussion, I think there’s an important distinction to make about <strong>scope and intended use cases</strong> that clarifies the architectural differences.</p>
<p>You’re right that Hologram is still a separate stateful system next to the DOM, and that external DOM manipulation (browser plugins, console commands) can create inconsistencies that won’t be corrected until the next reconciliation cycle. That’s a fair technical critique for specific cases that intentionally avoid the intended use through the API.</p>
<p>However, I’d argue this is similar to saying “Linux isn’t secure because you can modify <code>/dev/mem</code> as root” - while technically true, it misses the practical scope of what the system is designed to solve.</p>
<h2><a name="p-372064-where-hologram-does-prevent-inconsistencies-1" class="anchor" href="#p-372064-where-hologram-does-prevent-inconsistencies-1" aria-label="Heading link" rel="nofollow"></a>Where Hologram Does Prevent Inconsistencies</h2>
<p>For <strong>user-driven interactions</strong> - which represent 99.9% of real web app usage - Hologram genuinely does prevent inconsistencies rather than just correct them:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">&lt;input $change="update_name" value={@name} /&gt;

def action(:update_name, %{event: %{value: name}}, component) do
  put_state(component, :name, name)
end
</code></pre>
<p>This creates a closed synchronous loop:</p>
<ol>
<li>User types → DOM event fires immediately</li>
<li>Hologram handler executes in same event loop tick</li>
<li>State updates immediately</li>
<li>VDOM reconciliation happens immediately</li>
</ol>
<p>JavaScript’s event loop guarantees that the event handler runs atomically and completely before any other queued tasks can execute. This means the DOM event processing and state update happen in true lock-step, with no inconsistency window where they can diverge.</p>
<h2><a name="p-372064-the-key-architectural-difference-2" class="anchor" href="#p-372064-the-key-architectural-difference-2" aria-label="Heading link" rel="nofollow"></a>The Key Architectural Difference</h2>
<p>The fundamental issue is that latency creates an unavoidable distributed systems challenge for LiveView:</p>
<ul>
<li><strong>LiveView</strong>: User input → network roundtrip → server processing → network response → DOM reconciliation (with race conditions, ordering issues, connection failures)</li>
<li><strong>Hologram</strong>: User input → immediate local state update → immediate DOM sync (atomic)</li>
</ul>
<h2><a name="p-372064-external-dom-manipulation-is-an-edge-case-3" class="anchor" href="#p-372064-external-dom-manipulation-is-an-edge-case-3" aria-label="Heading link" rel="nofollow"></a>External DOM Manipulation Is An Edge Case</h2>
<p>Interestingly, even direct input manipulation demonstrates Hologram’s robustness: if someone does <code>document.getElementById("my-input").value = "hacked"</code> and the input has a <code>$change</code> event handler connected to the state, Hologram reconciles automatically and immediately when the programmatic change occurs.</p>
<p>Yes, someone could do <code>document.getElementById("my-div").innerHTML = "hacked content"</code> as you mentioned and break VDOM synchronization until the next reconciliation cycle - but this is equivalent to:</p>
<ul>
<li>Using <code>dangerouslySetInnerHTML</code> in React and complaining about inconsistencies</li>
<li>Manually editing database files and complaining about corruption</li>
<li>Writing kernel memory directly and complaining Linux crashed</li>
</ul>
<p>These break the intended API contract and represent edge cases, not fundamental architectural limitations.</p>
<h2><a name="p-372064-the-real-world-impact-4" class="anchor" href="#p-372064-the-real-world-impact-4" aria-label="Heading link" rel="nofollow"></a>The Real-World Impact</h2>
<p>For the scenarios developers actually encounter (form interactions, user events, programmatic state updates through the framework), Hologram’s architecture eliminates the consistency problems that LiveView cannot solve due to network latency.</p>
<p>While no abstraction is perfect when you deliberately bypass it, the practical advantage for intended use cases is significant - as <a class="mention" href="/u/garrison" rel="nofollow">@garrison</a> noted with his example of two-input forms that “literally require hooks” in LiveView but work naturally in Hologram.</p>
<p>When developers use Hologram’s event system as intended, it prevents inconsistencies from occurring. When they bypass this system with direct DOM manipulation, inconsistencies can happen - but that’s breaking the API contract.</p>
<p>So… to sum up… given that DOM event handlers are guaranteed to execute atomically without interruption from other queued JavaScript, I think it’s fair to say the distinction I made earlier that you quoted holds true within the framework’s intended scope of user-driven interactions.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="372064" 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/does-hologram-support-two-way-data-binding/72121/37">Post #36</a>
	                </div>
	            </div>
              <div id="likers-container-372064" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="372064"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-most-liked cat-most-liked" title="One of the top 3 liked posts in this thread!"></div>
  </section>
</div>
    <div class="postbit" id="375940" data-post-id="375940">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="bartblast" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/bartblast/120/17647_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  bartblast
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Hologram</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks for bringing up Electric Clojure! I took some time to look at the project, and it’s definitely a fascinating approach.</p>
<aside class="quote no-group" data-username="LostKobrakai" data-post="21" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>You can look at electric-closure it’s compiling reactive applications across both server and client. The react reconciler inspired the usegpu library, which does reactive/declarative programming for webgpu, a domain usually handled quite differently – so it’s not some trivial piece of code either.</p>
</blockquote>
</aside>
<aside class="quote no-group" data-username="LostKobrakai" data-post="25" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/lostkobrakai/48/3072_2.png" class="avatar"> LostKobrakai:</div>
<blockquote>
<p>And that’s exactly where e.g. electric-closure comes in and compiles applications not just for the client, but the combo of client and server – extending the underlying ideas to work across the network gap. Latency won’t go away, but it doesn’t mean ideas cannot extend beyond the latency. In the end it doesn’t matter if you get 60ms of latency because you’re on a cheap old android or because you’re talking to the next datacenter.</p>
</blockquote>
</aside>
<aside class="quote no-group" data-username="garrison" data-post="26" data-topic="72121">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/g/3bc359/48.png" class="avatar"> garrison:</div>
<blockquote>
<p>This framework came up before in another similar discussion (it might have even been me who brought it up, I can’t recall) but I still haven’t taken a proper look yet. I really need to do so, it sounds very interesting.</p>
<p>BTW, for anyone trying to search it’s <a href="https://github.com/hyperfiddle/electric" rel="noopener nofollow ugc">Electric <em>Clojure</em></a>.</p>
</blockquote>
</aside>
<aside class="quote no-group" data-username="jam" data-post="27" data-topic="72121" data-full="true">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/jam/48/36266_2.png" class="avatar"> jam:</div>
<blockquote>
<p>Cool, thanks for sharing the link. Looks like it has some similarities to the approach Hologram is taking though maybe pushed to another level with its <code>client</code> and <code>server</code> blocks in the same function and its DOM approach. Also reminds me a bit of Meteor’s isomorphism.</p>
</blockquote>
</aside>
<p>I can see many conceptual similarities with Hologram - particularly around providing a unified developer experience across the stack and writing in one language while automatically splitting code for client vs server execution.</p>
<p>When I started working on Hologram over 5 years ago, I actually considered a similar network-transparent approach where client and server code could be more seamlessly intertwined. However, I ultimately decided against it for several reasons:</p>
<ul>
<li><strong>Separation of concerns</strong> - The tight coupling between client and server logic felt like it would create architectural challenges down the line</li>
<li><strong>Testing complexity</strong> - I worried about how to properly test code that could execute “across” the contexts</li>
<li><strong>Debugging challenges</strong> - When issues arise, having explicit boundaries makes it much clearer where to look</li>
<li><strong>Boundary awareness</strong> - My instinct told me that making the network boundary explicit and visible was important for building applications that can be easily reasoned about</li>
</ul>
<p>Thinking about this now with more experience developing Hologram, I can see how that initial instinct about boundary awareness translates into specific technical concerns related to Electric Clojure’s approach:</p>
<ul>
<li><strong>Reasoning about implicit network operations</strong> - While EC’s client and server markers make it explicit where code runs, how do you reason about when data flows between these contexts? When does a seemingly local operation trigger network traffic, and what are the performance implications?</li>
<li><strong>Failure handling</strong> - The network is fundamentally unreliable (latency, failures, bandwidth constraints). How does the framework handle connection failures, timeouts, or network partitions when client and server code are so tightly coupled?</li>
<li><strong>Security and authorization</strong> - Given the blurred boundaries, I’m curious how access control and authorization are handled. Do you need to be extremely careful about what data gets exposed across the boundary?</li>
</ul>
<p>That said, I find Electric Clojure’s approach very interesting and innovative! It’s exploring a different point in the design space, and there may be elegant solutions to these challenges that I haven’t considered. The EC team is clearly pushing boundaries, and I’ll definitely be keeping track of the project for inspiration. Who knows - they might come up with solutions to these problems that could inform Hologram’s development as well!</p>
<p>Different architectural choices make sense for different use cases and philosophies, and I think both approaches have value.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="375940" 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/does-hologram-support-two-way-data-binding/72121/38">Post #37</a>
	                </div>
	            </div>
              <div id="likers-container-375940" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="375940"
                     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 #37"></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/72121/load_more?page=4">Load more posts (2 remaining)</a>
</div></template></turbo-stream>