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-loadly

v3.0.2

Published

⚛️ React Loadly - Modern React loader, spinner, and skeleton loader components. High-performance loading indicators for React apps with TypeScript support, Next.js compatibility, accessibility, and 30+ customizable animations. Perfect for dashboards, form

Readme

React Loadly — Reliable React Loading Experience Toolkit

React Loadly is a reliable React loading experience toolkit for modern loaders, SkeletonLoader, SkeletonGroupLoader, loading state hooks, accessibility, SSR support, and production-ready loading patterns. Built with TypeScript, optimized for Next.js and SSR, and designed with ARIA, reduced motion, and developer experience in mind.

Perfect for building React applications, dashboards, forms, SaaS tools, and data-driven UIs where loading states should feel deliberate, accessible, and consistent. AutoSkeletonLoader remains available as an experimental feature for backward compatibility and experimentation.

🔍 Search-friendly features: React loading spinner | React loader components | React skeleton loader | React loading indicator | Next.js loader | TypeScript loader | Accessible React loader | React loading animation

🏠 Home Page: https://mostafashadow1.github.io/react-loadly/

NPM Version Version Bundle Size License: MIT


What's New

  • New identity: Reliable React Loading Experience Toolkit.
  • SkeletonGroupLoader for coordinated production skeleton patterns.
  • New high-value loaders: GradientRingLoader, OrbitDotsLoader, SignalLoader, EqualizerLoader, and CardFlipLoader.
  • Production skeleton patterns for profile cards, product cards, articles, dashboards, sidebars, todos, tables, and forms.
  • Accessibility, SSR, fullscreen, and reduced-motion improvements across loaders.
  • AutoSkeletonLoader is clearly marked as Experimental and now has safer guarded inference for memo, forwardRef, custom hooks, and fallback presets.
  • AutoSkeleton Compiler roadmap documented.
  • The showcase app is now the source of truth for examples.

New Identity

React Loadly is no longer positioned as an automatic skeleton generator. It is a Reliable React Loading Experience Toolkit built around:

  • Modern React loaders
  • SkeletonLoader
  • SkeletonGroupLoader
  • Loading state hooks
  • Accessibility
  • SSR support
  • Reduced motion support
  • Production-ready loading patterns

Production Recommendation

For production-critical loading experiences, prefer explicit skeleton patterns with SkeletonLoader and SkeletonGroupLoader.

import { SkeletonGroupLoader, SkeletonLoader } from "react-loadly";
import "react-loadly/styles.css";

export function ProfileCardSkeleton() {
  return (
    <SkeletonGroupLoader shimmerSync stagger={0.08}>
      <SkeletonLoader variant="circular" width={56} height={56} />
      <SkeletonLoader variant="text" width="70%" height={16} />
      <SkeletonLoader variant="text" width="45%" height={12} />
      <SkeletonLoader variant="text" width="100%" height={12} />
    </SkeletonGroupLoader>
  );
}

These patterns are predictable, easy to design-review, compatible with complex React trees, and safer for production UI than runtime component introspection.


🚀 Getting Started

Installation

Install the package using your preferred package manager.

npm install react-loadly
# or
yarn add react-loadly
# or
pnpm i react-loadly

AutoSkeletonLoader Experimental

AutoSkeletonLoader is currently experimental.

The current implementation remains available for experimentation and backward compatibility. It uses best-effort structural inference by combining JSX traversal, safe presentational component inference, className heuristics, and smart fallback presets to generate realistic loading states.

It works best with native JSX, simple presentational components, className/style-based layouts, and visible component structure. It safely falls back for hook-heavy, context-heavy, Suspense-based, async, lazy, SSR-only, or opaque third-party components.

For production-critical loading experiences, React Loadly recommends SkeletonLoader and SkeletonGroupLoader.

Do not treat AutoSkeleton as pixel-perfect or guaranteed for every component tree.

AutoSkeletonLoader Safety Fixes

The guarded inference path now handles the most common wrapper and fallback cases more predictably:

  • React.memo, React.forwardRef, and nested memo(forwardRef(...)) components are unwrapped before structural inference.
  • Failed introspection is retried on the next render instead of permanently blacklisting the component type.
  • Custom hooks are detected through the React hook naming convention (use + capital letter), including third-party hooks such as Redux, SWR, Recoil, and Jotai-style hooks.
  • Fallback preset matching prefers the wrapper displayName before the unwrapped function name, which improves anonymous memo and forwardRef exports.

This means presentational memo/forwardRef components can produce a structural skeleton, while hook-heavy components skip execution and use the safest matching preset.

🧠 The Tech Behind the Magic

For simple presentational components, AutoSkeletonLoader uses guarded runtime JSX traversal to approximate your UI hierarchy without requiring manual skeleton markup.

  • Best-Effort Component Decoding: Supports native JSX and simple presentational components where they can be inspected safely.
  • Guarded Safe Render: safeRender skips risky components, including hook-heavy, async, lazy, and SSR paths, and falls back without crashing.
  • Class and Semantic Heuristics: Built-in analysis predicts dimensions for text, buttons, badges, images, cards, lists, forms, tables, dashboards, and common utility classes.
  • Animation Continuity (Stable Key Algorithm): v2.4.x introduces a stable keying algorithm that ensures shimmer animations don't "reset" or flicker when your component's state changes.
  • Smart Memoization: The VDOM analysis is extremely fast and memoized, occurring only when the component structure or configuration changes.

🚀 Full Example: The WorkerCard Molecule

In this example, we use a presentational card and let AutoSkeletonLoader infer a matching skeleton with zero extra skeleton markup.

import { AutoSkeletonLoader } from "react-loadly";
import "react-loadly/styles.css";

// A presentational component with memo and sub-components
const WorkerCard = React.memo(({ data }) => {
  return (
    <div className="card-container">
      <div className="flex gap-4">
        <img src={data.avatar} className="rounded-full w-12 h-12" />
        <div>
          <h3 className="text-lg font-bold">{data.name}</h3>
          <p className="text-gray-500">{data.role}</p>
        </div>
      </div>
      <div className="mt-4">
        <BadgeAtom text={data.status} variant="success" />
      </div>
      <BaseButtonAtom text="View Profile" onClick={handleProfile} />
    </div>
  );
});

// Implementation
function Dashboard({ isLoading, worker }) {
  return <AutoSkeletonLoader loading={isLoading} inheritStyles={true} shimmer={true} component={<WorkerCard data={worker} />} />;
}

