An open API service indexing awesome lists of open source software.

https://github.com/numandev1/react-native-auto-shimmer

Auto generated shimmer loading for React Native / Expo
https://github.com/numandev1/react-native-auto-shimmer

expo react-native shimmer shimmer-android shimmer-animation shimmer-effect shimmer-loading

Last synced: 1 day ago
JSON representation

Auto generated shimmer loading for React Native / Expo

Awesome Lists containing this project

README

          

react-native-auto-shimmer

# React Native Auto Shimmer

### Stop hand-coding skeleton screens. Capture them from your real UI in one click.

[![npm version](https://img.shields.io/npm/v/react-native-auto-shimmer?color=6366f1&style=flat-square)](https://www.npmjs.com/package/react-native-auto-shimmer)
[![npm downloads](https://img.shields.io/npm/dm/react-native-auto-shimmer?color=059669&style=flat-square)](https://www.npmjs.com/package/react-native-auto-shimmer)
[![license](https://img.shields.io/npm/l/react-native-auto-shimmer?color=f59e0b&style=flat-square)](LICENSE)
[![React Native](https://img.shields.io/badge/React%20Native-%3E%3D0.68-61dafb?style=flat-square&logo=react)](https://reactnative.dev)
[![Expo](https://img.shields.io/badge/Expo-compatible-000?style=flat-square&logo=expo)](https://expo.dev)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square)](CONTRIBUTING.md)


**โญ If this saves you time, star the repo โ€” it takes 2 seconds and helps others find it.**


**Auto Pulse**
![pulse animation](media/simulator_with_pulse.gif)

**Auto Shimmer**
![shimmer animation](media/simulator_with_shimmer.gif)

**ShimmerOverlay**
![shimmer overlay effect](media/shimmer_overlay.gif)

**ShimmerPlaceholder**
![shimmer placeholder effect](media/shimmer_placeholder.gif)

Auto-captured from live UI
Auto-captured from live UI
Wrap any element
Fixed-size box

---

## The problem with skeleton screens today

Every React Native developer has been here:

```
๐Ÿคฆ "OK let me eyeball this card width... maybe 340px? Let me check on a different device..."
๐Ÿคฆ "The design changed again. Rebuild all the skeletons."
๐Ÿคฆ "Why does the skeleton not match the real layout on iPad?"
```

Building skeletons by hand is a time sink that should not exist. **react-native-auto-shimmer fixes this permanently.**

---

## How it works (30 seconds)

![Skeleton Inspector live capture](media/simulator_with_debugger.png)

*The Skeleton Inspector DevTools panel โ€” click Capture, get pixel-perfect skeletons instantly*

1. **Wrap** your component with ``
2. **Open** Skeleton Inspector in React Native DevTools
3. **Click Capture** โ€” real skeleton geometry is measured from the live fiber tree
4. **Delete** any unwanted pieces with the trash icon
5. **Save** โ€” a TypeScript file lands in `src/skeletons/` with a ready-to-paste code snippet
6. **Done** โ€” skeletons that match your UI exactly, on every device size

No guessing. No hardcoding. No drift.

---

## Three ways to use it

| | **Auto Shimmer** โญ Primary | **ShimmerOverlay** | **ShimmerPlaceholder** |
|---|---|---|---|
| **What** | Skeleton from live UI, zero manual work | Shimmer sweep over any element | Fixed-size shimmer box |
| **Layout** | Measured from real component | Wraps whatever you give it | You set `width` / `height` |
| **Responsive** | โœ… % widths, any screen | โ€” | โŒ Fixed px |
| **Setup** | One-time DevTools capture | Wrap & go | Drop in |
| **Use when** | Building loading screens | Shine/highlight effects | Simple one-off placeholders |

> **Start with Auto Shimmer.** Drop to the manual options only for quick one-offs or pure visual effects.

---

## Installation

```sh
npm install react-native-auto-shimmer
# or
yarn add react-native-auto-shimmer
```

> No native modules ยท No `pod install` ยท No Gradle changes ยท Works with Expo ยท React Native โ‰ฅ 0.68

---

# Auto Shimmer โญ

> The main event. Capture pixel-perfect skeleton layouts directly from your running UI โ€” no measurement, no guesswork.

## Before vs. After

```diff
- // ๐Ÿ˜ฉ The old way
- const SkeletonCard = () => (
-
-
-
- // ... and redo all of this every time the design changes
- );

+ // โœ… With react-native-auto-shimmer
+
+
+
```

## Setup

### 1 โ€” Install dev dependencies

```sh
yarn add -D @rozenite/metro react-native-auto-shimmer-rozenite-plugin
```

### 2 โ€” Configure Metro

```js
// metro.config.js
const { getDefaultConfig } = require('@expo/metro-config'); // or require('metro-config')
const { withRozenite } = require('@rozenite/metro');
const { withSkeletonInspector } = require('react-native-auto-shimmer-rozenite-plugin/metro');

let config = getDefaultConfig(__dirname);
config = withSkeletonInspector(config);

if (process.env.WITH_ROZENITE === 'true') {
config = withRozenite(config, { enabled: true });
}

module.exports = config;
```

### 3 โ€” Register the plugin

```tsx
// App.tsx or index.js
if (__DEV__) {
const { getRozeniteDevToolsClient } = require('@rozenite/plugin-bridge');
const setupPlugin = require('react-native-auto-shimmer-rozenite-plugin').default;

getRozeniteDevToolsClient('react-native-auto-shimmer')
.then((client) => setupPlugin(client))
.catch((e) => console.warn('[SkeletonInspector] Could not connect:', e?.message));
}
```

### 4 โ€” Wrap your component

```tsx
import { Skeleton, SkeletonCapture } from 'react-native-auto-shimmer';

export function ArticleScreen() {
const [loading, setLoading] = useState(true);

return (

{/* Place SkeletonCapture inside Skeleton so it measures visible content */}




);
}
```

### 5 โ€” Run the inspector

```sh
WITH_ROZENITE=true yarn start
```

Open your app โ†’ **React Native DevTools** โ†’ **Rozenite tab** โ†’ **Skeleton Inspector**

### 6 โ€” Capture, review, save

1. Navigate to your screen (make sure `loading` is `false` โ€” real content must be visible)
2. Click **โฌก Capture** โ€” skeletons are measured from the live layout
3. Delete unwanted pieces with the trash icon
4. Click **โ†“ Save .ts (Responsive)** โ€” file lands in `src/skeletons/`
5. Copy the ready-to-paste snippet from the panel

![Skeleton Inspector โ€” captured skeletons](docs/captured-skeletons.png)

> **Save .ts vs Save .json**
> `.ts` stores `x`/`w` as percentages โ†’ scales to every screen size. **Use this.**
> `.json` stores raw dp values โ†’ fastest for a quick snapshot on a single device.

---

## Using your skeletons

### Import directly (recommended)

```tsx
import cardSkeletons from './skeletons/card.skeletons'; // .ts โ€” responsive

```

### Register once, use everywhere (optional)

```ts
// App.tsx
import { registerSkeletons } from 'react-native-auto-shimmer';
import cardSkeletons from './skeletons/card.skeletons';
import profileSkeletons from './skeletons/profile.skeletons';

registerSkeletons({ card: cardSkeletons, profile: profileSkeletons });
```

```tsx
// Any screen โ€” no import needed

```

### Global config

```ts
import { configureSkeleton } from 'react-native-auto-shimmer';

configureSkeleton({
animate: 'shimmer', // 'pulse' | 'shimmer' | 'solid'
color: 'rgba(0,0,0,0.06)',
darkColor: 'rgba(255,255,255,0.08)',
});
```

---

## API โ€” ``

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `loading` | `boolean` | **required** | Show skeleton (`true`) or real content (`false`) |
| `children` | `ReactNode` | **required** | Your component |
| `name` | `string` | โ€” | Registry key set via `registerSkeletons` |
| `initialSkeletons` | `SkeletonResult \| ResponsiveSkeletons` | โ€” | Direct skeleton data โ€” takes priority over `name` |
| `animate` | `'pulse' \| 'shimmer' \| 'solid' \| boolean` | `'pulse'` | Animation style |
| `color` | `string` | `'rgba(0,0,0,0.08)'` | Skeleton colour (light mode) |
| `darkColor` | `string` | `'rgba(255,255,255,0.06)'` | Skeleton colour (dark mode) |
| `style` | `ViewStyle` | โ€” | Wrapper style โ€” set `width`, `height`, `borderRadius` here |
| `fallback` | `ReactNode` | โ€” | Shown when `loading=true` but no skeletons exist yet |

## API โ€” `` *(dev only)*

No-op in production โ€” tree-shakes to a plain `` with zero overhead.

| Prop | Type | Description |
|------|------|-------------|
| `name` | `string` | Identifier shown in Skeleton Inspector |
| `children` | `ReactNode` | The component to measure |
| `style` | `ViewStyle` | Forwarded to the wrapper View |

---

## Animation styles

| Value | Behaviour |
|-------|-----------|
| `'pulse'` | Opacity 100% โ†’ 45% loop โ€” runs on the **native UI thread** |
| `'shimmer'` | Bright highlight sweeps left-to-right across all pieces |
| `'solid'` | Static โ€” no animation (good for Reduce Motion) |

---

## Responsive skeletons & dark mode

**Multi-breakpoint:** Capture at each device width. The file stores one entry per breakpoint; `` picks the nearest match automatically.

**Dark mode:** `` reads `useColorScheme()` internally โ€” pass `color` and `darkColor` or set them once with `configureSkeleton`.

---

# Manual Options

> Quick placeholders without the capture workflow.

---

## ShimmerOverlay

Adds a shimmer sweep to **any** existing element โ€” real content, buttons, images, cards. Not a loading placeholder; a visual highlight effect.

```tsx
import { ShimmerOverlay } from 'react-native-auto-shimmer';

// Basic

// Premium button highlight

// Staggered list
{items.map((item, i) => (



))}

// Programmatic control
const shimmerRef = useRef(null);

shimmerRef.current?.start()} />
```

### Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `active` | `boolean` | `true` | Whether the animation runs |
| `color` | `string` | `'rgba(255,255,255,0.8)'` | Shimmer band colour |
| `duration` | `number` | `1500` | One cycle in ms |
| `delay` | `number` | `400` | Pause between cycles |
| `initialDelay` | `number` | `0` | Delay before first cycle |
| `angle` | `number` | `20` | Band angle in degrees |
| `bandWidth` | `number` | `60` | Band width in px |
| `mode` | `'normal' \| 'expand' \| 'shrink'` | `'normal'` | Band size style |
| `direction` | `'left-to-right' \| 'right-to-left'` | `'left-to-right'` | Sweep direction |
| `iterations` | `number` | `-1` | Cycles (-1 = infinite) |
| `respectReduceMotion` | `boolean` | `true` | Pauses on system Reduce Motion |
| `pauseOnBackground` | `boolean` | `true` | Pauses when app backgrounds |
| `onAnimationComplete` | `() => void` | โ€” | Called when all iterations finish |

### Ref methods

```tsx
ref.current?.start(); // Start
ref.current?.stop(); // Stop
ref.current?.restart(); // Restart from beginning
ref.current?.isAnimating(); // โ†’ boolean
```

---

## ShimmerPlaceholder

A fixed-size shimmer box you size in code. Drop-in for [`react-native-shimmer-placeholder`](https://github.com/tomzaku/react-native-shimmer-placeholder) with **zero dependencies** โ€” no LinearGradient needed.

### Migrate in 2 lines

```diff
- import LinearGradient from 'react-native-linear-gradient';
- import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder';
- const ShimmerPlaceHolder = createShimmerPlaceholder(LinearGradient);

+ import { createShimmerPlaceholder } from 'react-native-auto-shimmer';
+ const ShimmerPlaceHolder = createShimmerPlaceholder();
```

### Usage

```tsx
import { ShimmerPlaceholder } from 'react-native-auto-shimmer';

// Text line

{title}

// Avatar circle

// Dark mode

{label}

```

### Full placeholder card

```tsx
function ArticleCardPlaceholder({ loaded }: { loaded: boolean }) {
return (






{title}


{excerpt}






{authorName}




);
}
```

### Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `width` | `number` | `200` | Width in px |
| `height` | `number` | `15` | Height in px |
| `visible` | `boolean` | `false` | `true` = show children, `false` = show shimmer |
| `shimmerColors` | `[string, string, string]` | `['#ebebeb','#d0d0d0','#ebebeb']` | Gradient colours |
| `isReversed` | `boolean` | `false` | Sweep right-to-left |
| `duration` | `number` | `1000` | One sweep in ms |
| `delay` | `number` | `0` | Delay before each sweep |
| `borderRadius` | `number` | `0` | Border radius |
| `style` | `StyleProp` | โ€” | Outer container style |
| `contentStyle` | `StyleProp` | โ€” | Children wrapper style |
| `shimmerStyle` | `StyleProp` | โ€” | Shimmer box style |

---

## FAQ

Do I need to keep <SkeletonCapture> in production?

No โ€” but you can safely leave it. In production (`__DEV__ === false`) it renders as a transparent `` with no bridge calls whatsoever.

The panel shows "No components found".

Navigate to the screen that mounts your ``. Components register on mount and deregister on unmount โ€” the panel reflects what's currently on screen.

<Skeleton> shows blank space instead of a skeleton.

No skeleton data has been passed yet. Use `fallback` while you complete the capture:

```tsx
}>

```

My component renders at different widths. Which do I capture?

Capture at every meaningful width. Each capture adds a breakpoint to the same file and `` picks the closest one at runtime.

Can I edit the skeleton data by hand?

Yes. `x`/`w` are % of container width, `y`/`h` are dp, `r` is border-radius in dp or `"50%"` for circles. Or just delete unwanted pieces in the inspector before saving.

Does it work with Expo?

Yes. No native modules. The Rozenite plugin uses Metro's `enhanceMiddleware` API, which Expo supports out of the box.

Does it work with the New Architecture (Fabric)?

Yes. `SkeletonCapture` detects the renderer at runtime and uses the correct measurement path for both Fabric and the legacy renderer.

Does it work with React Navigation / Expo Router?

Yes. `` registers on mount and cleans up on unmount โ€” no conflicts with any navigation library.

---

## Contributing

Bug fixes, features, and docs improvements are all welcome.

- [Development workflow](CONTRIBUTING.md#development-workflow)
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)

## Support the project

If this library saves you time, a star on GitHub goes a long way โ€” it helps other developers discover it.

**[โญ Star on GitHub](https://github.com/numandev1/react-native-auto-shimmer)**

Buy Me A Coffee

---

inspired by [boneyard](https://github.com/0xGF/boneyard)

## License

MIT ยฉ [Numan](https://github.com/numandev1)