npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-shimmer-craft

v1.0.0

Published

Lightweight, zero-dependency shimmer and auto-inference skeleton UI engine for React Native & Expo

Readme

react-native-shimmer-craft

npm version license CI PRs Welcome

react-native-shimmer-craft is a lightweight, zero-runtime-dependency shimmer and auto-inference skeleton UI engine for React Native, Expo, and React Native Web.

It automatically inspects your component tree to generate matching skeleton loading placeholders with near-zero layout shift, while also providing composable primitives for building custom skeleton layouts.


✨ Features

  • 🪄 Auto-Inference Mode: Automatically converts real React Native JSX trees into visually matched skeleton layouts.
  • 🧱 Explicit Primitives: Compose bespoke skeleton placeholders with ShimmerCraft.Text, ShimmerCraft.Circle, and ShimmerCraft.Rect.
  • Zero Runtime Dependencies: No react-native-reanimated, no native gradient modules, and zero native linking. Works out of the box in Expo Go and bare React Native.
  • 🚀 60fps Native Driver Animation: High-performance animated sweep running completely outside of React's state render loop.
  • 🔄 Synchronized Shimmer Clock: A single root animation coordinator powers 100+ skeleton items in a tree with minimal CPU & memory overhead.
  • 🧭 Multi-Directional Sweep: Supports left-to-right, right-to-left, top-to-bottom, and diagonal.
  • 🌗 Dark Mode & Palette Overrides: Automatically detects system appearance or allows manual overrides and custom color themes.
  • 🎯 Per-Element Overrides: Customize specific child nodes with shimmerType, shimmerWidth, and shimmerHeight.
  • Accessible & Reduced Motion: Automatically hides placeholder nodes from screen readers and respects system reduced motion settings.
  • 📱 100% Cross-Platform: iOS, Android, React Native Web, Expo, and React Native CLI.

📦 Installation

npm install react-native-shimmer-craft

or using yarn:

yarn add react-native-shimmer-craft

Peer Dependencies

Ensure you have react (>=17.0.0) and react-native (>=0.65.0) installed in your project.

Note: No native linking or Podfile changes are required!


🚀 Quick Start

Mode A: Auto-Inference Mode

Wrap any component tree with <ShimmerCraft isLoading={isLoading}>. When loading is active, the engine inspects the layout styles and element hierarchy to construct an aligned skeleton UI:

import React, { useState } from 'react';
import { View, Text, Image, StyleSheet } from 'react-native';
import ShimmerCraft from 'react-native-shimmer-craft';

