User Preferences

Learn how to access user preferences and how to adjust your app using react-three-fiber with @react-three-a11y

When it comes to accessibility, some users might need to have an interface as still as possible or with a preferred color scheme.

These are CSS media features and this library expose two of them

While you don't necessarily require this library to access them, we provide an easy way to use them and listen to their changes.

Setup

For that wrap your components inside the A11yUserPreferences component

<A11yUserPreferences>
  <My3dObject />
  <MySecond3dObject />
  [...]
</A11yUserPreferences>

Then, you can access the preferences in each children component where you might need them.

Reduce motions / animations for the users that request it

Some user on your website might need all animation turned off or limited to what's strictly necessary. For those users, if your app has an animation going somewhere, consider cancelling it for those who request it. You can do it like so.

const My3dObject = () => {
  // this const will give you access to the user preferences
  const { a11yPrefersState } = useUserPreferences()
  const mesh = useRef()

  // Rotate mesh every frame
  useFrame(() => {
    //unless the user prefers reduced motion
    if (!a11yPrefersState.prefersReducedMotion) {
      mesh.current.rotation.x = mesh.current.rotation.y += 0.01
    }
  })

  return (
    <mesh ref={mesh}>
      <boxBufferGeometry args={[1, 1, 1]} />
      <meshStandardMaterial />
    </mesh>
  )
}

Adapt colour scheme depending on the user preference

Some user on your website might need a darker / lighter theme. You can adapt your components according to it like so.

const My3dObject = () => {
  // this const will give you access to the user preferences
  const { a11yPrefersState } = useUserPreferences()
  const mesh = useRef()

  return (
    <mesh ref={mesh}>
      <boxBufferGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color={a11yPrefersState.prefersDarkScheme ? 'darkblue' : 'lightblue'} />
    </mesh>
  )
}

Use the context outside and inside the r3f canvas

At the moment React context can not be readily used between two renderers, this is due to a problem within React. If react-dom use the A11yUserPreferences provider, you will not be able to consume it within <Canvas>.

There's a ready-made solution in drei: useContextBridge which allows you to forward contexts provided above the <Canvas /> to be consumed within it.

You can see how it's used in the react-three-a11y demo