Optimistic UI

옵티미스틱 UI

Update the screen as if the server call already succeeded, without waiting for the response — roll back only if it fails.

Also known as: Optimistic updateOptimistic rendering
···
html
<div class="stage">
  <div class="pane"><div class="tag">✗</div>
    <button class="like" id="b1"><span class="ic">♥</span></button>
    <div class="spin" id="s1"></div>
  </div>
  <div class="pane"><div class="tag">✓</div>
    <button class="like" id="b2"><span class="ic">♥</span></button>
    <div class="check" id="s2">✓</div>
  </div>
</div>
css
.stage{width:94%;height:88%;display:flex;gap:6%}
.pane{position:relative;flex:1;border-radius:14px;border:1px solid var(--line);background:var(--surface);display:grid;place-items:center;gap:10px;overflow:hidden}
.tag{position:absolute;top:8px;left:10px;font:700 12px/1 monospace;color:var(--muted)}
.like{width:54px;height:54px;border-radius:50%;border:1px solid var(--line);background:var(--bg);display:grid;place-items:center}
.ic{font-size:22px;color:var(--muted);transition:color .1s}
.like.on .ic{color:var(--accent-2)}
.spin{width:14px;height:14px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--accent);opacity:0}
.spin.show{opacity:1;animation:spin .6s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.check{font:700 14px/1 monospace;color:var(--accent-3);opacity:0}
.check.show{opacity:1}
js
const b1 = document.getElementById('b1'), s1 = document.getElementById('s1');
const b2 = document.getElementById('b2'), s2 = document.getElementById('s2');
function cycleSlow() {
  s1.classList.add('show');
  setTimeout(() => { b1.classList.add('on'); s1.classList.remove('show'); }, 1300);
  setTimeout(() => { b1.classList.remove('on'); }, 2600);
}
function cycleFast() {
  b2.classList.add('on');
  setTimeout(() => { s2.classList.add('show'); }, 120);
  setTimeout(() => { s2.classList.remove('show'); }, 900);
  setTimeout(() => { b2.classList.remove('on'); }, 2600);
}
cycleSlow(); cycleFast();
setInterval(() => { cycleSlow(); cycleFast(); }, 3000);

The traditional flow is request → spinner → response → re-render. Optimistic UI updates the screen the instant the action fires — for high-confidence actions like a like or a checkbox — and rolls back with an error only in the rare failure case.

It's closely tied to the Doherty Threshold: when perceived latency approaches zero, the app *feels* instant. Slack and X's like/reaction buttons are the classic example.

Left waits for a spinner before filling in; right fills in immediately and confirms with the server silently afterward.

When to use

Use it for low-risk, easily reversible actions (like, toggle, add to cart). Avoid it for payments or deletions that are hard to undo.