TypeScript icon, indicating that this package has built-in type declarations

    1.1.0 • Public • Published


    npm version npm

    WebXR + react-three-fiber

    React components and hooks for creating VR/AR applications with react-three-fiber

    Note: Extremely early in development. Contributors welcome!

    These demos are real, you can click them! They contain the full code, too.


    yarn add react-xr

    Getting started

    Add VRCanvas or ARCanvas component (or replace your existing react-three-fiber Canvas component)

    import { VRCanvas } from 'react-xr'
    function App() {
      return (
          {/* All your regular react-three-fiber elements go here */}

    Adding controllers to the scene

    To get started with default controller models add DefaultXRControllers component. It will fetch appropriate input profile models. You can learn more here.

    import { VRCanvas, DefaultXRControllers } from 'react-xr'
      <DefaultXRControllers />

    You can access controllers' state (position, orientation, etc.) by using useXR() hook

    const { controllers } = useXR()


    VRCanvas / ARCanvas

    Extended react-three-fiber Canvas that includes:

    • Button to start VR session
    • Color management
    • VR Mode
    • react-xr context

    For VR apps use VRCanvas and for AR apps use ARCanvas

    import { VRCanvas } from 'react-xr'
      {/* All your regular react-three-fiber elements go here */}


    Hook that can only beused by components inside XRCanvas component.

    const { controllers } = useXR()

    Controllers is an array of XRController objects

    interface XRController {
      grip: Group
      controller: Group
      inputSource: XRInputSource
      // ...
      // more in XRController.ts

    grip and controller are ThreeJS groups that have the position and orientation of xr controllers. grip has an orientation that should be used to render virtual objects such that they appear to be held in the user’s hand and controller has an orientation of the preferred pointing ray.

    inputSource is the WebXR input source (MDN). Note that it will not be available before controller is connected.


    Every controller emits following events: select, selectstart, selectend, squeeze, squeezestart, squeezeend.

    To listen to those events use useXREvent hook:

    const onSqueeze = useCallback(() => console.log('Squeezed'), [])
    useXREvent('squeeze', onSqueeze)

    it supports optional third parameter with options

    const onSqueeze = useCallback(() => console.log('Left controller squeeze'), [])
    useXREvent('squeeze', onSqueeze, { handedness: 'left' })


    Use this hook to get n instance of the controller

    const leftController = useController('left')


    Add hands model for hand-tracking. Currently only works on Oculus Quest with #webxr-hands experimental flag enabled

      <Hands />


    react-xr comes with built-in high level interaction components.


    Hover component will allow you for detecting when ray shot from the controllers is pointing at the given mesh.

    <Hover onChange={(value) => console.log(value ? 'hovered' : 'blurred')}>
      <mesh />


    Select can be used when you need to select some mesh. Component will trigger onSelect function when controller is pointing at the given mesh and select event was fired.

    <Select onSelect={() => console.log('mesh has been selected')}>
      <mesh />

    Getting the VR Camera (HMD) Location

    To get the position of the VR camera, use three's WebXRManager instance.

    const { camera } = useThree()
    const cam = gl.xr.isPresenting ? gl.xr.getCamera(camera) : camera

    Parent VR HMD and Controllers to another object

    If you want to attach the user to an object so it can be moved around, just parent the VR camera and controllers to an object3D.

    const mesh = useRef()
    const { gl, camera } = useThree()
    useEffect(() => {
      const cam = gl.xr.isPresenting ? gl.xr.getCamera(camera) : camera
      return () => mesh.current.remove(cam)
    }, [gl.xr.isPresenting, gl.xr, camera, mesh])
    // bundle add the controllers to the same object as the camera so it all stays together.
    const { controllers } = useXR()
    useEffect(() => {
      if (controllers.length > 0) controllers.forEach((c) => mesh.current.add(c.grip))
      return () => controllers.forEach((c) => mesh.current.remove(c.grip))
    }, [controllers, mesh])




    npm i react-xr

    DownloadsWeekly Downloads






    Unpacked Size

    640 kB

    Total Files


    Last publish


    • drcmda