Shimmer
Animated highlight sweeping across content.
A highlight that sweeps through text and content, for loading, thinking and streaming states.
The content is used as a mask and a gradient band is swept behind it on the UI thread, so the highlight is clipped to the glyph shapes — the letters themselves catch the light rather than sitting under a passing overlay.
Installation
Shimmer ships with the library — no separate install.
import { Shimmer, Skeleton } from 'panelui-native';Or copy the source into your project, to own and edit it:
npx panelui-cli@latest add shimmerUsage
<Shimmer>Thinking…</Shimmer>
<Shimmer duration={1400} textClassName="text-lg font-medium">
Generating response…
</Shimmer>
// Mask arbitrary content instead of a string.
<Shimmer as="view" className="w-full gap-2">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-full" />
</Shimmer>Examples
A thinking indicator
The default. The sweep is clipped to the glyphs, so the letters catch the light instead of sitting under a passing band.
<Shimmer>Thinking…</Shimmer>
<Shimmer duration={1400} textClassName="text-lg font-medium">
Generating response…
</Shimmer>Masking a subtree
as="view" masks the sweep to whatever you pass instead of to a string.
<Shimmer as="view" className="w-full gap-2">
<Skeleton className="h-4 w-3/4" />
<Skeleton className="h-4 w-full" />
<Skeleton className="h-4 w-1/2" />
</Shimmer>Tuning the sweep
{/* Reverses on each pass instead of restarting from the left. */}
<Shimmer mode="ping-pong" duration={1600}>Ping-pong</Shimmer>
{/* Right to left. */}
<Shimmer reverse>Reversed</Shimmer>
{/* A wider, slower band. */}
<Shimmer spread={4} duration={2600}>Slow and broad</Shimmer>
{/* One pass, then stop. */}
<Shimmer once>Sweeps once</Shimmer>Custom colours
Both default to theme tokens, so you only need these on a surface the tokens do not suit.
<Shimmer baseColor="#3f3f46" shimmerColor="#fafafa">
Neutral on dark
</Shimmer>Turning it off
Renders the content statically in baseColor. Useful for stopping the sweep the moment a stream finishes, without swapping components.
<Shimmer enabled={isStreaming}>{status}</Shimmer>API Reference
Shimmer
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
as | 'text' | 'view' | 'text' | text renders children as a single styled string and masks the sweep to the glyphs. view masks the sweep to whatever subtree you pass. |
duration | number | 2000 | Milliseconds for one sweep. |
spread | number | 2 | Width of the highlight band, as a multiple of the content width. |
baseColor | string | — | Colour of the content at rest. Defaults to the theme's muted foreground. |
shimmerColor | string | — | Colour at the centre of the sweep. Defaults to the theme's foreground. |
mode | 'loop' | 'ping-pong' | 'loop' | loop restarts from the left; ping-pong reverses on each pass. |
once | boolean | false | Sweep once instead of repeating. |
reverse | boolean | false | Sweep right-to-left. |
enabled | boolean | true | Set false to render the content statically without animating. |
textClassName | string | — | Extra classes for the text when as="text". |
textStyle | StyleProp<TextStyle> | — | Extra styles for the text when as="text". |
color | string | — | Deprecated. Use shimmerColor. |
intensity | number | — | Peak opacity of the highlight. Deprecated. Set shimmerColor to a colour with the alpha you want. |
Every part also accepts the underlying React Native props (ViewProps or TextProps) and a className for Tailwind utilities.
Notes
The sweep runs entirely on the UI thread and never re-renders React while animating.
It stops when the OS reduce-motion setting is on, and when enabled is false — in both cases the content renders statically in baseColor.
baseColor and shimmerColor default to the theme's muted-foreground and foreground tokens, so the effect reads correctly on any surface without configuration. color and intensity still work but are deprecated in favour of the two colour props.