Skip to main content

<ThreeDom /> Component

The main bridge component. Place it inside your R3F <Canvas>.

import { Canvas } from '@react-three/fiber';
import { ThreeDom } from '@react-three-dom/core';

<Canvas>
<ThreeDom />
{/* your scene */}
</Canvas>

Props

PropTypeDefaultDescription
canvasIdstringUnique ID for multi-canvas apps. Registers in window.__R3F_DOM_INSTANCES__[canvasId].
primarybooleantrue when no canvasIdWhether window.__R3F_DOM__ points to this instance.
mode"auto" | "manual""auto"auto registers all objects. manual requires explicit registration via useR3FRegister or r3fRegister().
filter(obj: Object3D) => booleanOnly register objects that pass the filter. Auto mode only.
rootstring | HTMLElement"#three-dom-root"CSS selector or element for the mirror DOM container.
batchSizenumber500Objects to sync per amortized batch per frame.
syncBudgetMsnumber0.5Max time (ms) for sync work per frame.
maxDomNodesnumber2000Max materialized DOM nodes. LRU eviction when exceeded.
initialDepthnumber3How deep to materialize the DOM tree on mount.
enabledbooleantrueMaster switch for all sync.
debugbooleanfalseEnable debug logging to browser console.
inspectbooleanfalseEnable inspect mode on mount (hover-to-highlight).

Registration Modes

Auto (default)

Traverses the entire scene and registers every object. New objects added to the scene are automatically picked up via the Object3D.add patch.

<ThreeDom />

Auto with Filter

Only objects that pass the filter are registered. Useful when you want to exclude lights, helpers, or internal objects from the mirror DOM.

<ThreeDom filter={(obj) => obj.type === 'Mesh' || obj.type === 'Group'} />

Manual

Nothing is auto-registered. You control exactly which objects appear in the mirror DOM using the useR3FRegister hook or the r3fRegister() API.

<ThreeDom mode="manual" />

useR3FRegister Hook

Registers a Three.js object on mount and unregisters on unmount. Works in both modes.

import { useR3FRegister } from '@react-three-dom/core';

function Wall({ geometry }) {
const ref = useRef<Mesh>(null!);
useR3FRegister(ref);
return <mesh ref={ref} geometry={geometry} userData={{ testId: 'wall' }} />;
}

For multi-canvas setups, pass the canvas ID:

useR3FRegister(ref, 'viewer2');

The hook automatically:

  • Retries if the bridge isn't ready yet on mount
  • Detects ref.current identity swaps and re-registers
  • Skips unregistration for auto-registered objects (won't accidentally remove them)

Error Handling

If WebGL is unavailable or setup fails, the bridge creates a stub with _ready: false and an _error message. All API methods become no-ops. This prevents silent hangs — test waiters will see the error and fail with a clear message.