Skip to main content

Canvas initializes the three.js rendering context and is the root of your 3D scene. Every <T.*> and <Entity/> component must be a child of it.

Props

PropTypeDefaultDescription
cameraPartial<Props<Camera>> | Cameranew PerspectiveCamera()The scene camera — partial props for the default camera, or an instance you built.
globject | ((canvas: HTMLCanvasElement) => Renderer) | Renderernew WebGLRenderer({ alpha: true })How the renderer is built. See The gl prop.
scenePartial<Props<Scene>> | Scenenew Scene()Settings for the scene, or an existing Scene.
raycasterPartial<Props<EventRaycaster>> | EventRaycaster | Raycasternew CursorRaycaster()The raycaster used for pointer events.
shadowsboolean | "basic" | "percentage" | "soft" | "variance" | WebGLRenderer["shadowMap"]offEnables shadows. See Rendering defaults for the string mapping.
orthographicbooleanfalseUse an OrthographicCamera for the default camera.
linearbooleanfalseUse a linear output color space instead of sRGB.
flatbooleanfalseDisable tone mapping (NoToneMapping).
frameloop"always" | "demand" | "never""always"When to render: every frame, only on request, or never.
fallbackJSX.ElementShown while content loads asynchronously.
styleJSX.CSSPropertiesCSS for the canvas container.
classstringCSS class for the canvas container.
refRefWithCleanup<Context>Receives the Context once the renderer is created, so code outside <Canvas> can reach it. A callback ref may return a cleanup that runs when the Canvas unmounts; createXR uses this.
event handlersPartial<CanvasEventHandlers>Any event handler, firing after the event bubbles through the whole scene (e.g. onClick, onClickMissed).
Exact type
interface CanvasProps extends ParentProps<Partial<CanvasEventHandlers>> {
ref?: RefWithCleanup<Context> // Context | ((context: Context) => void | (() => void))
camera?: Partial<Props<PerspectiveCamera> | Props<OrthographicCamera>> | Camera
fallback?: JSX.Element
gl?: // The flat-object branch collapses to `never` when Register narrows
// ResolvedRenderer away from WebGLRenderer — see "Narrowing the
// renderer type project-wide" below.
| (WebGLRenderer extends ResolvedRenderer
? Partial<Props<WebGLRenderer> & WebGLRendererParameters>
: never)
| ((canvas: HTMLCanvasElement) => ResolvedRenderer)
| ResolvedRenderer
scene?: Partial<Props<Scene>> | Scene
raycaster?: Partial<Props<EventRaycaster>> | EventRaycaster | Raycaster
shadows?: boolean | "basic" | "percentage" | "soft" | "variance" | WebGLRenderer["shadowMap"]
orthographic?: boolean
linear?: boolean
flat?: boolean
frameloop?: "never" | "demand" | "always"
style?: JSX.CSSProperties
class?: string
// Plus all event handlers (Partial<CanvasEventHandlers>)
}

CanvasProps is exported as a type: import type { CanvasProps } from "solid-three".

Usage

<Canvas
camera={{ position: [0, 0, 5], fov: 75 }}
shadows="soft"
gl={{ antialias: true }}
onClickMissed={() => console.log("Clicked empty space")}
>
{/* Your 3D scene */}
</Canvas>

Rendering defaults

A few defaults are derived rather than passed directly:

  • Tone mappingACESFilmicToneMapping, or NoToneMapping when flat is set.

  • Output color spaceSRGBColorSpace, or LinearSRGBColorSpace when linear is set.

  • Shadow typeshadows={true} uses PCFSoftShadowMap. The string values map to three's constants:

    shadowsShadow map
    "basic"BasicShadowMap
    "percentage"PCFShadowMap
    "soft"PCFSoftShadowMap
    "variance"VSMShadowMap

Tone-mapping and color-space defaults are applied only to renderers that expose those fields — they're skipped silently for renderers like SVGRenderer.

The gl prop

gl controls how the renderer is built. It accepts three shapes:

ShapeExampleUse it for
Properties objectgl={{ antialias: true, toneMapping: ACESFilmicToneMapping }}Tweaking the default WebGLRenderer. Mixes constructor flags (antialias, alpha, powerPreference) with instance props (toneMapping).
Factorygl={canvas => new WebGPURenderer({ canvas })}Choosing a different renderer — WebGPURenderer, SVGRenderer, CSS2DRenderer, a custom one.
Instancegl={myRenderer}A renderer you already built.

