Navigate

Search topics across all sections

GitHub
Canvas & SetupFoundation

Canvas Component

Before you can show anything in 3D, you need a place to put it. The <Canvas> component is that place. Think of your React webpage as a wall -- the Canvas is a picture frame you hang on it. Everything 3D lives inside that frame. Outside? Normal React. Inside? A whole 3D universe.

You write your first <Canvas> with a beautiful orange box inside. You save, refresh the browser, and... nothing. A blank white page stares back at you. No errors in the console. The box exists in code, but it is invisible.

terminal
The <Canvas> rendered, but its parent <div> has height: auto (which is 0px).
Your entire 3D scene is there -- just squished into zero pixels.

Real-world

Imagine hanging a picture frame on your wall. The wall is your React webpage. The frame is the <Canvas>. The picture inside is your 3D world -- meshes, lights, cameras, everything.

But here is the thing: if you do not give the frame a size, it collapses flat. No frame, no picture. That is why the Canvas needs its parent container to have a width and height.

<Canvas>

You write this in JSX

Scene + Camera + Renderer

R3F creates these for you

Render Loop

60fps animation automatically

Pixels on Screen

Your 3D world appears!

Building Your First Canvas

Let us set up a Canvas step by step. It is simpler than you think -- three steps and you have a 3D scene running.

Step 1Give the parent a size

The Canvas fills whatever container it is inside. No container size means no visible canvas. A full-screen scene? Just make the parent fill the viewport.

App.tsxTSX
<div style={{ width: '100vw', height: '100vh' }}>
  <Canvas>
    {/* 3D stuff goes here */}
  </Canvas>
</div>

That div is now the size of the entire browser window, and the Canvas stretches to fill it.

Step 2Add lights so you can see things

Most materials need light to be visible, just like real life. No light in a room? Everything is black.

App.tsxTSX
<Canvas>
  <ambientLight intensity={0.5} />
  <directionalLight position={[5, 5, 5]} />
</Canvas>

ambientLight is like opening the curtains -- soft light everywhere. directionalLight is like the sun shining from a specific direction.

Step 3Drop in a 3D object

A mesh is a visible 3D thing. It needs a shape (geometry) and a surface look (material). Together they make something you can actually see.

App.tsxTSX
<Canvas>
  <ambientLight intensity={0.5} />
  <directionalLight position={[5, 5, 5]} />
  <mesh>
    <boxGeometry args={[1, 1, 1]} />
    <meshStandardMaterial color="orange" />
  </mesh>
</Canvas>

That is it. A lit, orange box floating in 3D space. The Canvas gave you a camera at position [0, 0, 5] looking at the origin, so the box is right in view.

What you just learned

Canvas is the boundary between normal React and the 3D world

It automatically creates a Scene, Camera, and Renderer for you

Canvas fills its parent, so the parent must have a defined size

Lights are needed for most materials to be visible

R3F hooks (useFrame, useThree) only work inside Canvas

Question

If Canvas creates its own camera automatically, what happens when you want two different camera angles? Can you have two Canvases on the same page?

Yes, you can. Each Canvas is a completely independent 3D world with its own camera, scene, and renderer. Some apps use multiple canvases for split-screen views or picture-in-picture effects.

Think about it...

You render a <Canvas> inside a <div> that has no CSS height. What will you see on screen?

Try These Challenges

Put what you learned into practice. Try each challenge in the demo above using the Leva controls, then check the solution.

Try This!

Beginner

Remove the parent div height -- what happens?

Try This!

Beginner

Add dpr={[1, 2]} to the Canvas -- does it look sharper?

Try This!

Intermediate

Set frameloop='demand' and drag to rotate -- what changes?

These are the patterns that trip up developers most often. Switch between Wrong and Fixed to compare the code side by side.

1
Canvas with no parent height
The canvas collapses to 0px
Don't do this
App.tsxTSX
// The Canvas has no height constraint
function App() {
  return (
    <div>
      <Canvas>
        <mesh />
      </Canvas>
    </div>
  )
}
Canvas fills its parent container. If the parent div has no height, the canvas will be 0px tall and invisible. Always give the parent a defined height via CSS, such as h-screen, 100vh, or a fixed pixel value.
2
Using R3F hooks outside Canvas
useFrame, useThree only work inside Canvas
Don't do this
App.tsxTSX
function App() {
  // This is OUTSIDE the Canvas tree!
  useFrame(() => { /* ... */ })

  return (
    <Canvas>
      <mesh />
    </Canvas>
  )
}
R3F hooks like useFrame and useThree depend on the internal context that Canvas provides. Any component calling these hooks must be a descendant of <Canvas>.
3
Forgetting lights with Standard materials
Scene appears completely black
Don't do this
App.tsxTSX
<Canvas>
  {/* No lights! */}
  <mesh>
    <boxGeometry />
    <meshStandardMaterial color="orange" />
  </mesh>
</Canvas>
MeshStandardMaterial simulates real lighting. Without light sources, everything renders black. Add at least an ambientLight plus a directionalLight.

Best Practices

Set dpr limits

Use dpr={[1, 2]} to cap the pixel ratio. On Retina displays, without this your GPU works 4x harder for barely noticeable quality gains.

Use demand mode for static scenes

If nothing is animating, set frameloop="demand" so the GPU only renders when something changes. Your laptop fan will thank you.

Enable shadows explicitly

Shadows are off by default (they are expensive). Add the shadows prop only when needed, and mark meshes with castShadow and receiveShadow.

Keep the Canvas wrapper sized

Canvas fills its parent. Always ensure the parent has explicit dimensions. A common pattern: className="h-screen w-full".