DEV Community

Cover image for react-native-modern-shimmer : The Simplest Shimmer Skeleton Loader for React Native — Zero Dependencies, Auto Dark Mode.
Abu Hasnat Nobin
Abu Hasnat Nobin

Posted on

react-native-modern-shimmer : The Simplest Shimmer Skeleton Loader for React Native — Zero Dependencies, Auto Dark Mode.

Every React Native app needs a loading state. And every developer eventually ends up writing the same boilerplate — a bunch of gray View components with hardcoded sizes, trying to approximate what the real UI will look like.

I got tired of doing that on every project. So I built react-native-modern-shimmer — a lightweight, zero-dependency shimmer skeleton loader that works beautifully out of the box.


What it looks like

Android iOS
Android Light iOS Light
Android Dark iOS Dark

Smooth, professional, and it automatically switches between light and dark mode — no extra props needed.


The problem with existing solutions

Most shimmer libraries for React Native have at least one of these problems:

  • They require expo-linear-gradient or react-native-linear-gradient — which means native linking, which means it doesn't work in Expo Go
  • They don't support dark mode at all
  • They have no TypeScript types
  • They're abandoned and unmaintained

react-native-modern-shimmer solves all of these.


Installation

# npm
npm install react-native-modern-shimmer

# yarn
yarn add react-native-modern-shimmer

# expo
npx expo install react-native-modern-shimmer
Enter fullscreen mode Exit fullscreen mode

No native modules. No linking. No extra packages. It works in Expo Go right out of the box.


Basic usage

import Shimmer from 'react-native-modern-shimmer';

export default function MyScreen() {
  return (
    <View style={{ padding: 16, gap: 12 }}>
      <Shimmer width={200} height={16} />
      <Shimmer width="80%" height={16} />
      <Shimmer width="60%" height={16} />
    </View>
  );
}
Enter fullscreen mode Exit fullscreen mode

That's it. No theme provider. No context. No configuration. It reads the system color scheme automatically using React Native's useColorScheme hook and updates instantly when the user switches themes.


Real-world examples

Card skeleton

<View style={{ gap: 12 }}>
  <Shimmer width="100%" height={180} borderRadius={16} />
  <Shimmer width="70%" height={16} borderRadius={6} />
  <Shimmer width="50%" height={13} borderRadius={6} />
</View>
Enter fullscreen mode Exit fullscreen mode

Avatar + name

<View style={{ flexDirection: 'row', alignItems: 'center', gap: 12 }}>
  <Shimmer width={48} height={48} borderRadius={24} />
  <View style={{ gap: 8 }}>
    <Shimmer width={140} height={14} borderRadius={4} />
    <Shimmer width={100} height={12} borderRadius={4} />
  </View>
</View>
Enter fullscreen mode Exit fullscreen mode

Product list rows

{Array.from({ length: 5 }).map((_, i) => (
  <View key={i} style={{ flexDirection: 'row', alignItems: 'center', gap: 12, marginBottom: 16 }}>
    <Shimmer width={52} height={52} borderRadius={12} />
    <View style={{ flex: 1, gap: 8 }}>
      <Shimmer width="80%" height={13} borderRadius={6} />
      <Shimmer width="55%" height={13} borderRadius={6} />
    </View>
  </View>
))}
Enter fullscreen mode Exit fullscreen mode

Full skeleton screen (with NativeWind / Uniwind)

import Shimmer from 'react-native-modern-shimmer';

export default function ShimmerScreen() {
  return (
    <SafeAreaView className="flex-1 bg-gray-100 dark:bg-zinc-950">
      <ScrollView className="flex-1" contentContainerClassName="px-5 py-6 gap-5">

        {/* Header */}
        <View className="flex-row items-center justify-between">
          <View className="flex-row items-center gap-3">
            <Shimmer width={46} height={46} borderRadius={23} />
            <View className="gap-2">
              <Shimmer width={80}  height={10} borderRadius={4} />
              <Shimmer width={130} height={15} borderRadius={5} />
            </View>
          </View>
          <Shimmer width={42} height={42} borderRadius={21} />
        </View>

        {/* Hero */}
        <Shimmer width="100%" height={200} borderRadius={20} speed={1200} />

        {/* Category chips */}
        <View className="flex-row gap-2 flex-wrap">
          {[64, 80, 72, 88].map((w, i) => (
            <Shimmer key={i} width={w} height={32} borderRadius={16} speed={900 + i * 60} />
          ))}
        </View>

        {/* List */}
        {[0, 1, 2, 3].map(i => (
          <View key={i} className="flex-row items-center gap-4 p-4 rounded-2xl bg-white dark:bg-zinc-900">
            <Shimmer width={54} height={54} borderRadius={16} speed={1000 + i * 70} />
            <View className="flex-1 gap-2">
              <Shimmer width="65%" height={13} borderRadius={4} />
              <Shimmer width="45%" height={10} borderRadius={3} />
            </View>
            <Shimmer width={40} height={20} borderRadius={5} />
          </View>
        ))}

      </ScrollView>
    </SafeAreaView>
  );
}
Enter fullscreen mode Exit fullscreen mode

All props

Prop Type Default Description
width number or string "100%" Accepts px number or "%" string
height number or string 16 Accepts px number or "%" string
borderRadius number 8 Corner radius
isDark boolean undefined Force dark or light. Omit to auto-detect
baseColor string theme default Override the background color
speed number 1000 Animation cycle in ms. Lower = faster
style StyleProp<ViewStyle> undefined Extra styles on the container

Why no LinearGradient?

The classic "sliding highlight" shimmer effect looks great but requires expo-linear-gradient or react-native-linear-gradient. Both need native linking or an Expo dev build — meaning they break in Expo Go and add setup friction.

This package achieves a professional shimmer using only React Native's built-in Animated API — a smooth opacity pulse that looks clean, feels native, and has zero setup cost. It runs on the native driver, so it's also battery friendly.


Links

If this saved you time, a ⭐ on GitHub goes a long way. And if you run into any issues or have feature requests, open an issue — contributions are very welcome.

Top comments (0)