Thinking indicator

생각 중 인디케이터

A shimmering trace of the model's reasoning before the answer, collapsing into "Thought for N seconds" once done.

Also known as: Reasoning traceChain-of-thought disclosure
···
html
<div class="wrap">
  <div class="think" id="th">
    <button class="head" id="hd"><i class="chev">▸</i><span id="label">생각 중</span><span class="shine" id="shine"></span></button>
    <div class="body" id="body"><p id="ptxt">검색 결과를 비교하는 중…</p></div>
  </div>
</div>
css
.wrap{width:min(300px,92%)}
.think{border:1px solid var(--line);border-radius:12px;background:var(--surface);overflow:hidden}
.head{width:100%;display:flex;align-items:center;gap:7px;padding:9px 12px;border:0;background:none;cursor:pointer;color:var(--muted);font-size:12px;font-weight:600;text-align:left}
.chev{font-style:normal;font-size:10px;transition:transform .2s}
.think[data-open] .chev{transform:rotate(90deg)}
.shine{margin-left:auto;width:0;height:0}
.body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .3s ease}
.think[data-open] .body{grid-template-rows:1fr}
.body p{overflow:hidden;min-height:0;margin:0;padding:0 12px;font-size:11px;color:var(--muted);line-height:1.6}
.think[data-open] .body p{padding-bottom:10px}
#label.shimmer{background:linear-gradient(90deg,var(--muted) 0%,var(--fg) 50%,var(--muted) 100%);background-size:200% auto;
  -webkit-background-clip:text;background-clip:text;color:transparent;animation:shim 1.6s linear infinite}
@keyframes shim{to{background-position:-200% 0}}
js
const th = document.getElementById('th'), label = document.getElementById('label'), ptxt = document.getElementById('ptxt');
const steps = ['후보 답변을 비교하는 중…', '근거를 다시 확인하는 중…', '결론을 정리하는 중…'];
th.setAttribute('data-open', '');
label.classList.add('shimmer');
let i = 0;
const iv = setInterval(() => { ptxt.textContent = steps[i % steps.length]; i++; }, 700);
setTimeout(() => {
  clearInterval(iv);
  label.classList.remove('shimmer');
  label.textContent = '4초간 생각함';
  th.removeAttribute('data-open');
  setTimeout(restart, 2200);
}, 2600);
function restart() {
  label.textContent = '생각 중';
  label.classList.add('shimmer');
  th.setAttribute('data-open', '');
  let j = 0;
  const iv2 = setInterval(() => { ptxt.textContent = steps[j % steps.length]; j++; }, 700);
  setTimeout(() => {
    clearInterval(iv2);
    label.classList.remove('shimmer');
    label.textContent = '4초간 생각함';
    th.removeAttribute('data-open');
    setTimeout(restart, 2200);
  }, 2600);
}

Reasoning models emit intermediate thinking tokens before the final answer. Hide that entirely and the wait feels featureless; show it with the same visual weight as the answer and the actual conclusion gets buried. This pattern splits the difference: while it's running, a shimmering summary line ("Comparing search results…") shows something is happening, and once done it collapses into a one-line summary ("Thought for 4s") that's optional to expand.

It differs from a typing indicator in purpose — three dots are a "starting soon" signal with no content, while a thinking indicator carries actual (if brief) intermediate reasoning text that partly explains why it's taking a while.

When expanded, it should show real model output, or at least reflect its actual order — flashing decorative phrases unrelated to what's really happening is the kind of thing users eventually notice was fake, and trust doesn't come back easily.

When to use

Use it for models or agent flows where reasoning genuinely takes a few seconds or more. On a question that could be answered instantly, it reads as manufactured drama.