ZYVOPMulti-Platform Sync
SeriesAI NewsWhy ZyVOPJoin Discord
LoginGet Started
ZYVOPMulti-Platform Sync

The Developer Publishing Hub. Write once, publish everywhere, and make your work citation-ready with built-in SEO, AEO, and GEO discovery support. Zero reader paywalls.

Content

  • Categories
  • Tags
  • Badges
  • Leaderboard
  • Write Article
  • Newsletter

Company

  • About Us
  • Why ZyVOP
  • Developer API & CLI
  • Write for Us
  • Contact

Connect

  • Privacy Policy
  • Terms of Service
  • Cookie Policy
  • DMCA Policy
  • Code of Conduct

© 2026 ZyVOP. Developer Publishing Hub.

Zero paywalls · Full content ownership
All systems operational
HomeMantine Book — Grab Any Edge, Turn Any Page

Mantine Book — Grab Any Edge, Turn Any Page

Giovambattista Fazioli
Giovambattista Fazioli
Senior Full-stack Engineer, Lead DeveloperSupport
September 4, 2026
5 min read
Mantine Book — Grab Any Edge, Turn Any Page
#nextjs#react#TypeScript#webcomponents

A realistic iBooks-style book for React built on Mantine: stack two-sided pages and turn them by dragging any point of the free edge — a pure-DOM reflection fold by default, a true 3D WebGL curl when you want it.

Introduction

Most page-flip libraries cheat: you can only grab the corner, and the fold is a special-cased animation that falls apart the moment you drag somewhere unexpected. This component started from the opposite question — what's the general math of a turning page? The answer is a perpendicular-bisector reflection fold: the grabbed point folds exactly onto your pointer, and the crease is computed from that single constraint. One code path covers every grab point and every drag direction — corner, mid-edge, upward, downward, forward, back. The classic corner turn is just the special case.

What is Mantine Book?

@gfazioli/mantine-book renders a realistic, interactive book: a stack of two-sided pages you turn like real paper. Drag the right half to go forward and the left half to go back, or drive it programmatically through a controlled page state — arrows, dots, sliders, keyboard, anything.

Mantine Book

It ships two rendering paths. The default flat variant is a pure DOM + CSS reflection fold — SSR-safe, zero canvas, interactive from the first paint. The opt-in rounded variant draws a true 3D curl on a WebGL canvas, with the page wrapping around the crease and a soft specular ridge along the bend. If WebGL is unavailable or a face snapshot fails, rounded degrades to flat automatically — opting in is always safe.

Any JSX goes inside a page face — text, images, MDX, even live components. Faces are rendered once by React (no innerHTML cloning), so the event handlers inside your pages stay alive.

✨ Key Features

Compound API or data-driven pages

Compose pages declaratively, or hand the book an array — same result:

<Book width={260} height={360}><Book.Page>
    <Book.Page.Front>Front of page 1</Book.Page.Front>
    <Book.Page.Back>Back of page 1</Book.Page.Back></Book.Page></Book>

Enter fullscreen mode Exit fullscreen mode

const pages: BookPageData[] = [{ front: <Cover />, back: <TableOfContents /> },{ front: <Chapter n={1} />, back: <Chapter n={2} /> },];

<Book width={260} height={360} pages={pages} />

Enter fullscreen mode Exit fullscreen mode

Grab anywhere, drag anywhere

The fold is a perpendicular-bisector reflection: the crease is derived from the segment between the grab point and the pointer, so the page follows your finger exactly — from any point of the free edge, in any direction. Releases settle naturally: past flipThreshold (or with a quick side-aware swipe) the turn completes; otherwise the page snaps back.

Two renderers: flat and rounded

// Pure DOM reflection fold — the default, SSR-safe<Book variant="flat" /* ... */ />

// True 3D WebGL curl with a lit specular ridge<Book variant="rounded" curlRadius={90} /* ... */ />

Enter fullscreen mode Exit fullscreen mode

The WebGL layer is lazy: it loads only when a rounded curl actually mounts, so flat users pay nothing. The whole book shares a single pooled WebGL context, no matter how many pages it has.

Controlled navigation with face-based indices

Page i has its front at face 2i and its back at 2i + 1 — face 0 is the closed book. Programmatic turns animate like a real drag:

const [page, setPage] = useState(0);

<Book page={page} onPageChange={setPage} pages={pages} /><Button onClick={() => setPage((p) => p + 2)}>Next spread</Button>

Enter fullscreen mode Exit fullscreen mode

Riffle through big jumps

Jumping several pages at once doesn't teleport — the book riffles through every page in between, with the total time budget compressed into riffleDuration (default 1000ms) and turns queued one page in flight at a time. Wire it to a slider and scrub through a 100-page book.

Hard covers

<Book withCover pages={pages} />

Enter fullscreen mode Exit fullscreen mode

With withCover, the first and last pages turn rigid around the spine — no curl, like the board of a hardcover — and the closed book is compact: centered on the play-zone, sliding into the two-page spread as the cover opens (the slide respects prefers-reduced-motion).

Reveal layers

revealBackground on the Book paints the inside cover — visible where no page rests and in the area a turning page uncovers. The same prop on a single Book.Page adds a side-aware layer under that page only.

Accessible by default

