Cube Scroll Menu

ProScroll3Dpowered by @vectorvesper/motion

A full-screen cube menu that rotates between sections as you scroll, with framer-motion overlays, configurable CTA and hint copy, and callbacks for both selection and open state. Seventeen props cover colour, labelling and behaviour.

Cube Scroll Menu

Included with membership

Members install Cube Scroll Menu with one command and get the full source, the usage code and the Framer remix, licensed for client work. One membership covers the whole library and the CLI.

When to use it

Primary navigation for a site with a handful of destinations, where the menu is meant to be an event. It suits eight to twelve entries; below that the drum barely turns, and well above it the wheel becomes a worse list than a list. It does not route on its own — you handle the navigation in onItemSelect.

  • Wire onItemSelect — without it the menu spins and settles but nothing happens when an entry is chosen.
  • Use onOpenChange to lock body scroll while the overlay is open, so the page behind does not move under it.
  • Keep titles short. Each one has a single face, and a long title wraps badly on a curved surface.
  • Raise zIndex above any fixed header, or the header floats over the overlay.

Avoid:

  • Do not use it as a link list. Only the settled entry is comfortably readable, so a visitor cannot scan the options.
  • Do not give two entries the same id — it keys the faces, and duplicates make the drum snap to the wrong one.
  • Do not lower snapDelay much below the default; the drum starts snapping out from under a slow scroll.

Props

A full-screen navigation overlay whose entries sit on the faces of a turning drum. Scroll or drag to spin it, and it settles on the nearest entry when you stop. Opens from a button you control.

<CubeScrollMenu />

The overlay and its trigger.

PropTypeDefaultDescription
items*CubeMenuItem[]—The entries, in order. Required — nothing renders without it.
onItemSelect(item: CubeMenuItem, index: number) => void—Fires when an entry is chosen. This is where you navigate; the component does not route on its own.
onOpenChange(open: boolean) => void—Fires whenever the overlay opens or closes, so surrounding UI can respond — locking scroll, dimming a header.
ctaLabelstring"Explore"Text on the button that opens the menu.
hintTextstring"Scroll to navigate"Line shown inside the overlay telling people how to move the drum.
overlayColorstring"#050507"Backdrop behind the drum.
showDotsbooleantrueShows a position indicator alongside the drum.
zIndexnumber50Stacking order of the overlay. Raise it if a fixed header sits on top.
classNamestring""Appended to the overlay's root.
faceHeightnumber80Height of one face in pixels, which sets how large each entry is and how far the drum turns between them.
sliceCountnumber4How many faces are visible around the drum at once. More shows further ahead and behind; fewer reads as a tighter wheel.
wheelSensitivitynumber0.35How far one wheel tick turns the drum.
dragSensitivitynumber0.55The same, for pointer drags. Higher than the wheel default by design.
rotationDampingnumber9How quickly the drum stops coasting. Higher settles sooner; lower keeps spinning after you let go.
snapDelaynumber160Milliseconds of stillness before it snaps to the nearest entry. Raise it if snapping interrupts a slow scroll.
openDurationnumber0.85Seconds the overlay takes to open.
closeDurationnumber0.6Seconds it takes to close.

<CubeMenuItem />

type

One entry on the drum.

PropTypeDefaultDescription
id*string | number—Stable key for the entry.
title*string—The entry itself. Kept short — it has one face to sit on.
image*string—Picture shown alongside the entry.
categorystring—Optional small label above the title.
descriptionstring—Optional supporting line.
The drum keeps spinning under reduced motion. If that matters, shorten openDuration and closeDuration and raise rotationDamping when the preference is set.
Client component. It reads the wheel and the pointer, so it has to run in the browser.
Back to all components