Comparison: AutoSkeletonLoader Status

| Feature | Explicit Skeletons (SkeletonLoader + SkeletonGroupLoader) | AutoSkeletonLoader | | :------------------------ | :------------------------------------------------------------ | :--------------------------- | | Recommendation | Production | Experimental | | Accuracy | Intentional and design-reviewable | Best-effort structural match | | Complex React Trees | Stable | May fall back | | Maintenance | Manual but predictable | Lower setup, more variance | | Runtime Introspection | None | Yes |


⚙️ AutoSkeletonLoader Props (IAutoSkeletonProps)

| Prop | Type | Default | Description | | :--------------- | :------------------------------ | :--------------------- | :------------------------------------------------------------------------------------------ | | component | ReactElement | Required | The actual component to analyze and mirror. | | loading | boolean | true | When false, the real component is rendered with a smooth transition. | | inheritStyles | boolean | false | If true, skeleton blocks will copy style and className from original elements. | | styless | Record<string, CSSProperties> | {} | Key-value pairs to override dimensions for specific tags (e.g., { h1: { width: '50%'} }). | | shimmer | boolean | true | Enables the high-performance GPU-accelerated shimmer wave. | | speed | number | 1 | Animation speed multiplier (higher is faster). | | color | string | "#e2e8f0" | The base background color of the skeleton blocks. | | highlightColor | string | "#f1f5f9" | The highlight color used in the shimmer gradient. | | shimmerColor | string | "#f1f5f9" | The center color used in the shimmer gradient. | | waveWidthValue | string | "200px" | Width of the shimmer wave gradient. | | waveDirection | String | "left-to-right" | Shimmer direction: left-to-right, right-to-left, etc. | | maxDepth | number | 30 | Maximum structural traversal depth before falling back. | | aria-label | string | "Loading content..." | Accessible label for screen readers. |


AutoSkeleton Examples

<AutoSkeletonLoader component={<ProfileCard />} />
<AutoSkeletonLoader component={<ProductCard />} />
<AutoSkeletonLoader component={<DashboardCard />} />

For best results, keep the target component presentational and expose meaningful JSX structure with className/style layout information.

import React from "react";
import { AutoSkeletonLoader } from "react-loadly";

const PhotoBase = ({ src, caption }: { src: string; caption: string }) => (
  <figure className="w-full">
    <img src={src} alt={caption} className="h-40 w-full rounded-xl" />
    <figcaption className="text-sm">{caption}</figcaption>
  </figure>
);

PhotoBase.displayName = "Photo";
const Photo = React.memo(PhotoBase);
Photo.displayName = "Photo";

export function PhotoSkeletonExample({ loading }: { loading: boolean }) {
  return <AutoSkeletonLoader inheritStyles loading={loading} component={<Photo src="/photos/lake.jpg" caption="Sunset at the lake" />} />;
}

Hook-heavy components are intentionally skipped and mapped to a fallback preset when possible:

function useAuthPreview() {
  return { user: { name: "Jane Doe", verified: true } };
}

function ProfileHeader() {
  const { user } = useAuthPreview();
  return <span>{user.name}</span>;
}

<AutoSkeletonLoader loading component={<ProfileHeader />} />;

In this case, the custom hook is detected before the component is executed, and the ProfileHeader name maps to the profile fallback preset.


New Production Loaders

GradientRingLoader

A premium gradient ring spinner for polished product surfaces and dashboards.

import { GradientRingLoader } from "react-loadly";

<GradientRingLoader size={56} color="#6366f1" secondaryColor="#06b6d4" aria-label="Loading dashboard" />;

Props: all base loader props plus secondaryColor and thickness.

Accessibility: renders role="status", aria-live="polite", and a screen-reader label.

SignalLoader

Animated signal bars for network, streaming, and realtime data loading states.

import { SignalLoader } from "react-loadly";

<SignalLoader size={48} count={4} color="#22c55e" aria-label="Connecting" />;

Props: all base loader props plus count and secondaryColor.

Accessibility: renders role="status", aria-live="polite", and a screen-reader label.

OrbitDotsLoader

Orbiting particles for polished loading states in dashboards, media apps, and realtime interfaces.

import { OrbitDotsLoader } from "react-loadly";

<OrbitDotsLoader size={56} count={4} color="#6366f1" secondaryColor="#22c55e" aria-label="Loading activity" />;

Props: all base loader props plus count and secondaryColor.

Accessibility: renders role="status", aria-live="polite", and a screen-reader label.

EqualizerLoader

Audio-style animated bars for uploads, streams, media, and activity states.

import { EqualizerLoader } from "react-loadly";

<EqualizerLoader size={52} count={5} color="#a855f7" secondaryColor="#ec4899" aria-label="Loading stream" />;

Props: all base loader props plus count and secondaryColor.

Accessibility: renders role="status", aria-live="polite", and a screen-reader label.

CardFlipLoader

A subtle flipping card animation for card-heavy interfaces and content loading.

import { CardFlipLoader } from "react-loadly";

<CardFlipLoader size={56} color="#6366f1" secondaryColor="#a78bfa" aria-label="Loading card" />;

Props: all base loader props plus secondaryColor and borderRadius.

Accessibility: renders role="status", aria-live="polite", and a screen-reader label.


✨ Key Features

  • High Performance: Uses hardware-accelerated CSS transforms and animations.
  • Accessibility First: Full ARIA support, screen reader compatibility, and keyboard navigation.
  • TypeScript Ready: Comprehensive type definitions for a seamless dev experience.
  • Highly Customizable: Adjust appearance with CSS variables or component props.
  • Tree-Shakable: Supports modern bundlers to only include what you use.
  • Reduced Motion: Respects the user's prefers-reduced-motion settings.
  • SSR Compatible: Works out-of-the-box with frameworks like Next.js.
  • Fullscreen Support: Display loaders in fullscreen mode with customizable backgrounds.
  • AutoSkeletonLoader Experimental: Best-effort runtime skeleton generation for experimentation and backward compatibility.

AutoSkeleton Compiler (In Progress)

We are actively building a next-generation compiler-assisted AutoSkeleton engine.

Instead of relying on runtime component introspection, the new architecture will leverage compile-time analysis to generate more accurate skeleton structures.