Keyboard turns (arrow keys, Home, End), a polite screen-reader live region announcing the visible pages (customizable via pageAnnouncement), and reduced-motion support throughout.

🚀 Getting Started

yarn add @gfazioli/mantine-book
# or
npm install @gfazioli/mantine-book

Enter fullscreen mode Exit fullscreen mode

import '@gfazioli/mantine-book/styles.css';import { Book } from '@gfazioli/mantine-book';

export function Demo() {return (
    <Book width={260} height={360}>
      <Book.Page>
        <Book.Page.Front>Hello</Book.Page.Front>
        <Book.Page.Back>World</Book.Page.Back>
      </Book.Page>
    </Book>);}

Enter fullscreen mode Exit fullscreen mode

That's a working, draggable book. The play-zone is twice the page width: the sheet rests in the right half and sweeps left as it turns.

Props & API

The essentials, in context:

<Bookvariant="rounded"        // 'flat' (default) | 'rounded'width={300}              // page width in px (default 300)height={600}             // page height in px (default 600)page={page}              // controlled face index (or defaultPage)onPageChange={setPage}   // reports the first visible face after a turnflippingTime={600}       // programmatic turn duration, msriffleDuration={1000}    // total budget for multi-page riffles, msturnOrigin="bottom"      // 'top' | 'middle' | 'bottom' — corner arc of programmatic turnswithCover                // rigid first/last pages + compact closed bookrevealBackground="gray.2" // inside-cover base (MantineColor or CSS color)curlRadius={90}          // rounded-variant curl tightnessshadowOpacity={0.5}      // fold shadow strength (0 disables)pageBackground="white"   // page base color behind your contentdisabled={false}         // turn off dragging/>

Enter fullscreen mode Exit fullscreen mode

Gesture tuning: flipThreshold (px to commit a release, default 50), swipeDistance / swipeTimeThreshold (quick-swipe detection, 30px / 250ms), and mobileScrollSupport (default true — vertical scrolling keeps working on touch until a horizontal gesture claims the pointer).

Every visual and gesture prop set on the Book cascades to all pages via context — and any individual Book.Page can override it locally:

<Book variant="rounded" shadowOpacity={0.3} pages={pages}>{/* …except this one, which stays flat and shadowless */}<Book.Page variant="flat" shadowOpacity={0} /* … */ /></Book>

Enter fullscreen mode Exit fullscreen mode

For advanced consumers, the pure page-index math (faceToTurnedPages, turnedPagesToFace) and the fold geometry types (Point, ReflectionFold, TurnOrigin) are exported too.

🎨 Styling

Full Mantine Styles API on both levels. The Book exposes root and page selectors; each page exposes root, restSheet, curlSheet, shadowLayer, revealLayer and face, plus CSS variables (--curl-page-width, --curl-page-height, --curl-page-background, --curl-shadow-color, --curl-reveal-background):

<BookclassNames={{ root: 'my-book' }}styles={{ page: { borderRadius: 8 } }}pages={pages}/>

Enter fullscreen mode Exit fullscreen mode

Colors accept any MantineColor ("dark.9", "gray.2") or raw CSS value — theme-aware out of the box.

⚡ Performance

  • Quiescent at rest — no perpetual requestAnimationFrame; the rAF loop runs only during a drag or the release settle.

  • Lazy WebGL — the rounded renderer and its snapshot dependency load on first use; an untouched book costs zero GPU contexts.

  • One context per book — the turn queue guarantees a single page in flight, so the whole stack shares one pooled WebGL context.

  • Memoized stack — a turn re-renders the handful of pages involved, not all N.

Live Demo & Documentation

The documentation site has interactive configurators for every feature — variants, curl radius, covers, riffle, gestures, events — where the displayed code regenerates live from the controls you touch:

→ gfazioli.github.io/mantine-book

Links

  • 📦 npm: @gfazioli/mantine-book

  • 📖 Documentation: gfazioli.github.io/mantine-book

  • 🔗 GitHub: gfazioli/mantine-book

  • 🦄 Mantine Extensions Hub

Comments (0)

Login to post a comment.

Giovambattista Fazioli
Giovambattista Fazioli

Senior Full-stack Engineer, Lead Developer

Italian Senior Full-stack Engineer and Lead Developer on the Cloud team at Namecheap. I build developer tools, React/Mantine UI components and native macOS apps — mostly open source. I work across TypeScript, Next.js, Go and SwiftUI, and I've been coding since the Commodore/Assembly days. Creator of WP Bones and 25+ Mantine extensions, and maintainer of the Undolog open-source studio.

Support
Subscribe to Giovambattista Fazioli's Newsletter

More from Giovambattista Fazioli

View profile

FinderGit 0.29.0 — open a commit like a folder

There’s a moment, reading a commit list, where you want to know one small thing: which files did that one touch?

3 minSep 4

Netfox 0.18.0 — is it my connection, or the internet?

There is a question that comes up every time something feels slow, and until now Netfox could not...

3 minSep 4

Netfox — The macOS app that never loses track of your network

I built Netfox because every existing answer to "what's actually on my network?" annoyed me. The...

5 minSep 4

Audio That Sees Itself

A Mantine-native audio player for React with waveform visualisation and a live spectrum analyser,...

5 minSep 4

The Player, the Pieces, and the Hook

A Mantine-native video player for React that ships as three layers in one package: a polished...

6 minSep 4