# @P5-wrapper/react: hosting a p5 sketch inside a React tree

> @P5-wrapper/react is a small React component that runs a p5.js sketch as a canvas element, forwards React props into the sketch through updateWithProps, and ships TypeScript types for the sketch function and its props. Version 5 renamed the component and raised the peer dependency floors to p5 2 and React 19, so an upgrade is a code change as well as a version bump.

**P5-wrapper/react** — A wrapper component that allows you to utilise P5 sketches within React apps.

- Repository: https://github.com/P5-wrapper/react
- Website: https://p5-wrapper.github.io/react/
- Stars: 566 · Forks: 51
- Language: TypeScript
- License: MIT
- Published: 2026-10-22 · Updated: 2026-10-22 · Language: en
- Canonical page: https://hysenlabs.com/projects/p5-wrapper-react

## A component that owns the canvas and hands you a p5 instance

P5.js sketches are written as functions that receive a p5 instance and assign to its setup and draw hooks. React components are written as functions that return elements. @P5-wrapper/react is the small piece of glue between the two: a component, P5Canvas, that takes a sketch function as a prop and renders the canvas that the sketch draws into.

The value of that glue is in the boundary it manages. p5 owns an animation loop and a canvas element, React owns a tree, and the two have different ideas about when work happens. The wrapper's job is to start the sketch when the component mounts, keep the p5 instance in step with the props the sketch receives, and clean up when the component goes away. The public surface reflects that narrow purpose: a sketch prop, arbitrary custom props, and an optional updater callback.

The package is small by design. The published files are only the README and dist/component, with the type definitions at dist/component/main.d.ts, the CommonJS entry at dist/component/main.cjs and the ES module entry at dist/component/main.mjs, all exposed through an exports map that points each condition at the right file. The source tree is TypeScript, the licence is MIT, and the maintained version is 5.0.4, with 5.0.3 released on 2026-04-11 and 5.0.2 on 2025-12-13. The last push to the repository was on 2026-10-01, and the project publishes a documentation site at p5-wrapper.github.io/react along with a live demo at the same address.

## Version 5 renamed the component and raised the peer floors

The v5 release was a breaking change, and the migration notes are explicit about the three things that changed.

The component itself was renamed. ReactP5Wrapper became P5Canvas, which is a better name for something that renders a canvas element, but it means every import site in your application changes. The type names moved with it: P5WrapperProps became P5CanvasProps, and P5WrapperClassName became CanvasContainerClassName. The class name prop is the one that affects styling, since it is how a consumer targets the container element the wrapper puts around the canvas.

The peer dependency floors moved as well. p5 has to be 2.0.0 or newer, react has to be 19.0.0 or newer, and react-dom has to be 19.0.0 or newer. These are peer dependencies rather than direct dependencies, so the wrapper does not pull them in for you: the application decides which versions it installs, and the wrapper is written against the new ones. A team still on React 18 is not able to move to version 5 of this package without moving React as well, which is the real upgrade cost rather than the rename.

If you are still on version 4, the documentation for it is kept in the repository at the v4.4.1 tag, so the older API remains readable while you plan the move.

## Installing the package and running your first sketch

The install is a single command, and the choice of package manager is left to you:

```shell
[npm|yarn|pnpm] [install|add] p5 @p5-wrapper/react
```

p5, react and react-dom are peer dependencies, so all three have to be present in your project. The TypeScript story is short because p5 ships its own type definitions, so no separate @types package is needed and the compiler picks the types up from the p5 package automatically.

The sketch itself is a plain function. Assign to p5.setup to create the canvas, assign to p5.draw for the per frame work, and hand the function to the component:

```jsx
import * as React from "react";
import { P5Canvas } from "@p5-wrapper/react";
function sketch(p5) {
  p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
  p5.draw = () => {
    p5.background(250);
    p5.plane(100);
  };
}
export function App() {
  return <P5Canvas sketch={sketch} />;
}
```