Goals:

  • Better accuracy
  • Better React compatibility
  • Better Next.js support
  • Better Vite support
  • Better performance
  • Better support for complex component trees
  • No runtime Hooks issues

Roadmap:

Experimental
↓
Compiler Research
↓
Prototype
↓
Public Beta
↓
Stable

AI and Contributor Rule

Whenever a new loader, hook, skeleton pattern, or feature is added:

  1. Update library exports.
  2. Update this README.
  3. Update showcase examples.
  4. Update showcase documentation.

The showcase app is the source of truth for examples.

Do not create examples inside:

packages/react-loadly/examples
packages/react-loadly/demo
packages/react-loadly/playground

All examples must live in:

apps/showcases

🆕 What's New in v3.0.1

React Loadly v3.0.1 introduces major features, performance enhancements, and developer-experience upgrades:

  1. <LoadlyProvider> - A global context system for managing settings overrides, theme modes ("light" | "dark"), and automatic runtime CSS injection.
  2. <SkeletonGroupLoader> - Coordinate staggering and synchronize shimmer animation phases across multiple skeleton loader children.
  3. useSkeletonState Hook - High-level loader/skeleton orchestrator hook with a minDisplayTime stabilizer to prevent UI flickering.
  4. Tree-shakeable Subpaths - Dedicated entrypoints (react-loadly/hooks, react-loadly/skeleton, react-loadly/loaders) for optimal bundling.
  5. Safe Fallbacks - AutoSkeletonLoader skips risky introspection paths and falls back when a component cannot be inspected safely.
  6. CSS Containment & Performance - Added contain: layout style paint; to skeleton container styles to reduce browser reflows during shimmer animations.
  7. Rules of Hooks Compliance - Refactored all 30 loader components to ensure hooks are called unconditionally before early returns.

Bundle Optimization & Subpath Exports

React Loadly v3.0.1 is fully tree-shakeable and supports dedicated subpath exports to minimize your application's bundle size:

  • CSS Auto-injection: In v3.0.1, the <LoadlyProvider> automatically injects the necessary CSS styles into the document head at runtime, so importing react-loadly/styles.css is optional when using the provider.
  • Tree-shakeable Entrypoints: Import directly from dedicated subpaths to ensure that your build tools only bundle what you actually use:
    • react-loadly/hooks: Re-exports hooks (useLoaderState, useSkeletonState, useAsyncLoader, etc.).
    • react-loadly/skeleton: Re-exports skeleton loaders (SkeletonLoader, AutoSkeletonLoader, SkeletonGroupLoader).
    • react-loadly/loaders: Re-exports the 27 standard design loaders.
// Import hooks
import { useSkeletonState } from "react-loadly/hooks";

// Import skeleton components
import { AutoSkeletonLoader } from "react-loadly/skeleton";

// Import loaders
import { SpinLoader } from "react-loadly/loaders";

Quick Usage

Import the components you need along with the base styles, then use them in your React application.

import { SpinLoader, PulseLoader } from "react-loadly";
import "react-loadly/styles.css"; // Essential for base styles

function App() {
  return (
    <div>
      {/* Simple spinning loader */}
      <SpinLoader />

      {/* A customized loader */}
      <PulseLoader color="#ff6b6b" size={60} />
    </div>
  );
}

🎨 Component Showcase

Geometric Loaders

| Component | Description | | --------------- | ---------------------------------------------------------------------------- | | SpinLoader | A classic spinner with a minimalist design. | | PulseLoader | A dynamic animation of pulsing dots. | | WaveLoader | A series of bars creating a wave-like effect. | | GridLoader | A grid of squares that animate in sequence. | | RingLoader | A sophisticated ring spinner with dual rotation. | | BarsLoader | Animated bars with staggered timing. | | BounceLoader | Bouncing dots with elastic animation. | | RotateLoader | 3D rotating elements with depth. | | OrbitLoader | Orbiting elements around a central point with customizable count and colors. | | PlaneLoader | 3D rotating cube with perspective transforms. | | SquaresLoader | Multiple rotating squares with varying delays and scales. | | StairLoader | Cascading stair steps creating a progress effect. | | HashtagLoader | Animated hashtag symbol with progressive drawing effect. | | SnakeLoader | Snake-like slithering animation with flowing segments. | | RippleLoader | Expanding ripple rings from a central point. |


Modern Content Loaders

| Component | Description | | -------------------- | ---------------------------------------------------------------------------------------------- | | SkeletonLoader | Modern skeleton placeholders with shimmer effects. with Sophisticated shimmer wave animations. | | AutoSkeletonLoader | Automatically generates skeleton loaders based on your component structure. |

Organic & Text-Based Loaders

| Component | Description | | -------------- | --------------------------------------------------- | | BlobLoader | A liquid-like loader with a smooth, organic feel. | | TypingLoader | A loader that simulates typing or processing text. | | DotsLoader | The familiar three-dot animation, perfect for text. | | LiquidLoader | Fluid, morphing shapes with organic movement. | | FlowLoader | Flowing particles with smooth transitions. |

Flexible Loaders

| Component | Description | | -------------------- | ------------------------------------------------------------------------------------ | --- | | ElementLoader | A flexible loader that can display any React element with various animation effects. | | FallbackLoader | Error handling and retry functionality with customizable UI. | | LogoSpinLoader | Specialized loader for logos and brand elements. | | ProgressRingLoader | Accessible progress ring with optional determinate mode. | | MorphLoader | Smooth morphing SVG shapes that interpolate between paths. | | SpinDotsLoader | Circular orbit of dots; perfect for inline text. | | HeatmapLoader | Grid of pulses with staggered timing; useful for dashboards. | |

ProgressRingLoader Component

The ProgressRingLoader is an accessible progress ring component that supports both determinate and indeterminate modes. In determinate mode, it shows the exact progress percentage, while in indeterminate mode, it provides a continuous spinning animation.

Basic Usage

import { ProgressRingLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Indeterminate mode (default) */}
      <ProgressRingLoader />

      {/* Determinate mode */}
      <ProgressRingLoader progress={75} />

      {/* Custom size and color */}
      <ProgressRingLoader size={60} color="#10b981" thickness={6} />
    </div>
  );
}

ProgressRingLoader Props

| Prop | Type | Default | Description | | ----------- | ---------------- | --------- | ------------------------------------------------ | | progress | number | null | null | Progress value (0-100) or null for indeterminate | | thickness | number | 4 | Thickness of the ring | | size | number | string | 40 | Size of the loader | | color | string | "#6366f1" | Color of the progress ring |

