# Shimmer Text

> Animated gradient sweep across text — the canonical “Thinking…” / “Searching…” label for in-progress AI work.

- **Slug:** `shimmer-text` · **Category:** feedback · **Status:** beta
- **Import:** `import { ShimmerText } from "@kura-ui/react/shimmer-text";`
- **Docs:** https://kuro.abstergo.fyi/components/shimmer-text
- **Registry item:** https://kuro.abstergo.fyi/r/shimmer-text.json
- **Tags:** loading, thinking, status, text, animation, shimmer, skeleton, progress

## Install

```bash
# shadcn registry (copies source into your project)
npx shadcn@latest add https://kuro.abstergo.fyi/r/shimmer-text.json
# Kura CLI (same, plus dependency resolution and --json output)
npx @kura-ui/cli add shimmer-text
# npm package
npm install @kura-ui/react
```

## When to use

- Show that a model or agent is working: “Thinking…”, “Searching the web…”, “Reading 12 files…”.
- Label the current step of a running tool call or reasoning trace.
- A lightweight inline loading label where a spinner would be too mechanical.

## When not to use

- Long paragraphs or body text — the sweep hurts legibility beyond a short phrase.
- Determinate progress (uploads, token budgets) — use a progress bar or context-meter.
- Streaming the model's answer itself — use streaming-text.
- A standalone animated dot/orb indicator — use thinking-indicator or agent-orb.

## Props

| Prop | Type | Default | Required | Description |
| --- | --- | --- | --- | --- |
| `children` | `React.ReactNode` | — | yes | The text to shimmer. Plain text reads best; inline elements are allowed. |
| `active` | `boolean` | `true` | no | Animate the sweep. Set false when the work finishes to settle into muted text. |
| `duration` | `number` | `2` | no | Seconds per sweep. Keep between 1.5 (urgent) and 3 (calm). |
| `spread` | `number` | `30` | no | Width of the bright band as a % of the text width (clamped 5–80). |
| `as` | `"span" \| "p" \| "div" \| "strong" \| "em"` | `"span"` | no | Element to render. |

Native attributes of the root element, `className` and `ref` are passed through.

## Anatomy

- **ShimmerText** (`data-slot="shimmer-text"`) — A single inline element; `data-active` reflects the `active` prop.

## Accessibility

- The text stays real text: screen readers read it normally; the animation is purely visual.
- Not a live region. Wrap the label in an element with role="status" (or aria-live="polite") if the change of state should be announced.
- Colors come from fg/fg-subtle tokens so contrast holds in light and dark mode.
- Reduced motion: The sweep is removed; the text renders as static muted text.

## Notes for agents

- Server-component safe: no hooks, pure CSS animation. No "use client" needed to render it.
- Flip `active` to false instead of unmounting when work completes, so layout does not jump.
- Keep the label under ~6 words and end with an ellipsis (…) while active.

## Examples

### Thinking label (minimal)

The smallest correct usage.

```tsx
import { ShimmerText } from "@kura-ui/react/shimmer-text";

export function ShimmerTextMinimal() {
  return <ShimmerText>Thinking…</ShimmerText>;
}
```

### Tuned sweep (full)

Every prop: element, speed, band width, and toggling `active` when work completes.

```tsx
"use client";

import * as React from "react";
import { Button } from "@kura-ui/react/button";
import { ShimmerText } from "@kura-ui/react/shimmer-text";

export function ShimmerTextFull() {
  const [active, setActive] = React.useState(true);
  return (
    <div className="flex flex-col items-center gap-4">
      <ShimmerText as="p" active={active} duration={2.4} spread={24} className="text-lg">
        {active ? "Searching 24 sources…" : "Searched 24 sources"}
      </ShimmerText>
      <Button variant="secondary" size="sm" onClick={() => setActive((a) => !a)}>
        {active ? "Finish" : "Restart"}
      </Button>
    </div>
  );
}
```

### Agent step with status region (composition)

A tool-call style row announcing progress politely to screen readers.

```tsx
"use client";

import { Check } from "lucide-react";
import * as React from "react";
import { ShimmerText } from "@kura-ui/react/shimmer-text";

export function ShimmerTextInToolStep() {
  const [done, setDone] = React.useState(false);
  React.useEffect(() => {
    const id = setTimeout(() => setDone(true), 3200);
    return () => clearTimeout(id);
  }, []);
  return (
    <div className="flex w-72 items-center gap-2.5 rounded-kura-lg bg-kura-surface px-3 py-2.5 text-sm shadow-kura-sm">
      <span className="flex size-5 items-center justify-center rounded-full bg-kura-accent-subtle text-kura-accent-text">
        {done ? (
          <Check className="size-3" />
        ) : (
          <span className="size-1.5 animate-kura-pulse rounded-full bg-current" />
        )}
      </span>
      <span role="status" aria-live="polite">
        <ShimmerText active={!done}>
          {done ? "Read package.json" : "Reading package.json…"}
        </ShimmerText>
      </span>
    </div>
  );
}
```

## Dependencies

- npm: none
- Kura registry items: `kura-theme`, `utils`
- Related: `thinking-indicator`, `reasoning`, `tool-call`, `streaming-text`
