Skip to content

Text Shimmer

Text with a band of light sweeping across it, for a loading message or a quiet accent. The words stay real text: selectable and read as normal.

Motionv0.1.0experimentalWCAG 2.2 AAView spec

Optional, and kept apart.

Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.

Thinking…
import { TextShimmer } from "@rdloom/react";

export default function TextShimmerBasicExample() {
  return (
    <TextShimmer className="text-lg font-medium">Thinking…</TextShimmer>
  );
}

Installation

npx rdloom add text-shimmer

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/text-shimmer.json

Works, but without upgrade tracking, and you import the motion CSS yourself.

Usage

import { TextShimmer } from "@rdloom/react";

<TextShimmer className="text-lg font-medium">Thinking…</TextShimmer>

In a heading

Your report is being prepared

import { TextShimmer } from "@rdloom/react";

export default function TextShimmerInAHeadingExample() {
  return (
    <h3 className="text-2xl font-semibold">
      Your report is{" "}
      <TextShimmer baseColor="var(--rd-color-action-primary)" highlightColor="var(--rd-color-text-default)" duration={2.2}>
        being prepared
      </TextShimmer>
    </h3>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
childrenrequired

The text.

nodenone
duration

Seconds for one sweep.

number2.8
baseColor

The resting colour of the text, any CSS colour. Defaults to the muted text colour.

stringnone
highlightColor

The colour of the passing light, any CSS colour. Defaults to the main text colour.

stringnone
isPaused

Stops the animation. Moving content that lasts more than five seconds should be stoppable.

booleanfalse

Accessibility

Role text, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

Not interactive.

Screen readers announce

  • Read as ordinary text: the sweep is purely visual

What your code must do

  • Decoration only: the animated layers are hidden from assistive technology and never take focus
  • Stands still for visitors who ask for less motion (prefers-reduced-motion), and the effect can also be shown still with the rdm-still class
  • Both colours meet 4.5:1 against the page, so the text is readable at every point of the sweep
  • In forced-colors (high contrast) mode it is drawn in the system text colour with no effect
  • Does not flash: nothing changes more than three times in a second (WCAG 2.3.1)
  • Optional: it is a separate component, so projects that do not add it carry none of its code

Guidelines

Use it when

  • "Thinking…" and other loading messages
  • A short label that should feel alive

Avoid it when

  • Paragraphs of body text
  • Anything the user must read closely

Don't

  • Choosing two colours that are close in lightness, which makes the sweep invisible
  • Long passages

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-text-default
  • --rd-color-text-muted