Skip to content
WANCRAFT

H.923D & Experimental

Paper Fold

A panel that folds and unfolds like paper: 3D accordion creases with shading, toggled or scrubbed.

NewReactMotionCSSTailwindadvanced

Overview

Paper Fold turns any panel into a sheet of paper. While it moves, the content is drawn as N clipped copies on nested 3D segments that hinge on each other with alternating rotateX (or rotateY) angles, so the sheet zigzags open with crease shading that deepens as it folds. Once fully unfolded, the single real copy of the content is shown: crisp, selectable and interactive. A button with aria-expanded toggles it, and dragging the button scrubs the fold by hand before snapping to the nearest state. Folded content is inert, and reduced motion switches instantly.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/paper-fold.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/paper-fold.json

Method 02 · Copy and paste

  1. 1. Install the dependencies below.
  2. 2. Copy the source from the Code tab into components/ui/paper-fold.tsx.
  3. 3. Import it and adjust props.
npm install motion
Dependencies
motion
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { PaperFold } from "@/components/ui/paper-fold";

export function PaperFoldExample() {
  return (
    <PaperFold className="max-w-sm">
      <div className="p-6">
        <p className="font-medium">Order #0412</p>
        <p className="text-sm text-zinc-500">2 items · RM 128.00</p>
      </div>
    </PaperFold>
  );
}

03Props

PropTypeDefaultDescription
childrenReactNode—The paper's content. Interactive only when fully unfolded.
foldsnumber5Accordion segments (2–12).
durationnumber900Fold / unfold duration in ms.
direction"vertical" | "horizontal""vertical"Fold along the height or the width.
shadingnumber0.5Crease shading strength, 0–1.
scrubbooleantrueDrag the toggle to scrub the fold; it snaps to the nearest state on release.
accentstring"#FF7448"Toggle focus ring and grip colour.
expandedboolean—Controlled state.
defaultExpandedbooleanfalseInitial state (uncontrolled).
onExpandedChange(expanded: boolean) => void—Called when the toggle or a scrub changes the state.
openLabelstring"Unfold"Toggle label while folded.
closeLabelstring"Fold"Toggle label while unfolded.
paperClassNamestring"bg-white text-zinc-900 dark:bg-zinc-900 dark:text-zinc-100"Paper surface classes for every segment and the unfolded content.
...propsHTMLAttributes<HTMLDivElement>—Forwarded to the root (a flex column holding the paper and the toggle).

04Features

  • 01Nested 3D segments with alternating ±φ angles: a true accordion zigzag
  • 02Crease shading that deepens with the fold angle
  • 03Single crisp, interactive copy of the content when unfolded
  • 04Toggle with aria-expanded; drag the toggle to scrub, snaps on release
  • 05Vertical or horizontal folding, 2–12 segments
  • 06Measured with ResizeObserver; the footprint follows the cosine of the fold
motion · tweeninput · clickinput · draginput · keyboard

05Accessibility

  • The toggle is a real button with aria-expanded and aria-controls pointing at the content.
  • Folded (and mid-fold) content is inert: not focusable and hidden from assistive tech until fully unfolded.
  • The folding copies are aria-hidden and inert, so content is never announced twice.
  • prefers-reduced-motion folds and unfolds instantly; scrubbing still follows the pointer.
  • Keyboard: Tab to the toggle, Enter or Space to fold / unfold.

06Limitations

  • While folding, children are rendered once per segment: avoid ids, autoplaying media or side-effectful components inside.
  • Content changes size only when unfolded; height is re-measured with ResizeObserver.