tomekowal
The topic of optimistic UIs in LiveView came up already e.g. How do you achieve Optimistic UI in Phoenix with LiveView? by @pillaiindu
but I wanted to show my solution.
LiveView team claims that LV is not suitable for optimistic UIs but I feel that there is a conceptually easy fix for that I present in this repo: GitHub - tomekowal/optimistic_counter: An experiment with optimistic UIs in Phoenix LiveView · GitHub
I described my solution in the optimistic_counter/README.md at master · tomekowal/optimistic_counter · GitHub
Let me know what you think about it!
Trending in Discussions
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
New
Hey there,
It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
I am happy to introduce the very α version of the new programming language compiled to BEAM.
Welcome Cure.
It has literally three kille...
New
Quite interesting article Google brought me. Didn’t find any mentions about it here.
What do you think in general? Would you use togethe...
New
Hi everyone!
The first release candidate for the Expert language server project is now available!
We’ve published a press release detai...
New
Hi there! :wave:
@frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
A little off-topic, but I feel like people here have a good head on their shoulders.
I used to be quite good at making software. Was luc...
New
Other Trending Topics
Edit: 2026 May 15 - This post is archived.
Mob is alive!!
Main docs: mob v0.7.11 — Documentation
A bit of explanation for the slightly c...
New
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
Hobbes is a low-level distributed database for the Elixir programming language.
Hobbes provides a simple, safe, and scalable storage lay...
New
Hi there! We created Gust: A task orchestrator inspired by Airflow.
For those who have never heard about Aiflow, it’s a Python-based wor...
New
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #ai
- #elixirconf-us
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #elixirconf-eu
- #metaprogramming
- #hex










Showing Posts 14 to 5- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
tomekowal
I fiddled around with existing clocks and references.
I think we need a completely new one for the purpose.
I can’t reuse view.ref because server initiated events would mess up current button references when synchronizing the clocks.
I also can’t reuse underlying transport numbering because keep-alive messages could mess up the clocks.
So I believe, I would have to add the clock to the payload.
tomekowal
Yes, We would need to make sure that the hook is closely tied to the event for two reasons:
So I would even send the event before running the hook.
josevalim
The clock example will definitely work with what we have in mind. The trick though is that, because you have to update the client, you won’t be using phx-click when you first click on the button, but rather a hook, so you can update the client and then push the event.
tomekowal
Some questions to make sure I understand the solution proposed here. Let’s work on the counter example to have something concrete.
We have two DOM elements: the button that emits click event and the counter.
Where do I use the
this.syncPushEvent? Do I attach it toonClickof that button insidemountedsection of that hook? Will that prevent sending regular event?Where do I put the code that updates the counter? in the
updatedsection of the button hook? How do we know we should not update the counter in the meantime?I think that the solution LiveView currently uses for buttons can work only because the event and state update are for the same DOM element. In case of optimistic UI, we should be able to change multiple parts of the page with a single event.
I was thinking about a different solution using client and server clocks.
client.clock. The server has its own, let’s call itserver.clockview.ref.<p phx-update="optimistic"><%= @counter %></p>.<button phx-click="inc" phx-hook="Button">+</button>I believe that solution is much more general because it takes into consideration both events started by the browser and server.
It can’t replace the current solution for buttons with
view.refbecause you need to precisely know which client event that button is handling.Also without separate clocks, you can’t handle optimistic updates originating on the server.
Does that make sense?
The machinery might seem complicated but I wanted it to work on examples like this:
This works even if server-side increments the counter a bunch of times.
josevalim
I have talked to Chris about an API like this:
In a hook, you will be able to call
this.syncPushEvent(...)this.syncPushEvent(...)will block all over-the-wire updates to the Hook, until an ack to the syncPushEvent is received. Custom JS code in the hook still runs thoughOnce a reply for the push event is received, we call the hook updated callback, so you can apply the server state to the hook contents
It is basically the mechanism that we use for optimistic UIs in buttons and forms, except we are making it available for hooks too. WDYT?
tomekowal
Haha
I might not have been clear enough 
Thanks for validation! I’ll check if I am able to dig in into infrastructure enough to propose something meaningful.
I currently imagine the API like this:
phx-hookbut I would like to tie optimistic updates to JS LV events instead of DOM lifecycle events)LostKobrakai
Seems like I misunderstood the intro. Seems like counters as examples nowadays automatically mean distributed state to me
josevalim
FWIW, LiveView already does this internally. For example, imagine you have three buttons on the page. Once you click them, they change their text to “Processing…”. Processing each button takes 1 second. If you click all 3 of them one right after the other, the first response will come in t=1, then t=2, then t=3.
if LiveView did not track the events, once t=1 arrived, all buttons would revert to their original text, but it doesn’t.
So maybe we can generalize this a bit so people can also leverage this information in hooks or similar, but the whole infrastructure is already there. This may be possible, I think it is a great idea!
Not really. The goal with optimistic UI is to change the client as a way to optimistically guess what the server will return. There is no state is really. The changes you do on the client will be discarded as soon as the ack is received.
LostKobrakai
You’ll lose that as soon as your client becomes stateful for the state you also deal with on the server.
This is exactly the reason, why liveview doesn’t synchronize state at all. There’s state on the server and there’s markup derived from this state. The markup is sent to the client and replaces existing markup. There’s the fancy markup diffing, where the client does indeed hold some amount of state (the static parts), but everything on the client is replaced in the case of a reconnect.
This basically boils down to an CRDT implementation. There’s e.g. automerge for JS, which implements crdts for json data and also has existing tooling for synchronising data via network connections. The “problem” for an elixir based solution is that you need node on the server or you need to re-implement the automerge crdt protocol in elixir. I’ve experimented with automerge from client to client proxied through phoenix channels in the past and it’s interesting tech, but also complex.
tomekowal
Thanks for your input! If I understand you correctly, you propose to write the core event handling logic in JS so that you can reuse it both on the server and client and then use channels to synchronize the states.
It might work but LiveView gives me much more. The server LiveView process is a single source of truth and I loose that if I use plain channels. The state synchronization is very hard to do efficiently so I really appreciate how great LiveView is in reducing the payload size between client and server.
LiveView also gives me entire lifecycle in case of dropped connections. Doing all that using channels seems like a big hurdle that would end up in a half reimplementation of LiveView.
I might be greatly underestimating the task of adding event counters to client and server side of LiveView but after we have that, optimistic UI algorithms boils down to:
It might need a separate “client modification timestamp” for each “gap” in the template and some JS functions to set that stamp when you modify those gaps on the client side. But it still seems like much less work than building custom solutions on bare channels.