With the properties object, instance props stay reactive — set them after construction and update them anytime. Constructor flags are the exception, below.

Constructor args are applied once

Constructor-only flags — antialias, alpha, powerPreference, depth, stencil, preserveDrawingBuffer — are passed to new WebGLRenderer({ ... }) once, at first construction, and never re-read. Updating them later does not rebuild the renderer or recreate the WebGL context, and it can't: canvas.getContext("webgl2") is idempotent — the browser returns the same context, with the original flags, on every call. solid-three logs a warning when it detects a reactive change to one of these flags.

If you genuinely need to change one at runtime, unmount and remount the <Canvas> — for example, gate it behind a <Show> keyed on the value you're swapping. That gives you a fresh <canvas> element, and therefore a fresh context.

Custom renderers

gl accepts anything in the Renderer union: three's WebGLRenderer or WebGPURenderer, three's DOM-based renderers (SVGRenderer, CSS2DRenderer, CSS3DRenderer), or a custom renderer matching the structural RendererLike interface.

import { WebGPURenderer } from "three/webgpu"
;<Canvas gl={canvas => new WebGPURenderer({ canvas })}>{/* scene */}</Canvas>

solid-three awaits renderer.init() before the first frame, so you don't need to await WebGPU setup yourself.

Narrowing the renderer type project-wide

By default useThree().gl is typed as the open SupportedRenderer union. Declare your concrete renderer once and the type narrows everywhere — both useThree().gl reads and <Canvas gl> assignments:

src/solid-three.d.ts
import type { WebGPURenderer } from "three/webgpu"
declare module "solid-three" {
interface Register {
renderer: WebGPURenderer
}
}

After this:

function Scene() {
const three = useThree()
three.gl.init() // ✓ no narrowing needed — `gl` is WebGPURenderer
three.gl.toneMapping // ✓ typed
}
<Canvas gl={canvas => new WebGPURenderer({ canvas })}> {/* ✓ */}
<Canvas gl={canvas => new WebGLRenderer({ canvas })}> {/* ✗ type error */}
<Canvas gl={{ toneMapping: ACESFilmicToneMapping }}> {/* ✗ type error —
the config shorthand
only builds a default
WebGLRenderer */}
Renderer types
/**
* Anything <Canvas> accepts as a renderer: a concrete three renderer
* (gets full three typing for `xr` / `shadowMap` etc.) or a custom
* structural `RendererLike`.
*/
type SupportedRenderer = WebGLRenderer | WebGPURenderer | RendererLike
/** Effective renderer type — narrowed by user `Register` augmentation if provided. */
type ResolvedRenderer = Register extends { renderer: infer R } ? R : WebGLRenderer
/**
* Module-augmentation point. Declare your concrete renderer choice in a
* project-local `.d.ts` and `useThree().gl`, `Context.gl`, and the
* `<Canvas gl>` prop all type-narrow project-wide.
*/
interface Register {}
/**
* Minimal structural interface for renderers — three's DOM-based renderers
* (SVGRenderer, CSS2DRenderer, CSS3DRenderer) and user-built renderers fit
* this. Concrete three renderers (WebGLRenderer, WebGPURenderer)
* structurally satisfy it too, but the `SupportedRenderer` union prefers their
* exact types so WebGL-specific surface remains reachable.
*/
interface RendererLike {
render(scene: any, camera: any): void
setSize(width: number, height: number, updateStyle?: boolean): void
domElement: Element
setPixelRatio?(value: number): void
getPixelRatio?(): number
xr?: WebGLRenderer["xr"] | WebGPURenderer["xr"]
shadowMap?: WebGLRenderer["shadowMap"] | WebGPURenderer["shadowMap"]
init?(): Promise<void>
hasInitialized?(): boolean
}

See also

  • useThree — read the renderer, scene, camera, and more from inside the canvas.
  • Raycasters — the raycaster types accepted by the raycaster prop.
  • Events overview — the handlers you can pass to <Canvas>.

Last updated: 6/8/26, 11:20 AM

solid threeA SolidJS renderer for three.js — learn by reading.
Community
github