All other props are inherited from IBaseLoaderProps.


MorphLoader Component

The MorphLoader creates smooth morphing SVG shapes that interpolate between different paths. It supports three variants: blob, soft, and sharp.

Basic Usage

import { MorphLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default blob variant */}
      <MorphLoader />

      {/* Soft variant */}
      <MorphLoader variant="soft" />

      {/* Sharp variant */}
      <MorphLoader variant="sharp" />

      {/* Custom size and color */}
      <MorphLoader size={60} color="#10b981" />
    </div>
  );
}

MorphLoader Props

| Prop | Type | Default | Description | | --------- | --------------------------- | --------- | --------------------------- | | variant | "blob" | "soft" | "sharp" | "blob" | Morph variant type | | speed | number | 1 | Animation speed multiplier | | size | number | string | 40 | Size of the loader | | color | string | "#6366f1" | Color of the morphing shape |

All other props are inherited from IBaseLoaderProps.


SpinDotsLoader Component

The SpinDotsLoader creates a circular orbit of dots, perfect for inline text loading indicators.

Basic Usage

import { SpinDotsLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default 3 dots */}
      <SpinDotsLoader />

      {/* Custom number of dots */}
      <SpinDotsLoader dots={5} />

      {/* Custom size and color */}
      <SpinDotsLoader size={50} color="#10b981" />
    </div>
  );
}

SpinDotsLoader Props

| Prop | Type | Default | Description | | ------- | ---------------- | --------- | -------------------------- | | dots | number | 3 | Number of dots in orbit | | gap | number | 8 | Gap between dots | | size | number | string | 40 | Size of the loader | | color | string | "#6366f1" | Color of the dots | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


HeatmapLoader Component

The HeatmapLoader displays a grid of pulses with staggered timing, useful for dashboard data placeholders.

Basic Usage

import { HeatmapLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default 3x5 grid */}
      <HeatmapLoader />

      {/* Custom grid size */}
      <HeatmapLoader rows={4} cols={6} />

      {/* Custom size and color */}
      <HeatmapLoader size={60} color="#10b981" />
    </div>
  );
}

HeatmapLoader Props

| Prop | Type | Default | Description | | ------- | ---------------- | --------- | -------------------------- | | rows | number | 3 | Number of rows in grid | | cols | number | 5 | Number of columns in grid | | size | number | string | 40 | Size of the loader | | color | string | "#6366f1" | Color of the cells | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


ClockLoader Component

The ClockLoader animates like a traditional clock with hour, minute, and second hands.

Basic Usage

import { ClockLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default clock */}
      <ClockLoader />

      {/* Custom size */}
      <ClockLoader size={60} />

      {/* Custom tick speed */}
      <ClockLoader tickSpeed={2} />
    </div>
  );
}

ClockLoader Props

| Prop | Type | Default | Description | | ----------- | ---------------- | --------- | ------------------------ | | size | number | string | 40 | Size of the clock | | tickSpeed | number | 1 | Speed of clock animation | | color | string | "#6366f1" | Color of the clock hands |

All other props are inherited from IBaseLoaderProps.


NeumorphicLoader Component

The NeumorphicLoader creates a soft neumorphic pill/dots loader for modern UI designs.

Basic Usage

import { NeumorphicLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default elevation */}
      <NeumorphicLoader />

      {/* Custom elevation */}
      <NeumorphicLoader elevation={8} />

      {/* Custom size and color */}
      <NeumorphicLoader size={50} color="#10b981" />
    </div>
  );
}

NeumorphicLoader Props

| Prop | Type | Default | Description | | ----------- | ---------------- | --------- | -------------------------- | | elevation | number | 5 | Elevation level (1-10) | | size | number | string | 40 | Size of the loader | | color | string | "#6366f1" | Color of the loader | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


OrbitLoader Component

The OrbitLoader creates a beautiful orbital animation with elements rotating around a central point, similar to planets orbiting a star.

Basic Usage

import { OrbitLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default with 3 orbiting elements */}
      <OrbitLoader />

      {/* Custom number of orbiting elements */}
      <OrbitLoader count={5} />

      {/* With secondary color */}
      <OrbitLoader count={4} color="#3b82f6" secondaryColor="#f59e0b" />
    </div>
  );
}

OrbitLoader Props

| Prop | Type | Default | Description | | ---------------- | ---------------- | --------- | ---------------------------------------- | | count | number | 3 | Number of orbiting elements | | secondaryColor | string | undefined | Secondary color for alternating elements | | size | number | string | 60 | Size of the loader | | color | string | "#6366f1" | Primary color of the orbit elements | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


PlaneLoader Component

The PlaneLoader displays a 3D rotating cube with perspective transforms, creating a modern 3D loading experience.

Basic Usage

import { PlaneLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default cube */}
      <PlaneLoader />

      {/* Custom size and color */}
      <PlaneLoader size={60} color="#10b981" />

      {/* With secondary color for cube faces */}
      <PlaneLoader size={70} color="#3b82f6" secondaryColor="#8b5cf6" />
    </div>
  );
}

PlaneLoader Props

| Prop | Type | Default | Description | | ---------------- | ---------------- | --------- | ----------------------------------- | | secondaryColor | string | undefined | Color for the cube face backgrounds | | size | number | string | 50 | Size of the loader | | color | string | "#6366f1" | Primary color of the cube edges | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


RippleLoader Component

The RippleLoader creates expanding ripple rings from a central point, similar to water ripples.

Basic Usage

import { RippleLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default with 3 ripples */}
      <RippleLoader />

      {/* Custom number of ripples */}
      <RippleLoader count={5} />

      {/* With secondary color and custom border width */}
      <RippleLoader count={4} color="#3b82f6" secondaryColor="#8b5cf6" borderWidth={3} />
    </div>
  );
}

RippleLoader Props

| Prop | Type | Default | Description | | ---------------- | ---------------- | --------- | --------------------------------------- | | count | number | 3 | Number of ripple rings | | secondaryColor | string | undefined | Secondary color for alternating ripples | | borderWidth | number | 2 | Width of the ripple border | | size | number | string | 50 | Size of the loader | | color | string | "#6366f1" | Primary color of the ripples | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


SquaresLoader Component

The SquaresLoader displays multiple rotating squares with varying delays and scales for a dynamic grid effect.

Basic Usage

import { SquaresLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default with 4 squares */}
      <SquaresLoader />

      {/* Custom number of squares */}
      <SquaresLoader count={6} />

      {/* With secondary color */}
      <SquaresLoader count={9} color="#3b82f6" secondaryColor="#f59e0b" />
    </div>
  );
}

SquaresLoader Props

| Prop | Type | Default | Description | | ---------------- | ---------------- | --------- | --------------------------------------- | | count | number | 4 | Number of squares | | secondaryColor | string | undefined | Secondary color for alternating squares | | size | number | string | 40 | Size of the loader | | color | string | "#6366f1" | Primary color of the squares | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


StairLoader Component

The StairLoader creates cascading stair steps that animate in sequence, creating a progress-like effect.

Basic Usage

import { StairLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default with 5 steps */}
      <StairLoader />

      {/* Custom number of steps */}
      <StairLoader count={7} />

      {/* With secondary color */}
      <StairLoader count={6} color="#3b82f6" secondaryColor="#8b5cf6" />
    </div>
  );
}

StairLoader Props

| Prop | Type | Default | Description | | ---------------- | ---------------- | --------- | ------------------------------------- | | count | number | 5 | Number of stair steps | | secondaryColor | string | undefined | Secondary color for alternating steps | | size | number | string | 35 | Size of the loader | | color | string | "#6366f1" | Primary color of the steps | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


HashtagLoader Component

The HashtagLoader animates a hashtag symbol with a progressive drawing effect.

Basic Usage

import { HashtagLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default hashtag */}
      <HashtagLoader />

      {/* Custom size and color */}
      <HashtagLoader size={60} color="#10b981" />

      {/* With secondary color */}
      <HashtagLoader size={70} color="#3b82f6" secondaryColor="#8b5cf6" />
    </div>
  );
}

HashtagLoader Props

| Prop | Type | Default | Description | | ---------------- | ---------------- | --------- | --------------------------------------------- | | secondaryColor | string | undefined | Secondary color for alternating path segments | | size | number | string | 50 | Size of the loader | | color | string | "#6366f1" | Primary color of the hashtag stroke | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


SnakeLoader Component

The SnakeLoader creates a snake-like animation with flowing segments that move in a wave pattern.

Basic Usage

import { SnakeLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Default with 6 segments */}
      <SnakeLoader />

      {/* Custom number of segments */}
      <SnakeLoader count={8} />

      {/* With secondary color */}
      <SnakeLoader count={10} color="#3b82f6" secondaryColor="#f59e0b" />
    </div>
  );
}

SnakeLoader Props

| Prop | Type | Default | Description | | ---------------- | ---------------- | --------- | ---------------------------------------- | | count | number | 6 | Number of snake segments | | secondaryColor | string | undefined | Secondary color for alternating segments | | size | number | string | 60 | Size of the loader | | color | string | "#6366f1" | Primary color of the snake segments | | speed | number | 1 | Animation speed multiplier |

All other props are inherited from IBaseLoaderProps.


🦴 SkeletonPatternLoader Component

The SkeletonPatternLoader is perfect for modern loading states, creating placeholder content that mimics the actual content structure.

Basic Usage

import { SkeletonPatternLoader } from "react-loadly";
import "react-loadly/styles.css";

function App() {
  return (
    <div>
      {/* Basic skeleton line */}
      <SkeletonPatternLoader />

      {/* Multiple skeleton lines */}
      <SkeletonPatternLoader lines={3} />

      {/* Card skeleton */}
      <SkeletonPatternLoader variant="card" width={300} height={200} />

      {/* Avatar skeleton */}
      <SkeletonPatternLoader variant="avatar" size={60} />
    </div>
  );
}

SkeletonPatternLoader Variants

The SkeletonPatternLoader supports multiple variants to match different content types:

// Line skeleton (default) - for text content
<SkeletonPatternLoader variant="line" lines={3} />

// Card skeleton - for image cards or content blocks
<SkeletonPatternLoader variant="card" width={300} height={200} />

// Avatar skeleton - for profile images
<SkeletonPatternLoader variant="avatar" size={60} />

// Text skeleton - for single line text
<SkeletonPatternLoader variant="text" width="100%" height={16} />

// Custom skeleton - for any custom shape
<SkeletonPatternLoader
  variant="custom"
  width={200}
  height={100}
  borderRadius="8px"
/>

Variant Details

| Variant | Use Case | Default Dimensions | Default Border Radius | | -------- | ---------------------------------- | --------------------------- | --------------------- | | line | Paragraphs, lists, general content | width: 100%, height: 16px | 4px | | card | Images, cards, content blocks | width: 300px, height: 200px | 8px | | avatar | Profile pictures, user icons | width: 40px, height: 40px | 50% (circular) | | text | Single line text elements | width: 100%, height: 16px | 4px | | custom | Any custom shape or element | width: 100%, height: 16px | 4px (customizable) |

Customization Options

<SkeletonPatternLoader
  lines={3}
  color="#f0f0f0"
  highlightColor="#e0e0e0"
  shimmerColor="rgba(255, 255, 255, 0.6)"
  spacing="12px"
  shimmer={true}
  waveWidth="200px"
  waveDirection="left-to-right"
  speed={1.5}
/>

SkeletonPatternLoader Props

| Prop | Type | Default | Description | | ---------------- | ------------------------------------------------------------------------ | ----------------------- | ----------------------------------- | | lines | number | 1 | Number of skeleton lines to display | | variant | "line" | "card" | "avatar" | "text" | "custom" | "line" | Variant of skeleton to display | | width | number | string | varies by variant | Width of skeleton elements | | height | number | string | varies by variant | Height of skeleton elements | | borderRadius | number | string | varies by variant | Border radius of skeleton elements | | spacing | number | string | "8px" | Spacing between skeleton lines | | shimmer | boolean | true | Whether to show shimmer animation | | shimmerColor | string | "rgba(255,255,255,0.6)" | Shimmer effect color | | highlightColor | string | "#f1f5f9" | Highlight color for shimmer effect | | waveWidth | number | string | "200px" | Shimmer wave width | | waveDirection | "left-to-right" | "right-to-left" | "top-to-bottom" | "bottom-to-top" | "left-to-right" | Direction of shimmer animation |


🎨 New Loaders Feature Guide

Using Multiple New Loaders Together

Here's how to combine the new loaders for amazing visual effects:

