LLM index: /llms.txt

Text Shimmer

An animated shimmer effect for loading and "in progress" feedback. TextShimmer renders a moving highlight across text and exposes controls for speed, spread, direction, contrast, and pause between passes.

Thinking through your request...
"use client";

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

const TextShimmerDefault = () => {
  return (
    <div className="flex min-h-24 w-full items-center justify-center">
      <TextShimmer className="text-sm leading-6">
        Thinking through your request...
      </TextShimmer>
    </div>
  );
};

export default TextShimmerDefault;

Installation

npx shadcn@latest add @nexus-ui/text-shimmer
pnpm dlx shadcn@latest add @nexus-ui/text-shimmer
yarn dlx shadcn@latest add @nexus-ui/text-shimmer
bunx shadcn@latest add @nexus-ui/text-shimmer

Copy and paste the following code into your project.

components/nexus-ui/text-shimmer.tsx
import * as React from "react";

import { cn } from "@/lib/utils";

export type TextShimmerProps = Omit<
  React.HTMLAttributes<HTMLElement>,
  "color"
> & {
  as?: React.ElementType;
  /**
   * Duration in seconds.
   * @default 1
   */
  duration?: number;
  /**
   * Spread around center in percent points.
   * @default 20
   */
  spread?: number;
  /**
   * Beam angle in degrees.
   * @default 0
   */
  angle?: number;
  /**
   * Override highlight color.
   */
  color?: string;
  /**
   * Invert shimmer contrast.
   * @default false
   */
  invert?: boolean;
  /**
   * Invert shimmer contrast in light theme only.
   * @default false
   */
  invertLight?: boolean;
  /**
   * Invert shimmer contrast in dark theme only.
   * @default false
   */
  invertDark?: boolean;
  /**
   * Delay before the next shimmer pass in seconds.
   * @default 0
   */
  repeatDelay?: number;
  /**
   * Disable shimmer animation and render plain text.
   * @default false
   */
  disableShimmer?: boolean;
};

export function TextShimmer({
  as: Comp = "span",
  className,
  style,
  duration = 1,
  repeatDelay = 0,
  spread = 20,
  angle = 0,
  color,
  invert = false,
  invertLight = false,
  invertDark = false,
  disableShimmer = false,
  children,
  ...props
}: TextShimmerProps) {
  const id = React.useId();
  const boundedSpread = Math.min(Math.max(spread, 5), 45);
  const activeDuration = Math.max(duration, 0);
  const pauseDuration = Math.max(repeatDelay, 0);
  const totalDuration = Math.max(activeDuration + pauseDuration, 0.001);
  const movePercent = (activeDuration / totalDuration) * 100;
  const keyframeName = React.useMemo(
    () => `nx-text-shimmer-${id.replace(/[^a-zA-Z0-9_-]/g, "")}`,
    [id],
  );
  const start = 50 - boundedSpread;
  const end = 50 + boundedSpread;
  const edge = "currentColor";
  const brightBeam =
    color ??
    "oklch(from currentColor max(0.8, calc(l + 0.4)) c h / calc(alpha + 0.35))";
  const dimBeam =
    color ??
    "oklch(from currentColor min(calc(l - 0.4), 0.2) c h / calc(alpha + 0.4))";
  const lightBeam = invert || invertLight ? dimBeam : brightBeam;
  const darkBeam = invert || invertDark ? dimBeam : brightBeam;
  const keyframes = `@keyframes ${keyframeName} {
    0% { background-position: 100% 50%; }
    ${movePercent}% { background-position: -60% 50%; }
    100% { background-position: -100% 50%; }
  }
  [data-nx-text-shimmer="${keyframeName}"] {
    --nx-text-shimmer-beam: var(--nx-text-shimmer-beam-light);
  }
  .dark [data-nx-text-shimmer="${keyframeName}"],
  [data-theme="dark"] [data-nx-text-shimmer="${keyframeName}"] {
    --nx-text-shimmer-beam: var(--nx-text-shimmer-beam-dark);
  }`;
  const shimmerVariables = disableShimmer
    ? {}
    : ({
        "--nx-text-shimmer-beam-light": lightBeam,
        "--nx-text-shimmer-beam-dark": darkBeam,
      } as React.CSSProperties);
  const shimmerStyle: React.CSSProperties = disableShimmer
    ? {}
    : {
        backgroundImage: `linear-gradient(${90 + angle}deg, ${edge} ${start}%, var(--nx-text-shimmer-beam) 50%, ${edge} ${end}%)`,
        animation: `${keyframeName} ${totalDuration}s linear infinite`,
        WebkitTextFillColor: "transparent",
      };

  return (
    <>
      {!disableShimmer ? <style>{keyframes}</style> : null}
      <Comp
        data-nx-text-shimmer={keyframeName}
        className={cn(
          !disableShimmer && "bg-size-[200%_auto] bg-clip-text",
          className,
        )}
        style={{
          ...shimmerVariables,
          ...shimmerStyle,
          ...style,
        } as React.CSSProperties}
        {...props}
      >
        {children}
      </Comp>
    </>
  );
}

