Skip to content

Events

Compare manual raycasting and pointer bookkeeping with R3F's built-in pointer event system.

Pinned example stack

react@19.1.1react-dom@19.1.1@react-three/fiber@9.3.0three@0.180.0

Exact Conversion

Switch between the React Three Fiber and Three.js examples, then test the R3F result in the live preview below.

React Three Fiber
import { useState } from 'react';
import { Canvas } from '@react-three/fiber';
function ClickableBox({ color, position }) {
const [active, setActive] = useState(false);
return (
<mesh position={position} scale={active ? 1.35 : 1} onClick={() => setActive((value) => !value)}>
<boxGeometry />
<meshStandardMaterial color={color} />
</mesh>
);
}
export default function App() {
return (
<div style={{ height: '100vh', background: '#111827' }}>
<Canvas camera={{ fov: 55, position: [0, 0.5, 5] }} dpr={[1, 2]}>
<color attach="background" args={['#111827']} />
<directionalLight position={[2, 3, 4]} intensity={1.6} />
<ClickableBox color="#f97316" position={[-1.1, 0, 0]} />
<ClickableBox color="#38bdf8" position={[1.1, 0, 0]} />
</Canvas>
</div>
);
}

Live preview

What Changed

  • In raw Three.js, you often manage a Raycaster, normalized pointer coordinates, and manual intersections yourself.
  • In R3F, a mesh can often handle onClick, onPointerOver, and related events directly.
  • The clicked object is still the same underlying Three.js mesh.
  • React state is fine here because the interaction is discrete, not per-frame.

Built-in R3F events cover a lot of interaction work. If you need fully custom hit testing or more complex control over intersections, you can still use the raw Three.js tools underneath.