import { OrbitLoader, PlaneLoader, RippleLoader, SquaresLoader, StairLoader, HashtagLoader, SnakeLoader } from "react-loadly";
import "react-loadly/styles.css";

function MultiLoaderShowcase() {
  return (
    <div style={{ display: "grid", gridTemplateColumns: "repeat(2, 1fr)", gap: "40px", padding: "40px" }}>
      {/* Orbital system animation */}
      <div style={{ textAlign: "center" }}>
        <h3>OrbitLoader - Space Theme</h3>
        <OrbitLoader size={80} count={5} color="#0ea5e9" secondaryColor="#fbbf24" />
      </div>

      {/* 3D cube for tech products */}
      <div style={{ textAlign: "center" }}>
        <h3>PlaneLoader - 3D Effect</h3>
        <PlaneLoader size={70} color="#6366f1" secondaryColor="#8b5cf6" />
      </div>

      {/* Ripple for notifications */}
      <div style={{ textAlign: "center" }}>
        <h3>RippleLoader - Pulse Effect</h3>
        <RippleLoader size={60} count={4} color="#10b981" borderWidth={3} />
      </div>

      {/* Dynamic grid */}
      <div style={{ textAlign: "center" }}>
        <h3>SquaresLoader - Grid Animation</h3>
        <SquaresLoader size={50} count={6} color="#3b82f6" />
      </div>

      {/* Progress stairs */}
      <div style={{ textAlign: "center" }}>
        <h3>StairLoader - Step Effect</h3>
        <StairLoader size={45} count={7} color="#f59e0b" />
      </div>

      {/* Social media hashtag */}
      <div style={{ textAlign: "center" }}>
        <h3>HashtagLoader - Social Media</h3>
        <HashtagLoader size={65} color="#1da1f2" speed={1.5} />
      </div>

      {/* Flowing snake */}
      <div style={{ textAlign: "center" }}>
        <h3>SnakeLoader - Organic Motion</h3>
        <SnakeLoader size={70} count={8} color="#ec4899" secondaryColor="#8b5cf6" />
      </div>
    </div>
  );
}

Color Themes for New Loaders

All new loaders support secondaryColor for beautiful gradient and alternating color effects:

// Ocean theme
<OrbitLoader color="#0ea5e9" secondaryColor="#06b6d4" />
<RippleLoader color="#0891b2" borderWidth={2} />

// Fire theme
<SnakeLoader color="#f97316" secondaryColor="#ef4444" />
<StairLoader color="#ff9500" secondaryColor="#ff6b00" />

// Purple theme
<PlaneLoader color="#7c3aed" secondaryColor="#a78bfa" />
<SquaresLoader color="#8b5cf6" secondaryColor="#c4b5fd" />

// Social media theme
<HashtagLoader color="#1da1f2" /> // Twitter blue
<HashtagLoader color="#E1306C" /> // Instagram pink

⚡ Performance & Best Practices

Performance Optimization

React Loadly is built with performance in mind:

  • Hardware Acceleration: All animations use CSS transforms and will-change for optimal performance
  • Reduced Motion Support: Automatically respects user's motion preferences
  • Tree Shaking: Import only the components you need
  • Memoization: Components use React.memo and useMemo for optimal re-rendering
  • CSS-in-JS: Minimal runtime overhead with CSS variables

Best Practices

// ✅ Good: Import only what you need
import { SpinLoader, SkeletonPatternLoader } from "react-loadly";

// ❌ Avoid: Importing everything
import \* as Loaders from "react-loadly";

// ✅ Good: Use appropriate loader for context
function UserProfile({ user, loading }) {
  if (loading) {
    return (
      <div>
        <SkeletonPatternLoader variant="avatar" size={60} />
        <SkeletonPatternLoader lines={2} />
      </div>
    );
  }
  return <div>{/_ User content _/}</div>;
}

// ✅ Good: Conditional rendering
function DataComponent({ data, loading }) {
  return <div>{loading ? <SpinLoader /> : <div>{data}</div>}</div>;
}

// ✅ Good: Use fullscreen for page-level loading
function App() {
  const [isLoading, setIsLoading] = useState(true);

  return (
    <div>
      {isLoading && <SpinLoader fullscreen loaderCenter screenBackground="rgba(255, 255, 255, 0.9)" />}
      {/_ App content _/}
    </div>
  );
}

Bundle Size Optimization

``jsx // ✅ Tree-shakable imports import { SpinLoader } from "react-loadly";

// ✅ CSS imports (only import what you need) import "react-loadly/styles.css";

// ✅ For Next.js, use dynamic imports for code splitting import dynamic from "next/dynamic";

const SkeletonPatternLoader = dynamic(() => import("react-loadly").then((mod) => ({ default: mod.SkeletonPatternLoader })));


---

## ♿ Accessibility

Accessibility is a core feature, not an afterthought. All loaders include:

- **ARIA attributes** (`role="status"`, `aria-label`) for screen readers.
- Support for **Reduced Motion**.
- **High contrast** and semantic HTML.

<!-- end list -->

``jsx
// Accessible by default
<SpinLoader aria-label="Loading content" />

// Custom accessible text
<PulseLoader showText loadingText="Processing your request..." />

🛠️ Customization

CSS Variables

Customize the entire loader library globally with CSS variables.

:root {
  --loader-color: #3b82f6;
  --loader-size: 40px;
  --loader-speed: 1s;
  --loader-text-color: #6b7280;
}

Component Props

Each loader component accepts a common set of props for fine-grained control.

interface BaseLoaderProps {
  size?: number | string;
  color?: string;
  speed?: number;
  loading?: boolean;
  className?: string;
  style?: React.CSSProperties;
  showText?: boolean;
  loadingText?: string;
  // Fullscreen props
  fullscreen?: boolean;
  screenWidth?: number | string;
  screenHeight?: number | string;
  loaderCenter?: boolean;
  screenBackground?: string;
}

TypeScript Integration

React Loadly provides comprehensive TypeScript definitions for all components and hooks. You can import types and interfaces directly from the library:

``tsx // ✅ Correct way to import shared interfaces import type { IBaseLoaderProps, ISkeletonPatternLoaderProps } from "react-loadly";

// For component-specific props import type { IOrbitLoaderProps, IPlaneLoaderProps, IRippleLoaderProps, ISquaresLoaderProps, IStairLoaderProps, IHashtagLoaderProps, ISnakeLoaderProps } from "react-loadly";

