Sketchbook
A page-turning sketchbook for React — a book you drag to turn, built from DOM and CSS 3D transforms. No WebGL, no dependencies beyond react/react-dom. It renders a full book: cover, binding, paper texture, page-turn physics, an optional magnifying loupe, and a larger lightbox view, all themeable through CSS custom properties.
Installation
pnpm dlx shadcn@latest add https://kagadmodyaa.vercel.app/r/sketchbook.jsonNeeds a React + Tailwind project set up with shadcn. Copies the component source straight into your project, so you can edit it.
Usage
import { Sketchbook } from '@kagadmodyaa/sketchbook'
import '@kagadmodyaa/sketchbook/style.css'
<Sketchbook
pages={[
{ spread: '/pages/01-title.webp', alt: 'Title page' },
{ left: '/pages/02a.webp', right: '/pages/02b.webp', alt: 'Floor plan and section' },
]}
book={{ binding: 'spiral', cover: { title: 'Portfolio' } }}
/>Pages
Each entry in pages is one opening of the book — what you see when it lies open, two pages side by side.
spread lays one image across both pages, split at the fold. Use this for an exported landscape portfolio page. For the default square page shape, export spreads at 2:1 — e.g. 2400×1200.
left / right give a separate image to each side; either may be left out.
Images are never cropped by default — imageFit: 'contain' shows every image whole, with paper around it if its shape differs from the page.
Options
Every book option.
| Name | Type | Default | Description |
|---|---|---|---|
| pageShape | 'portrait' | 'square' | 'landscape' | 'square' | Shape of one page. Square opens to a 2:1 spread. |
| binding | 'spiral' | 'wire-o' | 'stitched' | 'coptic' | 'glued' | 'stitched' | spiral: one continuous coil · wire-o: twin wire loops · stitched: sewn signatures (thread in the fold) · coptic: exposed chain stitch across the spine · glued: perfect-bound, a deep fold, nothing visible. |
| bindingColor | string | — | Wire colour (spiral, wire-o) or thread colour (stitched, coptic). |
| paper | string (any CSS colour) | '#f2ede3' | Paper colour. Page images are printed onto it (dark papers switch that off). |
| paperTexture | 'cold-press' | 'hot-press' | 'smooth' | 'kraft' | 'dotted' | 'grid' | 'none' | 'cold-press' | cold-press: toothy watercolour paper · hot-press: fine and smooth · smooth: plain · kraft: fibrous · dotted: dot-grid sketchbook · grid: squared sketchbook · none: flat colour. |
| printOnPaper | boolean | true | When true, whites in your images take the paper colour (looks printed). |
| imageFit | 'contain' | 'cover' | 'contain' | 'contain' shows every image whole, with paper around it if its shape differs from the page. 'cover' fills the page and trims the rest. |
| cover | CoverOptions | false | false | The book starts closed on this cover. false starts open. |
| ribbon | string | false | false | Ribbon bookmark colour, or false for none. |
| intro | boolean | true | Open the cover and riffle through to openAt when the page loads. |
| openAt | number | 1 | Which opening (1 = first page in pages) to settle on after the intro. |
| loupe | boolean | true | Draggable magnifying glass (desktop only). |
| captions | boolean | true | Show page captions under the book. |
| tabs | boolean | true | Coloured index tabs on the page edge, one per project. |
| maxHeight | string (CSS length) | '72vh' | Largest height the book may take. |
Props
| Name | Type | Default | Description |
|---|---|---|---|
| pages | SketchbookPage[] | — | The openings of the book. Each is { alt, caption?, project? } plus either spread or left/right. |
| book | BookOptions | {} | Look and behaviour of the book — see Options below. |
| projects | SketchbookProject[] | [] | { slug, title, color? }[]. Lets pages link to a project (for tabs and the lightbox). |
| className | string | — | Extra class on the root <section>. |
| label | string | 'Sketchbook' | Accessible label for the book (aria-label). |
| onEvent | (event: SketchbookEvent) => void | — | Fires on page turns ({ type: 'turn', opening, total }) and opens ({ type: 'open', opening, side }). |
| onPageClick | (opening, side) => boolean | void | — | Called when a page is clicked or tapped. Return true to stop the built-in lightbox from opening. |
| projectHref | (slug: string) => string | — | Href for a project, used by the lightbox's "View project" link. |
Keyboard & accessibility
- Arrow keys turn pages when the book has focus.
+/-/0zoom the book.- Enter opens the larger lightbox view of the focused page.
- Every image needs meaningful
alttext, used for screen readers and search. prefers-reduced-motionswaps page turns for a fade.
Built from DOM and CSS 3D transforms, no WebGL. MIT licensed — free to use, change and share.