useCanvas
The engine behind the canvas component. It tracks a camera
(x, y, scale) and wires up pan, wheel + pinch zoom, spacebar grab, marquee
selection, keyboard zoom shortcuts and fit-to-content, all via
requestAnimationFrame, with no dependencies. Most of the time you'll use
<Canvas> rather than the hook directly.
Pan · zoom · select
Scroll or two-finger drag to pan. Pinch or ⌘/Ctrl + scroll to zoom. Drag on empty space to marquee-select cards.
Another card
And another
Installation
npx shadcn@latest add https://canvas.blode.co/r/use-canvas.jsonUsage
const { containerRef, contentRef, cursorMode, handlers, initialStyle } =
useCanvas({ initial: { scale: 0.85, x: 0, y: 0 } });
return (
<div className="fixed inset-0" ref={containerRef} {...handlers}>
<div className="origin-top-left" ref={contentRef} style={initialStyle}>
{children}
</div>
</div>
);Options
| Prop | Type | Default | Description |
|---|---|---|---|
| initial | Partial<{ x; y; scale }> | — | Starting camera. Scale defaults to 0.85, x/y to 0. |
| onCameraSettle | (state) => void | — | Fires after pan/zoom settles, with the final camera. |
| onSelectionChange | (rect | null) => void | — | Fires while a marquee is being dragged. |
| onSelectionEnd | (rect | null) => void | — | Fires when the marquee gesture ends. |
Returns
| Prop | Type | Default | Description |
|---|---|---|---|
| containerRef | Ref<HTMLDivElement> | — | Attach to the fixed viewport element. |
| contentRef | Ref<HTMLDivElement> | — | Attach to the transformed content layer. |
| handlers | PointerEventHandlers | — | Spread onto the container to enable pan/zoom/select. |
| initialStyle | CSSProperties | — | Initial transform for the content layer. |
| cursorMode | "default" | "grab" | "grabbing" | "crosshair" | — | Current cursor state for the viewport. |
| animateTo | (target, duration?) => void | — | Animate the camera to a target state. |
| fitToContent | () => void | — | Frame all `[data-card-id]` children in the viewport. |