// For hook return types import type { IUseLoaderStateReturn } from "react-loadly/hooks";

// For animation types import type { AnimationDirectionType } from "react-loadly";


All types are properly exported and can be used in your TypeScript projects for better type safety and autocompletion.

**Available Interface Exports:**
- `IBaseLoaderProps` - Base props for all loaders
- `IGeometricLoaderProps` - Base props for geometric loaders (includes `count`, `secondaryColor`, etc.)
- `IOrbitLoaderProps`, `IPlaneLoaderProps`, `IRippleLoaderProps`, etc. - Specific loader props
- `ISkeletonPatternLoaderProps`, `IProgressRingLoaderProps`, `IMorphLoaderProps` - Specialized loader props

Avoid importing directly from internal paths like `react-loadly/types` or `react-loadly/interfaces` as these are not part of the public API and may change.

### Fullscreen Mode

Display any loader in fullscreen mode with customizable dimensions and background:

```jsx
// Fullscreen loader covering entire viewport
<SpinLoader
  fullscreen={true}
  loaderCenter={true}
  screenBackground="#f0f0f0"
/>

// Fullscreen loader with custom dimensions
<PulseLoader
  fullscreen={true}
  screenWidth={800}
  screenHeight={600}
  loaderCenter={true}
  screenBackground="rgba(0, 0, 0, 0.5)"
/>
```

---

## 🎯 Real-World Examples

### Loading States for Different Content Types

``jsx
import { SkeletonPatternLoader, SpinLoader, PulseLoader } from "react-loadly";

function ContentLoader() {
  return (

<div>
{/_ Blog post loading Dashboard loading _/}
<div className="blog-post">
<SkeletonPatternLoader variant="avatar" size={40} />
<SkeletonPatternLoader lines={3} spacing="8px" />
<SkeletonPatternLoader variant="card" width="100%" height={200} />
</div>

      {/* Button loading */}
      <button disabled>
        <SpinLoader size={16} />
        Processing...
      </button>

      {/* Inline loading */}
      <div>
        Loading data <PulseLoader size={12} />
      </div>
    </div>

  );
}

```

### Form Loading States

``jsx
function FormWithLoading() {
  const [isSubmitting, setIsSubmitting] = useState(false);

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" placeholder="Name" />
      <input type="email" placeholder="Email" />

      <button type="submit" disabled={isSubmitting}>
        {isSubmitting ? (
          <>
            <SpinLoader size={16} />
            Submitting...
          </>
        ) : (
          "Submit"
        )}
      </button>
    </form>
  );
}
```

### Data Table Loading

``jsx
function DataTable({ data, loading }) {
  if (loading) {
    return (

<div className="data-table">
{/_ Header skeleton _/}
<div className="table-header">
{Array.from({ length: 5 }).map((\_, i) => (
<SkeletonPatternLoader key={i} width={120} height={20} />
))}
</div>

        {/* Row skeletons */}
        {Array.from({ length: 10 }).map((_, i) => (
          <div key={i} className="table-row">
            {Array.from({ length: 5 }).map((_, j) => (
              <SkeletonPatternLoader key={j} width={100} height={16} />
            ))}
          </div>
        ))}
      </div>
    );

  }

  return <div className="data-table">{/_ Actual table content _/}</div>;
}

```

### Image Gallery Loading

``jsx
function ImageGallery({ images, loading }) {
  if (loading) {
    return (
      <div className="image-gallery">
        {Array.from({ length: 6 }).map((_, i) => (
          <SkeletonPatternLoader
            key={i}
            variant="card"
            width={200}
            height={200}
            borderRadius="8px"
            shimmer
            shimmerColor="#f0f0f0"
            waveDirection="left-to-right"
          />
        ))}
      </div>
    );
  }

  return (
    <div className="image-gallery">
      {images.map((image, i) => (
        <img key={i} src={image.url} alt={image.alt} />
      ))}
    </div>
  );
}
```

### Social Media Feed Loading

``jsx
function SocialFeed({ posts, loading }) {
  if (loading) {
    return (
      <div className="social-feed">
        {Array.from({ length: 5 }).map((_, i) => (
          <div key={i} className="feed-card">
            <div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginBottom: '12px' }}>
              <SkeletonPatternLoader variant="avatar" size={40} />
              <SkeletonPatternLoader lines={2} width="80%" />
            </div>
            <SkeletonPatternLoader variant="card" width="100%" height={200} />
            <div style={{ display: 'flex', gap: '8px', marginTop: '12px' }}>
              <SnakeLoader size={20} count={4} />
              <span>Processing...</span>
            </div>
          </div>
        ))}
      </div>
    );
  }

  return <div className="social-feed">{posts.map(renderPost)}</div>;
}
```

### Gaming/Entertainment Loading States

``jsx
function GameLoader() {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '20px', alignItems: 'center' }}>
      {/* Futuristic game loading */}
      <OrbitLoader size={80} count={6} color="#00f5ff" secondaryColor="#ff0080" />

      {/* Social media hashtag */}
      <HashtagLoader size={60} color="#1da1f2" speed={1.5} />

      {/* Snake game effect */}
      <SnakeLoader size={70} count={8} color="#10b981" secondaryColor="#f59e0b" />
    </div>
  );
}
```

### 3D and Modern UI Loading

``jsx
function ModernDashboardLoader() {
  return (
    <div className="dashboard-loader">
      {/* 3D rotating cube for tech products */}
      <PlaneLoader size={60} color="#6366f1" secondaryColor="#8b5cf6" />

      {/* Ripple effect for notifications */}
      <RippleLoader size={50} count={4} color="#3b82f6" borderWidth={3} />

      {/* Staircase for progress indication */}
      <StairLoader count={7} size={40} color="#10b981" />
    </div>
  );
}

---

## 🧩 Advanced Usage

### `useLoaderState` Hook

Manage loading, error, and retry states for your data fetching with this convenient hook.

```jsx
import { useLoaderState, SpinLoader } from "react-loadly";

function DataComponent() {
  const { state, setLoading, setError, retry } = useLoaderState({
    timeout: 10000,
    maxRetries: 3,
  });

  const loadData = async () => {
    setLoading(true);
    try {
      await fetch("/api/data");
      setLoading(false);
    } catch (error) {
      setError(error.message);
    }
  };

  if (state.error) {
    return (
      <div>
        Error: {state.error}
        <button onClick={retry}>Retry</button>
      </div>
    );
  }

  return (
    <div>
      <SpinLoader loading={state.isLoading} />
      <button onClick={loadData} disabled={state.isLoading}>
        Load Data
      </button>
    </div>
  );
}
```

