The Modern SPFx Stack
SharePoint Framework (SPFx) has evolved significantly in the last 18 months. The current shipping generation supports React 18, Fluent UI v9, TypeScript 5.x, Node 22, and ES2022 target. For developers who built SPFx solutions on React 16 and Fluent UI v8 three years ago, the toolchain, the component library, and the patterns have all changed.
This guide walks through modern SPFx development patterns, the specific breaking changes between React 16 and React 18 that matter for SPFx, the Fluent UI v9 component model, TypeScript 5 features that improve SPFx code quality, and the performance patterns that produce production-quality extensions.
The Generator and Scaffold
Start every new solution with the latest Yeoman generator for SharePoint Framework. The scaffold produces a solution structure that is compatible with modern tooling and includes ESLint, Jest, Webpack 5, and Node 22 support.
```bash
# Install the latest SPFx generator globally
npm install -g @microsoft/generator-sharepoint@latest
# Scaffold a new solution
mkdir my-spfx-solution
cd my-spfx-solution
yo @microsoft/sharepoint
```
The generator prompts for solution type (web part, extension, library), framework preference (React recommended), and Node version. Select React 18 and TypeScript 5 when prompted. The resulting package.json targets the current supported versions and includes the necessary polyfills.
React 18 in SPFx: What Changed and Why It Matters
React 18 introduced concurrent rendering, automatic batching, Suspense improvements, and a new root API. The changes that matter for SPFx developers specifically:
The New Root API
React 18 requires calling createRoot to mount components. The legacy ReactDOM.render API is deprecated. SPFx web parts must use the new pattern.
```typescript
import * as React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import MyComponent from './components/MyComponent';
export default class MyWebPart extends BaseClientSideWebPart
private _root: Root | null = null;
public render(): void {
if (!this._root) {
this._root = createRoot(this.domElement);
}
this._root.render(
React.createElement(MyComponent, {
description: this.properties.description,
context: this.context,
})
);
}
protected onDispose(): void {
this._root?.unmount();
this._root = null;
}
}
```
The critical detail is keeping the root reference across renders. Creating a new root on every render causes memory leaks and performance issues. Unmounting in onDispose prevents leaks when the web part is removed.
Automatic Batching
React 18 batches state updates across promises, setTimeouts, and native event handlers automatically. This improves performance but changes behavior for code that relied on synchronous state updates. The common symptom is state that was expected to update after an async operation but appears to update on a later render.
The fix is usually straightforward: code that depended on flushed state should use useEffect or await a microtask. In rare cases flushSync is the right answer, but reach for it only when batching produces a visible rendering problem.
Concurrent Features
Concurrent rendering allows React to interrupt, pause, and resume rendering work. For SPFx, the practical benefits come from useTransition and useDeferredValue. These hooks let expensive operations (large list filtering, heavy computations) run without blocking user input.
```typescript
import * as React from 'react';
import { useState, useTransition, useDeferredValue } from 'react';
export const FilterableList: React.FC<{ items: Item[] }> = ({ items }) => {
const [query, setQuery] = useState('');
const [isPending, startTransition] = useTransition();
const deferredQuery = useDeferredValue(query);
const filtered = React.useMemo(
() => items.filter(i => i.name.toLowerCase().includes(deferredQuery.toLowerCase())),
[items, deferredQuery]
);
return (
value={query}
onChange={(e) => {
const value = e.target.value;
startTransition(() => setQuery(value));
}}
/>
{isPending &&
- {item.name} )}
{filtered.map(item =>
);
};
```
Fluent UI v9: A Different Component Library
Fluent UI v9 is not a version update of Fluent UI v8. It is a rewrite built on Griffel (a CSS-in-JS solution) with a new component model, new theming system, and new bundle strategy. SPFx solutions can use either v8 (via @fluentui/react) or v9 (via @fluentui/react-components). They can even mix them during migration, though that increases bundle size significantly.
Why v9
Fluent UI v9 was designed for modern performance requirements. Components are tree-shakable, bundles are smaller, theming is token-based and dynamic, and the rendering approach plays better with React 18's concurrent features. For new SPFx solutions, v9 is the preferred choice.
The v9 Component Model
v9 components follow a consistent API pattern: a primary component, slot APIs for customization, and tokens for theming. A typical usage:
```typescript
import * as React from 'react';
import {
FluentProvider,
webLightTheme,
Button,
Card,
CardHeader,
Text,
makeStyles,
tokens,
} from '@fluentui/react-components';
const useStyles = makeStyles({
container: {
padding: tokens.spacingVerticalL,
backgroundColor: tokens.colorNeutralBackground1,
},
title: {
color: tokens.colorNeutralForeground1,
marginBottom: tokens.spacingVerticalM,
},
});
export const ModernWebPartComponent: React.FC = () => {
const styles = useStyles();
return (
header={ />
);
};
```
Theme Integration With SharePoint
SPFx solutions must respect the SharePoint theme, including light mode, dark mode, and high contrast. The SharePoint context provides theme information that can be mapped to Fluent v9 themes.
The typical pattern is reading the current SharePoint theme from the context, selecting the matching Fluent v9 theme (webLightTheme, webDarkTheme, teamsLightTheme, teamsDarkTheme), and wrapping the component tree in a FluentProvider with that theme. A production implementation should also listen for theme change events and re-render when the user changes the site theme.
TypeScript 5: Features That Matter for SPFx
TypeScript 5 brings several features that improve SPFx code quality.
Decorators (Stage 3)
Stage 3 decorators are stable and replace the older experimental decorators. SPFx generator output now uses Stage 3 decorators by default. Custom decorator libraries need to be updated if they rely on the older decorator model.
const Type Parameters
const type parameters preserve literal types in generic functions, which improves IntelliSense and reduces the need for as const assertions in many SPFx patterns.
satisfies Operator
The satisfies operator validates that a value matches a type without widening the inferred type. This is particularly useful for SPFx property pane configurations and Graph API query definitions where you want both type safety and preserved literal types.
```typescript
import { IPropertyPaneConfiguration } from '@microsoft/sp-property-pane';
const propertyPaneConfig = {
pages: [
{
header: { description: 'Configure the web part' },
groups: [
{
groupName: 'Data source',
groupFields: [
{ label: 'Site URL' },
{ label: 'List title' },
],
},
],
},
],
} satisfies IPropertyPaneConfiguration;
```
Performance Patterns That Produce Fast Extensions
Modern SPFx extensions must hit tight performance budgets. A web part that takes 800ms to render degrades the entire page's Core Web Vitals score. Four performance patterns consistently matter.
Pattern 1: Code Splitting
Use dynamic imports for heavy dependencies. A web part that needs a charting library should not import it eagerly. Dynamic imports ensure the chart library only loads when the web part is actually rendered.
Pattern 2: Request Batching
Multiple Microsoft Graph requests should be batched using @microsoft/sp-http request batching or Graph JavaScript SDK batch support. A typical web part that lists user information, site information, and list items should issue one batched request rather than three serial requests.
Pattern 3: Caching with SWR Patterns
Cache remote data using stale-while-revalidate (SWR) patterns. The web part renders from cache immediately, then issues a background request to refresh the data. Libraries like SWR and TanStack Query implement this pattern natively.
Pattern 4: Lazy Rendering
Defer rendering of below-the-fold content until the user scrolls near it. IntersectionObserver is the standard mechanism. For web parts that render a large list, rendering only the first 20 items immediately and loading the rest on scroll reduces initial render time dramatically.
Testing Modern SPFx Solutions
Automated testing is non-negotiable for production SPFx. The standard stack:
- Jest: Unit testing framework
- @testing-library/react: Component testing
- MSW (Mock Service Worker): API mocking for Graph and SharePoint REST calls
- Playwright: End-to-end testing in a real browser
Target 80 percent code coverage at the business logic layer and 100 percent coverage of utility functions. End-to-end tests should cover the 3 to 5 critical user flows of the extension.
Deployment and Lifecycle
Modern SPFx solutions follow a CI/CD deployment pipeline. The pattern that works:
- Source code in Git with feature branch workflow
- Pull request builds that run lint, type check, and unit tests
- Merge to main triggers a build that produces the SPFx package
- Deployment to a tenant-wide app catalog goes through a release pipeline with manual approval
- Post-deployment smoke tests validate the package in the target environment
Azure DevOps and GitHub Actions both have first-class support for SPFx builds. The official Microsoft documentation includes sample pipeline definitions that cover the full lifecycle.
Getting Started
The fastest path to a production-quality SPFx extension is to start with the modern scaffold, port any existing React 16 / Fluent v8 patterns to React 18 / Fluent v9 intentionally (not mechanically), and instrument the extension from day one with performance telemetry and automated tests.
Our SharePoint specialists build modern SPFx extensions for enterprise customers across regulated industries. Contact our team to scope an SPFx development engagement, or review our SharePoint consulting services for architecture and delivery support.
Written by the SharePoint Support Team
Senior SharePoint Consultants | 25+ Years Microsoft Ecosystem Experience
Our senior SharePoint consultants bring deep expertise spanning 500+ enterprise migrations and compliance implementations across HIPAA, SOC 2, and FedRAMP environments. We cover SharePoint Online, Microsoft 365, migrations, Copilot readiness, and large-scale governance.
Expert SharePoint Services
Frequently Asked Questions
What React version does SPFx support in 2026?▼
Should we use Fluent UI v8 or v9 for new SPFx web parts?▼
Can we mix Fluent UI v8 and v9 in the same SPFx solution?▼
What is the correct way to render a React component in SPFx 2026?▼
How do we handle SharePoint theme changes in Fluent UI v9 components?▼
What bundle size budget should SPFx web parts target?▼
Can SPFx solutions use TypeScript 5 features?▼
What testing framework works best for modern SPFx solutions?▼
Need Expert Help?
Our SharePoint consultants are ready to help you implement these strategies in your organization.