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

@flibbertigibbeting/loading-message

v0.2.2

Published

React component for delightful loading messages

Readme

@flibbertigibbeting/loading-message

Loading states done right. Delightful messages, 50+ spinners, accessible by default.

npm version bundle size license


Why?

Loading states are tedious. You either grab a spinner that doesn't match your app, or build something custom every time. Meanwhile, users stare at generic "Loading..." text.

This library gives you:

  • 50+ spinner animations — from minimal to playful
  • Cycling loading messages — keep users engaged during waits
  • Accessible by defaultaria-live, reduced-motion support
  • Tiny bundle — tree-shakeable, zero dependencies

Quick Start

npm install @flibbertigibbeting/loading-message
import { Spinner, LoadingMessage } from '@flibbertigibbeting/loading-message'

// Simple spinner
<Spinner type="dots-bounce" />

// Cycling messages with spinner
<LoadingMessage 
  messages={["Loading...", "Almost there...", "Just a moment..."]}
  spinnerType="circle"
/>

When to Use What

| Situation | Component | Example | |-----------|-----------|---------| | Quick async operation (<2s) | <Spinner /> | Button click, form submit | | Longer operation (2-10s) | <LoadingMessage /> | API calls, file processing | | Custom implementation | useLoadingMessage() | Complex loading UX |


Components

<Spinner />

Standalone animated spinner with 50+ styles.

import { Spinner } from '@flibbertigibbeting/loading-message'

<Spinner 
  type="dots-bounce"  // See all types below
  size={32}           // Size in pixels
  color="#3b82f6"     // Any CSS color
  speed={1}           // Animation speed multiplier
/>

Spinner Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | type | SpinnerType | 'circle' | Animation style (see list below) | | size | number | 40 | Size in pixels | | color | string | 'currentColor' | Any valid CSS color | | speed | number | 1 | Animation speed (0.5 = slower, 2 = faster) | | label | string | 'Loading' | Accessible label for screen readers | | className | string | - | Additional CSS classes |


<LoadingMessage />

Displays cycling messages with optional spinner.

import { LoadingMessage } from '@flibbertigibbeting/loading-message'

// Basic usage
<LoadingMessage messages={["Loading...", "Please wait..."]} />

// With custom spinner
<LoadingMessage 
  messages={["Fetching data...", "Processing...", "Almost done..."]}
  interval={2000}
  spinnerType="dots-bounce"
  spinnerColor="#10b981"
/>

// Using built-in message categories
<LoadingMessage category="tech" tone="playful" />

LoadingMessage Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | messages | string[] | - | Custom messages to cycle through | | category | string | - | Use built-in messages by category | | tone | string | - | Filter by tone (playful, professional, etc.) | | interval | number | 3000 | Milliseconds between messages | | showSpinner | boolean | true | Show spinner alongside message | | spinnerType | SpinnerType | 'circle' | Spinner animation style | | spinnerSize | number | 20 | Spinner size in pixels | | spinnerColor | string | 'currentColor' | Spinner color | | onMessageChange | (msg) => void | - | Callback when message changes |


useLoadingMessage() Hook

For custom loading implementations.

import { useLoadingMessage } from '@flibbertigibbeting/loading-message'

function CustomLoader() {
  const { message, index, isComplete, reset } = useLoadingMessage({
    messages: ["Step 1...", "Step 2...", "Step 3..."],
    interval: 1500,
    loop: false,  // Stop after last message
  })

  return (
    <div>
      <p>{message}</p>
      {isComplete && <button onClick={reset}>Retry</button>}
    </div>
  )
}

Hook Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | messages | string[] | Required | Messages to cycle through | | interval | number | 3000 | Milliseconds between messages | | loop | boolean | true | Loop back to first message | | autoStart | boolean | true | Start cycling immediately |

Hook Returns

| Property | Type | Description | |----------|------|-------------| | message | string | Current message | | index | number | Current message index | | isComplete | boolean | True if finished (when loop: false) | | start() | function | Start/resume cycling | | stop() | function | Pause cycling | | reset() | function | Reset to first message |


All Spinner Types

Circle (10 types)

circle · circle-fade · circle-dots · circle-pulse · circle-notch · circle-quarter · circle-half · circle-split · dual-ring · ring-resize

Dots (10 types)

dots-bounce · dots-fade · dots-pulse · dots-wave · dots-flashing · dots-elastic · dots-carousel · dots-scale · dots-orbit · dots-shuffle

Bars (6 types)

bars · bars-fade · bars-scale · bars-wave · bars-pulse · bars-rotate

Squares (8 types)

square-spin · square-fold · squares-grid · squares-shift · cube · cube-grid · blocks-wave · blocks-shuffle

Lines (4 types)

line-wobble · line-scale · line-wave · line-bounce

Creative (14 types)

heart-beat · hourglass · infinity · ripple · orbit · atom · dna · pacman · clock · gear · flower · spiral · windmill · seesaw

Progress (3 types)

progress-bar · progress-orbit · meter


Utilities

import { allSpinnerTypes, spinnerCategories } from '@flibbertigibbeting/loading-message'

// Array of all 55 spinner type names
console.log(allSpinnerTypes)
// ['circle', 'circle-fade', 'dots-bounce', ...]

// Types organized by category
console.log(spinnerCategories)
// { circle: [...], dots: [...], bars: [...], ... }

Accessibility

This library is built with accessibility in mind:

  • Screen reader support — Uses aria-live="polite" to announce loading state changes
  • Reduced motion — Respects prefers-reduced-motion automatically
  • Semantic HTML — Proper role and label attributes
  • Customizable labels — Override label prop for context-specific announcements
// Custom accessible label
<Spinner type="circle" label="Loading your dashboard" />

TypeScript

Full TypeScript support with exported types:

import type { 
  SpinnerType, 
  SpinnerProps, 
  LoadingMessageProps,
  UseLoadingMessageOptions 
} from '@flibbertigibbeting/loading-message'

Browser Support

Works in all modern browsers. Uses CSS animations with no JavaScript animation runtime.


License

MIT © flibbertigibbeting