---

### Global Configuration: `LoadlyProvider`

The `LoadlyProvider` allows you to customize defaults globally, manage theme modes (`"light"` | `"dark"`), and handle automatic CSS injection:

```tsx
import { LoadlyProvider } from "react-loadly";
import { SpinLoader } from "react-loadly/loaders";

function App() {
  return (
    <LoadlyProvider
      theme="dark" // Sets dark mode defaults automatically
      color="#8b5cf6" // Overrides the default loader color globally
      injectStyles={true} // Automatically injects base CSS into the document head
    >
      <SpinLoader />
    </LoadlyProvider>
  );
}
```

#### Provider Options (Props)

| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `theme` | `"light" \| "dark"` | `"light"` | Configures automatic color adjustments for theme modes. |
| `color` | `string` | `"#6366f1"` | Global base loader color. |
| `secondaryColor` | `string` | `"#8b5cf6"` | Global secondary loader color. |
| `speed` | `number` | `1` | Global animation speed multiplier. |
| `injectStyles` | `boolean` | `true` | When true, automatically injects base CSS into the document head at runtime. |
| `loaderCenter` | `boolean` | `false` | Centers all loaders horizontally and vertically when fullscreen is enabled. |

---

### SkeletonPatternLoader Coordination: `SkeletonGroupLoader`

Use the `SkeletonGroupLoader` component to synchronize shimmer animation phases and implement stagger effects across multiple skeleton loader children.

```tsx
import { SkeletonGroupLoader, SkeletonPatternLoader } from "react-loadly/skeleton";

function ListPlaceholder() {
  return (
    <SkeletonGroupLoader stagger={0.15} shimmerSync={true}>
      <SkeletonPatternLoader lines={2} />
      <SkeletonPatternLoader lines={3} />
      <SkeletonPatternLoader lines={1} />
    </SkeletonGroupLoader>
  );
}
```

#### `SkeletonGroupLoader` Props

| Prop | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `stagger` | `number` | `0.1` | Delay in seconds between the start of each skeleton child's shimmer. |
| `shimmerSync` | `boolean` | `true` | Coordinates animation timeline phases across all children. |

---

### `useSkeletonState` Hook

`useSkeletonState` is a high-level orchestrator hook designed to manage loading, skeleton props, and error/retry states with a `minDisplayTime` stabilizer to prevent jarring UI flashes.

```tsx
import { useSkeletonState } from "react-loadly/hooks";
import { AutoSkeletonLoader } from "react-loadly/skeleton";

function UserProfile({ userId }) {
  const { loading, error, showSkeleton, retry, data } = useSkeletonState({
    fetchFn: () => fetchUser(userId),
    minDisplayTime: 400, // Keeps the skeleton visible for at least 400ms to stabilize layout
  });

  if (error) {
    return <button onClick={retry}>Retry loading profile</button>;
  }

  return (
    <AutoSkeletonLoader
      loading={showSkeleton}
      component={<ProfileCard user={data} />}
    />
  );
}
```

#### `useSkeletonState` Options

| Option | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `fetchFn` | `() => Promise<T>` | **Required** | The async function to fetch data. |
| `minDisplayTime` | `number` | `300` | Minimum duration (in milliseconds) the skeleton will remain visible to prevent flashing. |
| `onSuccess` | `(data: T) => void` | `undefined` | Callback invoked upon successful fetch. |
| `onError` | `(err: any) => void` | `undefined` | Callback invoked upon fetch failure. |

---

## 🤝 Contributing

We welcome contributions from the community! Whether you're fixing bugs, adding new features, or improving documentation, your contributions help make React Loadly better for everyone.

### How to Contribute

1. **Fork the repository** on GitHub
2. **Clone your fork** locally:
   ```bash
   git clone https://github.com/your-username/react-loadly.git
   cd react-loadly
   ```
3. **Create a new branch** for your changes:
   ```bash
   git checkout -b feature/your-feature-name
   ```
4. **Install dependencies**:
   ```bash
   pnpm install
   ```
5. **Make your changes** and ensure tests pass:
   ```bash
   pnpm test
   pnpm build
   ```
6. **Commit your changes**:
   ```bash
   git commit -m "feat: add your awesome feature"
   ```
7. **Push to your fork**:
   ```bash
   git push origin feature/your-feature-name
   ```
8. **Open a Pull Request** with a clear description of your changes

### What You Can Contribute

- 🐛 **Bug fixes** - Help us squash bugs
- ✨ **New loader components** - Add new loading animations
- 📚 **Documentation** - Improve examples and guides
- 🎨 **Design improvements** - Enhance existing components
- 🧪 **Tests** - Add test coverage
- 🌐 **Internationalization** - Help with translations
- 📦 **Build improvements** - Optimize bundle size and build process

### Development Guidelines

- Follow the existing code style and patterns
- Add tests for new features
- Update documentation for API changes
- Ensure accessibility standards are met
- Keep bundle size impact minimal

### Need Help?

- 💬 **Join our discussions** in GitHub Discussions
- 🐛 **Report bugs** in GitHub Issues
- 💡 **Suggest features** in GitHub Issues
- 📖 **Read our contributing guide** for detailed information

---

## 👥 Contributors

Thank you to all the amazing people who have contributed to React Loadly:

<!-- Contributors will be automatically updated by GitHub Actions -->
<!--
<a href="https://github.com/Mostafashadow1/react-loadly/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=Mostafashadow1/react-loadly" />
</a>
-->

### Hall of Fame

- **[@Mostafashadow1](https://github.com/Mostafashadow1)** - Creator and maintainer
- _Your name could be here!_ - [Contribute today](#-contributing)

### Recognition

We recognize contributors in several ways:

- 🏆 **Contributor badges** in pull requests
- 📝 **Contributor recognition** in release notes
- 🌟 **Hall of fame** in this README
- 🎉 **Special thanks** in our changelog

---

## 📄 License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

---

## 🙏 Acknowledgments

- Thanks to the React community for inspiration and feedback
- Special thanks to all contributors who help make this project better
- Built with ❤️ for developers who value great UX

---

**Made with ❤️ by the React Loadly community**