export default function UserProfileCard() {
  const [isLoading, setIsLoading] = useState(true);

  return (
    <ShimmerCraft isLoading={isLoading} duration={1200}>
      <View style={styles.card}>
        <Image
          source={{ uri: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb' }}
          style={styles.avatar}
        />
        <View style={styles.content}>
          <Text style={styles.name}>Sophia Chen</Text>
          <Text style={styles.role}>Mobile Architect</Text>
        </View>
      </View>
    </ShimmerCraft>
  );
}

const styles = StyleSheet.create({
  card: { flexDirection: 'row', padding: 16, alignItems: 'center' },
  avatar: { width: 56, height: 56, borderRadius: 28 },
  content: { marginLeft: 12, flex: 1 },
  name: { fontSize: 16, fontWeight: '700' },
  role: { fontSize: 13, color: '#666', marginTop: 4 },
});

When isLoading={false}, your original component tree is rendered untouched.


Mode B: Explicit Primitives

Construct fine-tuned loading placeholders manually using compound primitives:

import React from 'react';
import { View } from 'react-native';
import ShimmerCraft from 'react-native-shimmer-craft';

export function CustomSkeleton() {
  return (
    <ShimmerCraft isLoading={true} direction="diagonal">
      <View style={{ padding: 16 }}>
        {/* Avatar */}
        <ShimmerCraft.Circle size={64} />

        {/* Text lines */}
        <View style={{ marginTop: 16 }}>
          <ShimmerCraft.Text width="75%" height={16} />
          <View style={{ height: 8 }} />
          <ShimmerCraft.Text lines={3} height={12} gap={6} lastLineWidth="50%" />
        </View>

        {/* Card or Banner */}
        <View style={{ marginTop: 16 }}>
          <ShimmerCraft.Rect width="100%" height={140} borderRadius={12} />
        </View>
      </View>
    </ShimmerCraft>
  );
}

You can also import primitives as named exports:

import { ShimmerText, ShimmerCircle, ShimmerRect } from 'react-native-shimmer-craft';

🛠️ Child Overrides in Auto-Inference

In Auto-Inference mode, you can override how specific elements are translated into skeletons:

<ShimmerCraft isLoading={isLoading}>
  <View style={styles.container}>
    {/* Force element to render as a circle skeleton */}
    <View shimmerType="circle" shimmerWidth={48} shimmerHeight={48} />

    {/* Force element to render as a text bar with specific width */}
    <View shimmerType="text" shimmerWidth="60%" />

    {/* Force element to render as a rectangle */}
    <View shimmerType="rect" shimmerHeight={120} />

    {/* Reserve layout dimensions without applying any shimmer animation */}
    <View shimmerType="none" style={{ width: 100, height: 40 }} />
  </View>
</ShimmerCraft>

Override Priority Order

  1. Explicit child shimmer props (shimmerType, shimmerWidth, shimmerHeight)
  2. Explicit style dimensions (width, height, borderRadius)
  3. Automatic element inference (<Text>, <Image>, <View>)
  4. Safe fallback defaults

🧭 Shimmer Directions

Support for 4 sweep directions:

<ShimmerCraft direction="left-to-right" /> {/* Default */}
<ShimmerCraft direction="right-to-left" />
<ShimmerCraft direction="top-to-bottom" />
<ShimmerCraft direction="diagonal" />

🌗 Dark Mode & Themes

By default, react-native-shimmer-craft detects the operating system color scheme using useColorScheme().

You can explicitly control the theme and configure custom palettes:

<ShimmerCraft
  isLoading={true}
  useDarkMode={true}
  shimmerColors={['#E5E7EB', '#F9FAFB', '#E5E7EB']}
  darkShimmerColors={['#1E293B', '#334155', '#1E293B']}
>
  <UserProfile />
</ShimmerCraft>

📖 API Reference

<ShimmerCraft /> Props

| Prop | Type | Default | Description | | :--- | :--- | :--- | :--- | | isLoading | boolean | true | When true, displays skeleton UI. When false, displays original children. | | children | ReactNode | — | Component tree to render or infer skeletons from. | | fallback | ReactNode | undefined | Custom skeleton component to render when isLoading=true (bypasses auto-inference). | | direction | 'left-to-right' \| 'right-to-left' \| 'top-to-bottom' \| 'diagonal' | 'left-to-right' | Direction of the shimmer animation sweep. | | duration | number | 1200 | Duration in milliseconds of one animation loop cycle. | | useDarkMode | boolean | undefined | Manual dark mode toggle. If omitted, uses system appearance. | | shimmerColors | string[] | ['#E0E0E0', '#F5F5F5', '#E0E0E0'] | Light mode color palette [base, highlight, base]. | | darkShimmerColors | string[] | ['#2A2A2A', '#3F3F3F', '#2A2A2A'] | Dark mode color palette [base, highlight, base]. | | autoBorderRadius | number | 6 | Default corner radius for auto-inferred skeleton shapes. | | style | StyleProp<ViewStyle> | undefined | Container style. | | testID | string | undefined | Test identifier. |


<ShimmerCraft.Text /> Props

| Prop | Type | Default | Description | | :--- | :--- | :--- | :--- | | width | number \| string | '100%' | Width of the text bar(s) (e.g. 200 or '75%'). | | height | number | 14 | Height of each text line. | | borderRadius| number | 4 | Corner radius of the text bar. | | lines | number | 1 | Number of lines to generate for multi-line text skeletons. | | gap | number | 8 | Spacing between lines when lines > 1. | | lastLineWidth | number \| string | '60%' | Width of the final line when lines > 1. | | style | StyleProp<ViewStyle> | undefined | Custom container style. |


<ShimmerCraft.Circle /> Props

| Prop | Type | Default | Description | | :--- | :--- | :--- | :--- | | size | number | 48 | Diameter of the circle (sets width, height, and borderRadius = size/2). | | width | number \| string | 48 | Explicit width override. | | height | number \| string | 48 | Explicit height override. | | style | StyleProp<ViewStyle> | undefined | Custom container style. |


<ShimmerCraft.Rect /> Props

| Prop | Type | Default | Description | | :--- | :--- | :--- | :--- | | width | number \| string | '100%' | Width of the rectangle. | | height | number \| string | 80 | Height of the rectangle. | | borderRadius| number | 6 | Corner radius. | | style | StyleProp<ViewStyle> | undefined | Custom container style. |


⚡ Performance & Architecture

  • Single Animation Clock: Rather than instantiating an independent Animated.Value and interval per node, <ShimmerCraft> shares an animation clock across all descendant nodes via React Context.
  • Zero Frame State Updates: The shimmer sweep relies entirely on Animated.timing with useNativeDriver: true (or standard web CSS translations on React Native Web). React renders zero times during the animation loop.
  • Memoized Tree Inspection: Component parsing is memoized during render cycles, ensuring fast 60fps performance even for large screens with 100+ skeleton items.

♿ Accessibility

  • All skeleton placeholders are automatically annotated with accessible={false}, accessibilityElementsHidden={true}, and importantForAccessibility="no-hide-descendants" to ensure screen readers do not read placeholder elements.
  • When isLoading={false}, your real content retains full accessibility.
  • Reduced Motion: Automatically integrates with React Native's AccessibilityInfo.isReduceMotionEnabled() to disable looping highlight translations when the user prefers reduced motion.

⚠️ Auto-Inference Limitations & Best Practices

React Native does not expose the rendered pixel layout dimensions of arbitrary custom components prior to measurement on screen.

How Auto-Inference Works

  • The parser inspects the JSX element tree, styles (StyleSheet.flatten), and explicit dimensions.
  • It preserves layout containers (flex, flexDirection, margin, padding, gap, borderRadius, etc.) while replacing content nodes (<Text>, <Image>, leaf <View>) with shimmer placeholders.

When to Use Child Overrides or Primitives

  • If you have an opaque custom component that doesn't expose inline style dimensions (e.g. <CustomIcon />), provide explicit dimensions or overrides:
    <CustomAvatar shimmerType="circle" shimmerWidth={56} shimmerHeight={56} />
  • For highly custom or irregular loading screens, use explicit primitives (ShimmerCraft.Text, Circle, Rect) or the fallback={<CustomSkeleton />} prop.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request or open an Issue.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/my-feature)
  3. Run tests and linting:
    npm test
    npm run lint
    npm run typecheck
  4. Commit your changes (git commit -m 'Add new feature')
  5. Push to the branch (git push origin feature/my-feature)
  6. Open a Pull Request

📄 License

MIT © 2026 Bhagwat018