Add the text shimmer component for "Thinking…" labels (#3152)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-10-05 23:26:59 +02:00
1 parent 6c46d55336
commit 744f9fecf5
13 files changed
+409 -1

No files matched your search

@@ -0,0 +1,79 @@
---
title: Text shimmer
summary: A highlight that sweeps across a short label while an agent thinks or a task runs.
description: Show that something is in progress with the text shimmer - a light band that moves across a label such as "Thinking…" until the result arrives.
related: [/ui/components/spinner, /ui/components/placeholder, /ui/components/chat]
source: core/scss/ui/_text-shimmer.scss
css-vars: text-shimmer
classnames:
component:
- class: text-shimmer
desc: Dims the text and sweeps a highlight across it
part:
- class: text-shimmer-loader
desc: A small spinner before the label
---
import Example from '@components/Example.astro';
## Basic example
Add `.text-shimmer` to a short label that reports work in progress. The label fades in, then the text is dimmed and a band of full color moves across it from start to end.
<Example centered>
<span class="text-shimmer">Thinking…</span>
</Example>
## Colors
The shimmer is a mask, so the text keeps its own color. Combine it with any text color utility.
<Example centered>
<div class="d-flex flex-column gap-2">
<span class="text-shimmer">Thinking…</span>
<span class="text-shimmer text-secondary">Thinking…</span>
<span class="text-shimmer text-primary">Thinking…</span>
<span class="text-shimmer text-green">Thinking…</span>
</div>
</Example>
## With a loader
Put an empty `.text-shimmer-loader` before the label when the text alone is too quiet. It is a small spinner drawn by the element alone. It sits inside the shimmer, so it takes the color of the text and dims with it.
<Example centered>
<div class="d-flex flex-column gap-2">
<span class="text-shimmer" role="status"><span class="text-shimmer-loader" aria-hidden="true"></span>Thinking…</span>
<span class="text-shimmer text-primary" role="status"><span class="text-shimmer-loader" aria-hidden="true"></span>Generating a reply…</span>
</div>
</Example>
The loader is a `1em` box, so it follows the font size. Set `--tblr-text-shimmer-loader-size` and `--tblr-text-shimmer-loader-border-width` to resize the ring inside it, `--tblr-text-shimmer-loader-duration` to change its speed, `--tblr-text-shimmer-loader-opacity` to change how faint the ring behind the arc is, and `--tblr-text-shimmer-loader-margin` to change the space before the label.
## Speed and contrast
Set `--tblr-text-shimmer-duration` to change how long one sweep takes, and `--tblr-text-shimmer-opacity` to change how much the text is dimmed between sweeps. The fade-in is `320ms` by default; change it with `--tblr-text-shimmer-fade-duration`.
<Example centered>
<div class="d-flex flex-column gap-2">
<span class="text-shimmer" style="--tblr-text-shimmer-duration: 1s">Fast sweep</span>
<span class="text-shimmer" style="--tblr-text-shimmer-duration: 4s">Slow sweep</span>
<span class="text-shimmer" style="--tblr-text-shimmer-opacity: 0.7">Less contrast</span>
</div>
</Example>
## In a chat
Use the shimmer in place of a reply that has not arrived yet, next to the avatar of the assistant.
<Example centered>
<div class="d-flex align-items-center gap-2">
<span class="avatar avatar-xs">AI</span>
<span class="text-shimmer text-secondary" role="status"><span class="text-shimmer-loader" aria-hidden="true"></span>Reading the file…</span>
</div>
</Example>
## Accessibility
- The animation is only a hint. The label itself has to say what is going on, for example "Thinking…" or "Uploading 3 files…".
- Add `role="status"` when the label appears while the user waits, so screen readers announce it and any change to it.
- When the user prefers reduced motion, the sweep stops and the text shows in its full color.