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

v1.0.3

Published

A lightweight React component for realistic page-flip animations, featuring built-in navigation controls, full TypeScript support, and easy style customization.

Downloads

175

Readme

react-magazine

React component for creating realistic magazine-style page flip animations with built-in controls and full TypeScript support.

Demo

react-magazine demo

Installation

npm install react-magazine

Quick Start

import { MagazineBook, Page } from 'react-magazine';

const images = [
  "https://picsum.photos/id/1/400/500",
  "https://picsum.photos/id/2/400/500",
  "https://picsum.photos/id/3/400/500",
  "https://picsum.photos/id/4/400/500",
  "https://picsum.photos/id/5/400/500",
  "https://picsum.photos/id/6/400/500",
];

function App() {
  return (
    <MagazineBook width={400} height={500} showCover={true} showControls={true}>
      {images.map((img, index) => (
        <Page key={index} number={index + 1}>
          <img
            src={img}
            alt={`Page ${index + 1}`}
            style={{ width: "100%", height: "100%", objectFit: "cover" }}
          />
        </Page>
      ))}
    </MagazineBook>
  );
}

export default App;

Features

  • Realistic page flip animation
  • Built-in navigation controls
  • Hard/soft page density support
  • Responsive design (fixed/stretch modes)
  • Portrait and landscape orientation
  • Touch and mouse support
  • TypeScript support
  • SSR compatible (with dynamic import)
  • Zero configuration - styles are built-in

Using the useFlipBook Hook

import { MagazineBook, Page, useFlipBook } from 'react-magazine';

const images = [
  "https://picsum.photos/id/1/400/500",
  "https://picsum.photos/id/2/400/500",
  "https://picsum.photos/id/3/400/500",
  "https://picsum.photos/id/4/400/500",
];

function App() {
  const { bookRef, state, flipNext, flipPrev, handlers } = useFlipBook();

  return (
    <div>
      <MagazineBook ref={bookRef} width={400} height={500} {...handlers}>
        {images.map((img, index) => (
          <Page key={index} number={index + 1}>
            <img
              src={img}
              alt={`Page ${index + 1}`}
              style={{ width: "100%", height: "100%", objectFit: "cover" }}
            />
          </Page>
        ))}
      </MagazineBook>
      <div>
        <button onClick={() => flipPrev()}>Previous</button>
        <span>Page {state.currentPage + 1} of {state.pageCount}</span>
        <button onClick={() => flipNext()}>Next</button>
      </div>
    </div>
  );
}

export default App;

Props

MagazineBook Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | width | number | 400 | Page width in pixels | | height | number | 300 | Page height in pixels | | size | 'fixed' \| 'stretch' | 'fixed' | Size mode | | startPage | number | 0 | Starting page index | | showCover | boolean | false | Makes first & last pages hard (like book covers) | | showControls | boolean | false | Show built-in navigation controls | | drawShadow | boolean | true | Draw shadow when flipping | | flippingTime | number | 1000 | Flip animation duration (ms) | | usePortrait | boolean | false | Use portrait mode | | mobileScrollSupport | boolean | true | Enable mobile scroll | | swipeDistance | number | 30 | Swipe distance threshold | | showPageCorners | boolean | true | Show page corner fold on hover | | disableFlipByClick | boolean | false | Disable click to flip | | clickEventForward | boolean | true | Forward click events to children | | useMouseEvents | boolean | true | Enable mouse/touch events | | maxShadowOpacity | number | 1 | Shadow intensity (0-1) | | autoSize | boolean | true | Auto-resize based on container | | isLoading | boolean | false | Show loading state | | disabled | boolean | false | Disable all interactions | | controlsClassName | string | '' | Custom class for controls | | controlsStyle | CSSProperties | {} | Custom style for controls |

Event Props

| Prop | Type | Description | |------|------|-------------| | onFlip | (e: FlipEvent) => void | Called when page flips | | onChangeState | (e: StateEvent) => void | Called when state changes | | onChangeOrientation | (e: OrientationEvent) => void | Called when orientation changes | | onInit | (e: FlipEvent) => void | Called when initialized | | onUpdate | (e: FlipEvent) => void | Called when updated |

Page Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | number | number | - | Page number (for display) | | density | 'soft' \| 'hard' | 'soft' | Page density (soft bends, hard doesn't) | | className | string | '' | Custom class | | style | CSSProperties | {} | Custom style |

showCover Behavior

When showCover={true}:

  • First page automatically becomes hard (doesn't bend)
  • Last page automatically becomes hard (doesn't bend)
  • All inner pages remain soft (paper flip effect)
import { MagazineBook, Page } from 'react-magazine';

function App() {
  return (
    <MagazineBook showCover={true}>
      <Page>Front Cover (auto hard)</Page>
      <Page>Page 2 (soft - bends)</Page>
      <Page>Page 3 (soft - bends)</Page>
      <Page>Back Cover (auto hard)</Page>
    </MagazineBook>
  );
}

export default App;

Ref API Methods

Access via bookRef.current:

| Method | Description | |--------|-------------| | flipNext(corner?) | Flip to next page | | flipPrev(corner?) | Flip to previous page | | flip(pageNum, corner?) | Flip to specific page with animation | | turnToPage(pageNum) | Jump to page without animation | | getCurrentPageIndex() | Get current page index (0-based) | | getPageCount() | Get total page count | | getOrientation() | Get current orientation | | getState() | Get current state | | pageFlip() | Get underlying PageFlip instance |

useFlipBook Hook

Returns:

| Property | Type | Description | |----------|------|-------------| | bookRef | RefObject | Ref to attach to MagazineBook | | state | object | { currentPage, pageCount, orientation, pageState, isFlipping } | | flipNext | function | Flip to next page | | flipPrev | function | Flip to previous page | | flipTo | function | Flip to specific page | | turnTo | function | Jump without animation | | canFlipNext | function | Check if can flip next | | canFlipPrev | function | Check if can flip prev | | handlers | object | Event handlers to spread on MagazineBook |

Next.js Usage

import dynamic from 'next/dynamic';

const MagazineBook = dynamic(
  () => import('react-magazine').then((mod) => mod.MagazineBook),
  { ssr: false }
);

const Page = dynamic(
  () => import('react-magazine').then((mod) => mod.Page),
  { ssr: false }
);

function App() {
  return (
    <MagazineBook width={400} height={500} showControls>
      <Page number={1}>Page 1</Page>
      <Page number={2}>Page 2</Page>
    </MagazineBook>
  );
}

export default App;

TypeScript

All types are exported:

import type {
  PageFlipInstance,
  IFlipSetting,
  IEventProps,
  PageProps,
  FlipEvent,
  OrientationEvent,
  StateEvent,
  PageDensity,
  PageOrientation,
  PageState,
  FlipCorner,
  SizeType,
} from 'react-magazine';

License

MIT