The canvas size, 600 by 400 here, and the renderer, WEBGL, are chosen in your sketch rather than by the wrapper, so the wrapper does not impose a canvas size on you. If you prefer to keep the setup and draw bodies in separate functions, the documented pattern is to have them return the actual hook functions, and the sketch function then assigns them, which keeps a long draw routine out of the component file.

To see the examples, the repository ships a demo application with its own sketches. Clone it, install with pnpm and start the dev server:

```sh
git clone git@github.com:<your username>/react.git
cd react
pnpm install
pnpm dev
```

The dev server serves the demo on http://localhost:5173.

## Driving a sketch from React state with updateWithProps

The interesting part of the wrapper is how React state reaches a running animation loop. You can pass any custom props to P5Canvas, and they are forwarded to an updateWithProps method that you define on the sketch. That method is called on the initial render and again whenever the props change, which is the mechanism that lets a React value change the behaviour of a sketch that is otherwise driven by its own frame loop.

The pattern is a closure over a variable that the draw function reads:

```jsx
import { P5Canvas } from "@p5-wrapper/react";
import React, { useEffect, useState } from "react";
function sketch(p5) {
  let rotation = 0;
  p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
  p5.updateWithProps = props => {
    rotation = (props.rotation * Math.PI) / 180;
  };
}
export function App() {
  const [rotation, setRotation] = useState(0);
  return <P5Canvas sketch={sketch} rotation={rotation} />;
}
```

The direction of travel is one way, from React into the sketch. The wrapper does not ask the sketch to push values back, and the p5 instance is not a React state container. That is deliberate, and it keeps React out of the frame loop, but it also means a sketch cannot set a React value on every frame without the cost of a render per frame, which is where the updater prop comes in.

The updater prop receives a callback that runs alongside updateWithProps on every props change but lives in the React layer, and the documented use is exactly the case the props channel cannot cover: reading frameCount or other instance properties to drive React state.

## Sketch, P5CanvasInstance and SketchProps for typed sketches

TypeScript support is the part of the package that has grown since version 4, and there are two ways to type a sketch. The Sketch type auto-types the p5 argument for you, so the sketch function is written as a typed constant. The P5CanvasInstance type is the plain instance type, for people who prefer a regular function declaration.

The typed constant version looks like this:

```tsx
import { P5Canvas, Sketch } from "@p5-wrapper/react";
const sketch: Sketch = p5 => {
  p5.setup = () => p5.createCanvas(600, 400, p5.WEBGL);
  p5.draw = () => {
    p5.background(250);
    p5.plane(100);
  };
};
```

For props, the package exports a SketchProps type, and generics are what tie the props you pass to the props your sketch expects:

```tsx
import { P5Canvas, Sketch, SketchProps } from "@p5-wrapper/react";
import React, { useEffect, useState } from "react";
type MySketchProps = SketchProps & {
  rotation: number;
};
```

MySketchProps is declared here as an intersection with SketchProps, and the documentation also shows the equivalent interface form that extends SketchProps. The same generics work with P5CanvasInstance if you prefer that form. The practical value is that updateWithProps stops being an untyped any: the props parameter of the callback is typed from the generic you declared, so a renamed prop or a wrong number type shows up at compile time rather than as a silent no-op in the sketch.

## Next.js, the pnpm workspace and the demo project

Server rendering is the case the package explicitly steps aside for. For Next.js applications the documentation points to a separate dynamic implementation published as @p5-wrapper/next, which is installed alongside the React wrapper and p5:

```shell
[npm|yarn|pnpm] [install|add] p5 @p5-wrapper/next @p5-wrapper/react
```

The reasoning is straightforward once you look at what a p5 sketch does: it touches the document and the canvas at mount time, so a component that does that cannot be rendered on the server without a dynamic boundary. The separate package supplies that boundary rather than making every consumer of the base wrapper configure one.

The repository itself is a pnpm workspace, with pnpm-workspace.yaml and pnpm-lock.yaml at the top level, and the package manifest declares pnpm as its package manager at version 12.3.4. The tree is split into src/ for the component, demo/ for the demo application with its own app.jsx, demo.css, index.html and sketches directory, config/ for the build and tooling configuration, tests/, and tsconfig.json. The demo is a separate workspace package rather than a folder inside the component, which is why the build produces a demo bundle as well as the library.

