Back to Fluentui

React Version Support

apps/public-docsite-v9/src/Concepts/ReactVersionSupport.mdx

4.40.2-hotfix24.3 KB
Original Source

import { Meta } from '@storybook/addon-docs/blocks';

<Meta title="Concepts/Developer/React Version Support" />

React Version Support

ℹ️ Note: Our migration docs focus solely on FluentUI related changes.

If you're migrating between React major versions, please refer to the official React documentation for comprehensive migration guides.

For migrating your codebase TypeScript types, you can leverage Types React Codemod

React 17

Full support starting @fluentui/react-components v9.0.0.

React 18

Full support starting @fluentui/react-components v9.66.0.

Migration

💡 Check Following PR for further details https://github.com/microsoft/fluentui/pull/34456

Runtime/API changes:

NONE

TypeScript types changes:

Slot Children as a Function

Because @types/react@18 Breaking Changes, we needed to loosen Slot children property to any.

This change will affect users that use Slot children as a function in conjunction with TypeScript strict mode.

If that's your case, TypeScript will fail on noImplicitAny. To mitigate this you need to add type assertions (satisfies SlotRenderFunction<T>)

Before:

tsx
import * as React from 'React';

<Button
  // children was inferred as union of ReactNode and SlotRenderFunction
  icon={{ children: (Component, props) => <Component {...props /> }}
>
Label
</Button>

After:

tsx
import * as React from 'React';
import { type SlotRenderFunction } from '@fluentui/react-utilities';

<Button
  icon={{
    // children is now `any` and needs to be asserted as `SlotRenderFunction`
    children: ((Component, props) => <Component {...props} />) satisfies SlotRenderFunction<
      React.ComponentProps<'span'>
    >,
  }}
>
  Label
</Button>;

React 19

Full support starting @fluentui/react-components v9.72.2.

Migration

💡 Follow official React 19 migration guidelines

Runtime/API changes:

NONE

TypeScript Types Recommendations

📚 For Library Authors & FluentUI Extension Developers

These recommendations ensure your library's TypeScript types remain backwards compatible across React 17, 18, and 19.

💡 See PR #34733 for technical details

1. Enforce Explicit Return Types for Render Functions & Hooks

React 19 made removed global JSX type, that can cause type compatibility issues across versions.

Always explicitly type your APIs that return JSX markup (render functions, hooks).

Setup ESLint Rule:

js
{
  '@typescript-eslint/explicit-module-boundary-types': [
    'error',
    {
      allowArgumentsExplicitlyTypedAsAny: true,
      allowOverloadFunctions: true,
    },
  ],
}

Why? This prevents implicit return type inference that may differ between React versions, ensuring your component and hook signatures remain consistent.

📖 Learn more in PR #35080

2. Use FluentUI Cross-Version Compatible JSX Types

React's JSX namespace types changed between versions. FluentUI provides stable, cross-compatible type utilities that work across React 17, 18, and 19.

Setup ESLint Rule:

Configure @typescript-eslint/no-restricted-types to enforce FluentUI types. View complete setup

Migration Example:

Before (React-specific types):

tsx
const renderFoo = (): JSX.Element => <div>Hello</div>;

interface SomeElementProps {
  as?: keyof JSX.IntrinsicElements;
  divProps?: JSX.IntrinsicElements['div'];
}

After (FluentUI cross-version types):

tsx
import type { JSXElement, JSXIntrinsicElementKeys, JSXIntrinsicElement } from '@fluentui/react-components';

const renderFoo = (): JSXElement => <div>Hello</div>;

interface SomeElementProps {
  as?: JSXIntrinsicElementKeys;
  divProps?: JSXIntrinsicElement<'div'>;
}

Available Types:

  • JSXElement - Replaces JSX.Element / React.JSX.Element
  • JSXIntrinsicElementKeys - Replaces keyof JSX.IntrinsicElements
  • JSXIntrinsicElement<K> - Replaces JSX.IntrinsicElements[K]

Benefits:

  • ✅ Works across React 17, 18, and 19
  • ✅ No breaking changes when users upgrade React versions
  • ✅ Consistent type checking regardless of @types/react version