tw-shimmer

Tailwind CSS v4 plugin for shimmer effects.

tw-shimmer is a zero-dependency Tailwind CSS v4 plugin that provides polished shimmer animations for both text and skeleton loaders. It uses sine-eased gradients with 17 carefully calculated stops and OKLCH color mixing for smooth, banding-free effects.

  • CSS-only — No JavaScript runtime, pure Tailwind utilities
  • Text + Background — Shimmer text or skeleton placeholders
  • Auto-sizing — CSS container queries size the animation track automatically
  • Customizable — Speed, spread, angle, color, and timing

See the interactive demo for live examples.

Installation

npm install tw-shimmer

Add to your CSS:

app/globals.css
@import "tailwindcss";
@import "tw-shimmer";

Quick Start

Text Shimmer

<span class="shimmer text-foreground/60">Loading...</span>

Info

Set a semi-transparent text color (e.g., text-foreground/40) for the shimmer highlight to be visible. Text shimmer keeps one text node and uses a compositor highlight when -webkit-mask-clip: text is supported; other browsers use the gradient fallback.

Skeleton Loader

<div class="shimmer shimmer-bg bg-muted h-4 w-48 rounded" />

Skeleton Card with Auto-Sizing

<div class="shimmer-container flex gap-3">
  <div class="shimmer shimmer-bg bg-muted size-12 rounded-full" />
  <div class="flex-1 space-y-2">
    <div class="shimmer shimmer-bg bg-muted h-4 w-1/4 rounded" />
    <div class="shimmer shimmer-bg bg-muted h-4 w-full rounded" />
    <div class="shimmer shimmer-bg bg-muted h-4 w-4/5 rounded" />
  </div>
</div>

API Reference

Core Utilities

shimmer

Base utility for text shimmer. It keeps one text node and, when -webkit-mask-clip: text is supported, masks the host and animates an additive highlight band on the compositor. The fallback animates the text gradient.

The compositor band is additive and defaults to white. --shimmer-color, shimmer-color-*, and shimmer-invert select its color. The two paths match on white and dark surfaces; tinted surfaces can differ. Because the host is masked, keep non-text descendants such as icons outside it. Selection backgrounds are clipped to the glyphs on the compositor path.

Both paths hold still under prefers-reduced-motion: reduce, leaving the label in its plain text color. shimmer-bg keeps animating.

shimmer-bg

Background shimmer for skeleton loaders. Requires the base shimmer class, which paints and animates the gradient, and a base bg-* class.

<div class="shimmer shimmer-bg bg-muted h-4 w-64 rounded" />

shimmer-container

CSS-only auto-sizing helper using container queries. It uses the container width as the animation track width. Because it establishes inline-size containment only, the height term for angled gradients uses the nearest block-size query container when one exists and otherwise falls back to the small viewport height; half the container width and 200px remain its minimums.

<div class="shimmer-container">
  <div class="shimmer shimmer-bg bg-muted h-4 w-full rounded" />
</div>

Warning

shimmer-container sets container-type: inline-size, which prevents shrink-to-fit sizing. Not recommended for text-only containers.

Customization Utilities

UtilityDefault (text)Default (bg)Description
shimmer-speed-{n}2001000Animation speed in px/s
--shimmer-track-width200px200pxTrack width for timing
shimmer-spread-{n}calc(4ch + 80px)480pxShimmer highlight width
shimmer-color-{color}autoautoHighlight color (Tailwind palette)
shimmer-angle-{deg}1515Sweep angle in degrees
shimmer-duration-{ms}autoautoFixed animation duration
shimmer-repeat-delay-{ms}10020Pause between cycles
shimmer-invertUse a contrasting highlight color

All utilities are inheritable — set on a parent to affect all shimmer children.

Speed and Track Width

Speed controls how fast the shimmer moves in pixels per second. --shimmer-track-width tells the animation how far the highlight travels for timing calculations; shimmer-container sets it from the container.

<span class="shimmer shimmer-speed-200 [--shimmer-track-width:400px] text-foreground/40">
  Fast, wide shimmer
</span>

Color

Use any Tailwind color with optional opacity:

<span class="shimmer shimmer-color-blue-500 text-blue-500/40">
  Blue shimmer
</span>

<div class="shimmer shimmer-bg shimmer-color-blue-300/30 bg-muted h-4 rounded" />

Angle

Control the sweep angle. The default is 15deg.

<div class="shimmer-container shimmer-angle-15">
  <div class="shimmer shimmer-bg bg-muted h-4 w-full rounded" />
</div>

Warning

Avoid 90deg and 270deg, where tan() diverges and the gradient width becomes unbounded. Angles from 0deg to 75deg are safe. Negative angles are possible with an arbitrary property such as [--shimmer-angle:-15deg], but only shallow ones: when the magnitude of --shimmer-track-height * tan() exceeds the spread, the gradient width goes negative and the effect stops. At the default 200px track height that is around -30deg for text; inside a shimmer-container the track height can be larger, making the limit shallower.

Position Hints (Angled Shimmer)

For angled shimmers, set the unitless --shimmer-x and --shimmer-y position hints to sync elements:

<div class="shimmer-container shimmer-angle-15 flex gap-3">
  <div class="shimmer shimmer-bg [--shimmer-x:20] [--shimmer-y:20] bg-muted size-12 rounded-full" />
  <div class="flex-1 space-y-2">
    <div class="shimmer shimmer-bg [--shimmer-x:52] [--shimmer-y:0] bg-muted h-4 w-24 rounded" />
    <div class="shimmer shimmer-bg [--shimmer-x:52] [--shimmer-y:24] bg-muted h-4 w-full rounded" />
  </div>
</div>

Repeat Delay

Control the pause between animation cycles. The default is derived from speed: 100ms for text and 20ms for backgrounds.

<!-- Continuous shimmer, no pause -->
<span class="shimmer shimmer-repeat-delay-0 text-foreground/40">
  Always moving
</span>

<!-- Long pause between cycles -->
<span class="shimmer shimmer-repeat-delay-3000 text-foreground/40">
  Slow pulse
</span>

CSS Variables

All values can be set via CSS variables for dynamic control:

VariableDescription
--shimmer-speedSpeed in px/s
--shimmer-track-widthTrack width for timing
--shimmer-track-heightTrack height for sizing
--shimmer-spreadHighlight width
--shimmer-angleSweep angle
--shimmer-colorHighlight color
--shimmer-durationOverride duration (ms)
--shimmer-repeat-delayPause between cycles (ms)
--shimmer-xHorizontal position hint (unitless, px)
--shimmer-yVertical position hint (unitless, px)
<div
  style={
    { "--shimmer-track-width": `${containerWidth}px` } as React.CSSProperties
  }
>
  <div className="shimmer shimmer-bg bg-muted h-4 w-full rounded" />
</div>

Browser Support

Uses modern CSS features: @property, relative oklch(), color-mix(), tan(), independent translate, CSS masking, and CSS Container Queries. The compositor path is gated by -webkit-mask-clip: text; browsers that fail that gate keep the gradient fallback.

Supported: Chrome 119+, Firefox 128+, Safari 16.4+

Older browsers degrade gracefully. Below the floor the text shimmer drops its clip, gradient, and animation together, so the element renders as plain static text; shimmer-bg renders as a static block.