There is also a tests/ directory and a Vitest based test command, and the build scripts separate the two outputs: the component is compiled with tsc and then bundled with Vite in library mode, while the demo is built with Vite in demo mode.

## MIT licensing, Node 24 and the release cadence

The licence is MIT, and for a component of this size that removes the usual questions about embedding it in a commercial product. There is no copyleft obligation and no attribution requirement beyond keeping the licence text with the source.

The engine requirement is worth noting because it is stricter than most React libraries ask for: the manifest declares node >=24.20.0, and the package manager is pinned to pnpm 12.3.4. A continuous integration image on an older Node will fail on the engine check before it reaches anything else, which is a cheap failure but one that looks confusing the first time.

The build and quality scripts show how the project is maintained. The build removes the dist directory, then builds the component and the demo in turn. The component build runs tsc and then Vite in library mode, which is what produces the dist/component output that the files list publishes. Formatting is Prettier with its own configuration, linting is ESLint with a config file under config/eslint, and the tests run under Vitest with a separate coverage and watch mode. There is an integrate script that chains format check, lint, test and build, which is the one command that tells you whether the tree is in a shippable state.

Release activity is steady rather than fast: version 5.0.4 was published on 2026-06-17, 5.0.3 on 2026-04-11 and 5.0.2 on 2025-12-13, and the last push to the repository was on 2026-10-01. For a component that sits between a React version and a p5 version, that pace is what you should plan around, since each React or p5 release is a reason for the peer dependency floors to move again.

## Conclusion

This wrapper is worth adopting when you want a p5 sketch to live inside an existing React application and to be driven by React state, since updateWithProps and the typed SketchProps generics are the parts you would otherwise write yourself, and the MIT licence leaves no obligation on your side. It is the wrong tool for a page that needs server rendering, for a project that cannot move to p5 2 and React 19, and for a team that wants a specific canvas sizing or lifecycle behaviour, because the wrapper owns the canvas and the p5 instance. Before installing, read the v5 migration notes and rename ReactP5Wrapper to P5Canvas, confirm your Node version satisfies the >=24.20.0 engine requirement, and check whether a Next.js application should use the @p5-wrapper/next dynamic implementation instead.

## FAQ

### What is @P5-wrapper/react and what does the P5Canvas component do?

It is a React component that lets you use P5.js sketches inside a React application. The P5Canvas component takes a sketch function that receives a p5 instance, creates the canvas from that sketch's setup function, and forwards React props into the sketch.

### How do I install @P5-wrapper/react and what are its peer dependencies?

Install it with npm, yarn or pnpm together with p5. The peer dependencies are p5 at 2.0.0 or newer, react at 19.0.0 or newer and react-dom at 19.0.0 or newer, and they must be installed in your project. No separate @types package is needed because p5 ships its own type definitions.

### What changed in version 5 of @P5-wrapper/react?

The component was renamed from ReactP5Wrapper to P5Canvas, P5WrapperProps became P5CanvasProps and P5WrapperClassName became CanvasContainerClassName, and the peer dependency floors rose to p5 2.0.0, react 19.0.0 and react-dom 19.0.0. Documentation for version 4 is kept in the repository at the v4.4.1 tag.

### How do I pass React state into a p5 sketch with @P5-wrapper/react?

Pass custom props to P5Canvas and define an updateWithProps method on your sketch, which is called on the initial render and whenever the props change. For the opposite direction, reading p5 instance values to drive React state, the updater prop provides a callback that runs in the React layer.

## Sources

- [License: MIT](https://github.com/P5-wrapper/react/blob/main/LICENSE)
- [P5-wrapper/react on GitHub](https://github.com/P5-wrapper/react)
- [Project website](https://p5-wrapper.github.io/react/)
- [README](https://github.com/P5-wrapper/react/blob/main/README.md)
- [Releases](https://github.com/P5-wrapper/react/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/p5-wrapper-react
