# tw-shimmer
URL: /docs/utilities/tw-shimmer

Tailwind CSS v4 plugin for shimmer effects.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

`tw-shimmer` is a zero-dependency Tailwind CSS v4 plugin that provides shimmer animations for text and skeleton loaders. It uses sine-eased gradients with 17 stops and OKLCH color mixing to avoid banding.

- **CSS-only**: Tailwind utilities with no JavaScript runtime
- **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](/tw-shimmer) for live examples.

## Installation

Choose one:

**npm**

```
npm install tw-shimmer
```

**pnpm**

```
pnpm add tw-shimmer
```

**yarn**

```
yarn add tw-shimmer
```

Add to your 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>
```

> [!warn]
>
> `shimmer-container` sets `container-type: inline-size`, which prevents shrink-to-fit sizing. Not recommended for text-only containers.

### Customization Utilities

| Utility                     | Default (text)     | Default (bg) | Description                        |
| --------------------------- | ------------------ | ------------ | ---------------------------------- |
| `shimmer-speed-{n}`         | `200`              | `1000`       | Animation speed in px/s            |
| `--shimmer-track-width`     | `200px`            | `200px`      | Track width for timing             |
| `shimmer-spread-{n}`        | `calc(4ch + 80px)` | `480px`      | Shimmer highlight width            |
| `shimmer-color-{color}`     | auto               | auto         | Highlight color (Tailwind palette) |
| `shimmer-angle-{deg}`       | `15`               | `15`         | Sweep angle in degrees             |
| `shimmer-duration-{ms}`     | auto               | auto         | Fixed animation duration           |
| `shimmer-repeat-delay-{ms}` | `100`              | `20`         | Pause between cycles               |
| `shimmer-invert`            | —                  | —            | Use a contrasting highlight color  |

All utilities are inheritable: set one 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>
```

> [!warn]
>
> 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:

| Variable                 | Description                             |
| ------------------------ | --------------------------------------- |
| `--shimmer-speed`        | Speed in px/s                           |
| `--shimmer-track-width`  | Track width for timing                  |
| `--shimmer-track-height` | Track height for sizing                 |
| `--shimmer-spread`       | Highlight width                         |
| `--shimmer-angle`        | Sweep angle                             |
| `--shimmer-color`        | Highlight color                         |
| `--shimmer-duration`     | Override duration (ms)                  |
| `--shimmer-repeat-delay` | Pause between cycles (ms)               |
| `--shimmer-x`            | Horizontal position hint (unitless, px) |
| `--shimmer-y`            | Vertical 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.