React component for flipping book pages animation
Demo
https://namannehra.github.io/flipping-pages/
Installation
Supported React versions: ^16.14.0 || ^17.0.0 || ^18.0.0
NPM
npm install flipping-pages
Yarn
yarn add flipping-pages
Example
App.js
import { FlippingPages } from 'flipping-pages';
import 'flipping-pages/dist/style.css';
import { useState } from 'react';
import './App.css';
const App = () => {
const [selected, setSelected] = useState(0);
const back = () => {
setSelected(selected => Math.max(selected - 1, 0));
};
const next = () => {
setSelected(selected => Math.min(selected + 1, 2));
};
return (
<div>
<div className="pages">
<FlippingPages
direction="bottom-to-top"
onSwipeEnd={setSelected}
selected={selected}
>
<div className="page page1">Page 1</div>
<div className="page page2">Page 2</div>
<div className="page page3">Page 3</div>
</FlippingPages>
</div>
<button onClick={back}>Back</button>
<button onClick={next}>Next</button>
</div>
);
};
export default App;
App.css
.pages {
height: 256px;
width: 256px;
}
.page {
height: 100%;
width: 100%;
user-select: none;
touch-action: none;
}
.page1 {
background-color: pink;
}
.page2 {
background-color: yellow;
}
.page3 {
background-color: aqua;
}
Props
Name (* = Required) | Type | Default |
---|---|---|
animationDuration |
number |
400 |
children |
ReactNode |
|
containerProps |
HTMLAttributes<HTMLDivElement> |
|
containerRef |
Ref<HTMLDivElement> |
|
direction * |
'bottom-to-top' | 'top-to-bottom' | 'left-to-right' | 'right-to-left' |
|
disableSwipe |
boolean |
false |
noSwipeClass |
string |
|
onAnimationEnd |
() => void |
|
onAnimationStart |
() => void |
|
onAnimationTurn |
(selected: number) => void |
|
onOverSwipe |
(overSwipe: number) => number |
overSwipe => overSwipe / 4 |
onSwipeEnd |
(selected: number) => void |
|
onSwipeStart |
(event: PointerEvent<HTMLDivElement>) => boolean |
event => event.isPrimary |
onSwipeTurn |
(selected: number) => void |
|
perspectiveMultiplier |
number |
2 |
selected * |
number |
|
shadowBackground |
string |
'rgb(0, 0, 0, 0.25)' |
shadowComponent |
Component<ShadowProps> |
|
swipeLength |
number |
400 |
swipeSpeed |
number |
0.1 |
willChange |
boolean | 'auto' |
'auto' |
animationDuration
number
Time in milliseconds for one page turn. Set to 0
to disable animation.
children
ReactNode
Each child is rendered on a separate page.
containerProps
HTMLAttributes<HTMLDivElement>
Props passed to the root element.
containerRef
Ref<HTMLDivElement>
Ref for the root element.
direction
*
'bottom-to-top' | 'top-to-bottom' | 'left-to-right' | 'right-to-left'
Direction of page turn.
disableSwipe
boolean
Disables page turning by swiping.
noSwipeClass
string
Elements with this class (or their descendants) will not trigger page turn by swiping.
onAnimationEnd
() => void
Called after page turning animation ends.
onAnimationStart
() => void
Called after page turning animation starts.
onAnimationTurn
(selected: number) => void
Called on each tick of page turning animation. selected
is the page index in decimal. Uses
requestAnimationFrame
.
onOverSwipe
(overSwipe: number) => number
Called when swiping back on the first page or next on the last page. overSwipe
is between 0
and
1
. Return value determines how page turning is throttled.
onSwipeEnd
(selected: number) => void
Called after swiping ends. selected
is the page index to which user swiped.
onSwipeStart
(event: PointerEvent<HTMLDivElement>) => boolean
Called before swipe starts. event
is a
pointerdown
event. Swipe starts only if true
is returned. This can be used to disable swiping for certain
pointer types like mouse.
onSwipeTurn
(selected: number) => void
Called on each tick of swipe turn. selected
is the page index in decimal.
perspectiveMultiplier
number
Value of CSS perspective
is
calculated by multiplying perspectiveMultiplier
with the size of the root element. Size is height
or width depending on direction
. perspective
can be set manually using
containerProps.style.perspective
.
selected
*
number
Index of the current page. Decimal values are supported.
shadowBackground
string
Pages have a shadow when they are turning. Shadow has 0
opacity when page is resting and 1
opacity when page is half turned. shadowBackground
is used for CSS background
of the shadow
element.
shadowComponent
Component<ShadowProps>
ShadowProps
Name (* = Required) | Type |
---|---|
selected * |
number |
willChange * |
boolean |
Component to use as page shadow.
swipeLength
number
The distance in pixels user must swipe to completely one page turn.
swipeSpeed
number
Minimum speed in pixels per milliseconds to turn the page after a swipe.
willChange
boolean | 'auto'
Sets CSS will-change
on turning
page and shadow. If 'auto'
then will-change
is applied during turning animation and swiping.
Notes
user-select
You can set CSS user-select
to
prevent text selection when swiping using a mouse.
touch-action
You can set CSS touch-action
to
prevent page scrolling when swiping using a touch screen.
State is not synced
The web platform doesn't have a way to bend an element in half. To achieve this effect, this component renders each page twice. For the first render, only the first half of the page is visible. For the second render, only the last half of the page is visible. Then these halves are rotated independently to achieve the page turning effect.
If a child component has internal state then that state will not be synced between both the page renders. The same also applies to uncontrolled components.
Hire me
I'm looking for a full time job as a front end web dev. Email me at naman6469@pm.me.