Update import paths to match your project setup.

Usage

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";
<TextShimmer> Running tool calls... </TextShimmer>

Examples

With Repeat Delay

Use repeatDelay to create a pause between shimmer passes:

Generating response...
"use client";

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

const TextShimmerRepeatDelay = () => {
  return (
    <div className="flex min-h-24 w-full items-center justify-center">
      <TextShimmer className="text-sm leading-6" repeatDelay={2}>
        Generating response...
      </TextShimmer>
    </div>
  );
};

export default TextShimmerRepeatDelay;

Angled Shimmer

Tune beam geometry with spread and angle:

Re-ranking search results
"use client";

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

const TextShimmerAngled = () => {
  return (
    <div className="flex min-h-24 w-full items-center justify-center">
      <TextShimmer className="text-sm leading-6" spread={5} angle={45}>
        Re-ranking search results
      </TextShimmer>
    </div>
  );
};

export default TextShimmerAngled;

Inverted Contrast

Use invert for lower-luminance emphasis (often better on lighter text):

Processing tool output...
"use client";

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

const TextShimmerInverted = () => {
  return (
    <div className="flex min-h-24 w-full items-center justify-center">
      <TextShimmer className="text-sm leading-6" invert>
        Processing tool output...
      </TextShimmer>
    </div>
  );
};

export default TextShimmerInverted;

As Custom Element

Render another element type with as:

Compiling component registry

"use client";

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

const TextShimmerAsParagraph = () => {
  return (
    <div className="flex min-h-24 w-full items-center justify-center px-6">
      <TextShimmer
        as="p"
        className="max-w-md text-center text-sm leading-6"
      >
        Compiling component registry
      </TextShimmer>
    </div>
  );
};

export default TextShimmerAsParagraph;

Custom Highlight Color

Use color to override the highlight beam for accent-driven states:

Syncing vector index
"use client";

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

const TextShimmerCustomColor = () => {
  return (
    <div className="flex min-h-24 w-full items-center justify-center">
      <TextShimmer
        className="text-sm leading-6"
        color="oklch(0.78 0.12 255)"
      >
        Syncing vector index
      </TextShimmer>
    </div>
  );
};

export default TextShimmerCustomColor;

Slow Sweep

Increase duration for a calmer motion profile:

Analyzing conversation context
"use client";

import { TextShimmer } from "@/components/nexus-ui/text-shimmer";

const TextShimmerSlowSweep = () => {
  return (
    <div className="flex min-h-24 w-full items-center justify-center">
      <TextShimmer className="text-sm leading-6" duration={5.5}>
        Analyzing conversation context
      </TextShimmer>
    </div>
  );
};

export default TextShimmerSlowSweep;

API Reference

TextShimmer

Animated text wrapper component. Uses a generated keyframe name per instance to avoid collisions and applies shimmer via a gradient background clipped to text.

Prop

Type

View as markdown Edit on GitHub