React 18 is not compatible with Fluent UI and how to work around it in PCF projects

React version 18 has recently been pushed into npm which is great if all of your components support it, however, if you are working with Fluent UI then you may stumble across the following error:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR!
npm ERR! While resolving: my-app20@0.1.0
npm ERR! Found: @types/react@18.0.8
npm ERR! node_modules/@types/react
npm ERR!   @types/react@"^18.0.8" from the root project
npm ERR!
npm ERR! Could not resolve dependency:
npm ERR! peer @types/react@">=16.8.0 <18.0.0" from @fluentui/react@8.67.2
npm ERR! node_modules/@fluentui/react
npm ERR!   @fluentui/react@"*" from the root project
npm ERR!
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR!
npm ERR! See C:\Users\...\AppData\Local\npm-cache\eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\...\AppData\Local\npm-cache\_logs\....-debug-0.log

This might happen if you are doing either of the following:

  1. When creating a standard PCF project using pac pcf init and then using npm install react followed by npm install @fluentui/react
  2. Using create-react-app with the standard typescript template, followed by npm install @fluentui/react

The reason in both cases for the error is that once React 18 is installed, Fluent UI will not install since it requires a version less than 18. The Fluent UI team are working on React 18 compatibility but I do not know how long it will be until Fluent UI supports React 18. 

These kinds of issues often crop up when node module dependencies are set to automatically take the newest major version of packages.

How to fix the issue?

Fundamentally the fix is to downgrade the version of React and the related libraries before installing Fluent UI:

pac pcf init

If you are using standard controls - you might consider moving to virtual controls.
Doing this actually requires a specific version of React and Fluent UI to be installed and so there is no issue.
Check out my blog post on how to convert to a virtual control and install the specific versions required.

Alternatively, if you are installing react after using pac pcf init with a standard control you can install version 17 specifically using:

npm install react@17 react-dom@17 @types/react@17 @types/react-dom@17

After you've done that, you can install fluent as usual using:

npm install @fluentui/react@latest

create-react-app

Create-react-app is a command-line utility that is commonly used to quickly create a react app - and is often used for testing purposes when building pcf components. Now that React 18 has been released, using create-react-app will also install react-18. The scripts and templates have all be updated accordingly. 

Unfortunately, you can't use an older version of create-react-app that used the older version of react (e.g. npx create-react-app@5.0.0) because you will receive the error:

You are running `create-react-app` 5.0.0, which is behind the latest release (5.0.1).
We no longer support global installation of Create React App.

The Fluent UI team are actually working on a create-react-app template for fluent that specifically installs react17 - but until then you will need to follow these steps:

  1. Use create-react-app as usual:
    npx create-react-app my-app --template typescript
  2. After your app has been created use:
    cd my-app
    npm uninstall react react-dom @testing-library/react @types/react @types/react-dom
    npm install react@17 react-dom@17 @testing-library/react@12 @types/react@17 @types/react-dom@17
  3. Since the latest template is designed for React 18 you will need to make some minor modifications to index.ts:
    Replace import ReactDOM from 'react-dom/client'; with import ReactDOM from 'react-dom';
    Replace the following code:
    const root = ReactDOM.createRoot(
      document.getElementById('root') as HTMLElement
    );
    root.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>
    );
    With the code:
    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      document.getElementById('root')
    );
    This is required because React 18 does not support the ReactDOM.render method anymore.

Once Fluent UI has been updated to support React 18, these steps will not be required - however, if you are using Virtual Controls, then until the platform is updated, your controls will continue to need to use React 16.8.6.

Hope this helps!

@ScottDurow

Comments are closed