114Thinking & streaming
The wait, made legible. Three squares fading on a 1.2s loop beside a mono label that says what is actually happening, a disclosable trace of the steps taken, tool chips for what was read, and a block caret while tokens arrive.
Use it for
- Between send and first token — with a label that names the stage, not a generic “Thinking…”
- Tool chips whenever the assistant reads something the student could check themselves
- The trace on any answer that consulted more than one source
Not for
- A bouncing three-dot indicator: Principle 5 rules out springy motion, and opacity carries the same meaning
- Hiding the tools it used — the difference between a tutor and an oracle is that you can see what it looked at
Thinking
The label is the status; the dots are decoration. Name the stage — “Reading your progress” tells a waiting student more than a spinner ever will.
Reading your progress
markup
<p class="ns-aithinking" role="status" aria-live="polite"><span class="ns-aithinking__dots" aria-hidden="true"><i></i><i></i><i></i></span>Reading your progress</p>Streaming
A mono block caret on a 1.1s step timing — a cursor is a discrete thing, so it steps rather than fades.
Three project ideas that map to what you have already built, hardest last
markup
<div class="ns-aiturn__body" style="max-inline-size:36rem"><p>Three project ideas that map to what you have already built, hardest last<span class="ns-aistream" aria-hidden="true"></span></p></div>Tool calls
What it read, as chips. Running spins, done checks, failed carries the error border — and a failed tool does not silently become an unsourced answer.
Read your progress Searched catalog6 Checking exam outline Trailhead lookup
markup
<p>
<span class="ns-aitool" data-state="done"><i class="ph ph-check-circle" aria-hidden="true"></i>Read your progress</span>
<span class="ns-aitool" data-state="done"><i class="ph ph-check-circle" aria-hidden="true"></i>Searched catalog<span class="ns-aitool__count">6</span></span>
<span class="ns-aitool" data-state="running"><i class="ph ph-circle-notch" aria-hidden="true"></i>Checking exam outline</span>
<span class="ns-aitool" data-state="failed"><i class="ph ph-x" aria-hidden="true"></i>Trailhead lookup</span>
</p>Reasoning trace
Collapsed by default. A beginner asking “what is a trigger” does not want a plan; a student debugging their own prompt very much does.
How I answered this 3 steps
Read your progress — Apex basics, lesson 03 of 12.
Searched the catalog for bulk-safe Apex material.
Checked the Platform Developer I outline against what you have finished.
markup
<details class="ns-aitrace" open>
<summary><i class="ph ph-caret-right" aria-hidden="true"></i> How I answered this <span class="ns-aisource__num">3 steps</span></summary>
<div class="ns-aitrace__steps">
<p class="ns-aitrace__step"><i class="ph ph-check-circle" aria-hidden="true"></i><span><b>Read</b> your progress — Apex basics, lesson 03 of 12.</span></p>
<p class="ns-aitrace__step"><i class="ph ph-check-circle" aria-hidden="true"></i><span><b>Searched</b> the catalog for bulk-safe Apex material.</span></p>
<p class="ns-aitrace__step"><i class="ph ph-check-circle" aria-hidden="true"></i><span><b>Checked</b> the Platform Developer I outline against what you have finished.</span></p>
</div>
</details>Accessibility contract
- The thinking block is role="status" aria-live="polite", so the wait is announced once instead of being a silent pause
- Under prefers-reduced-motion the dots, spinner and caret all stop and the label alone carries the state
- The trace is a real
<details>— it discloses with no JavaScript