When to Use
Use this skill when:
- Creating or scaffolding new SPFx web parts, extensions (Application Customizers, Field Customizers, Command Sets) or libraries
- Reviewing or refactoring existing SPFx projects
- Extending existing solutions with new web parts or extensions while maintaining consistent patterns
- Answering questions about SPFx architecture, React, TypeScript, localization, styling (Sass), data access, authentication, Microsoft Graph, SharePoint APIs or tooling
Scope
Applies to:
- SPFx web parts, extensions and libraries
- React with TypeScript
- Localization (
loc resources)
- Styling with Sass modules
- Data access (SharePoint REST, Microsoft Graph, Entra ID–secured APIs)
- SPFx toolchain (Heft / gulp / webpack)
- Modern SPFx development workflows
Technology Stack Constraints
When generating code, adhere to these specific library versions and standards unless instructed otherwise:
- Framework: SharePoint Framework (SPFx)
- UI Library: Fluent UI React (
@fluentui/react)
- Data Access: PnPjs v4 (
@pnp/sp, @pnp/graph, @pnp/logging)
- Language: TypeScript
- State Management: React Hooks
- Styling: CSS Modules (
.module.scss) or Fluent UI Styling (mergeStyles)
Best Practices to Enforce
Project Structure & Architecture
- Use a feature-based or layered folder structure:
src/
common/
controls/
helpers/
hooks/
models/
services/
webparts/
extensions/
- Apply Separation of Concerns
- Keep UI, business logic and data access isolated
- Prefer reusable services over inline API logic
Toolchain & Build
- Target the latest supported SPFx version (e.g. 1.22.x+) if available.
- Use Heft as the primary build orchestrator instead of gulp when starting new projects
- Avoid custom gulp hacks unless absolutely required
- Do not override toolchain defaults unless there is a documented, reproducible need
- Avoid unsupported patches and nonstandard build steps
- Keep configuration minimal and aligned with SPFx defaults
- Validate guidance against current SPFx release notes before shipping
TypeScript & Code Quality
- Enable strict TypeScript settings
- Avoid
any; use interfaces, enums and generics
- Prefer
async/await
- Keep utilities framework-agnostic where possible
React Best Practices
- Prefer functional components and React Hooks
- Keep components small and focused
- Extract logic into custom hooks or services
- Memoize expensive operations (
useMemo, useCallback)
- Use Fluent UI for consistency and accessibility
Localization
- Use SPFx
loc files for all user-facing strings
- Never hardcode display text
- Reference strings via
strings.<Key>
- Ensure graceful fallback for missing translations
- Avoid string concatenation; use placeholders for plurals, dates and numbers
Styling (Sass)
- Use
.module.scss files scoped to components
- Centralize shared variables, mixins and themes
- Avoid global CSS unless explicitly required
- Follow consistent naming conventions
- Controls: Use standard Fluent UI controls to match the M365 look and feel.
- Theming: strictly use
ThemeProvider or the themeVariant object passed from the base context.
- Rule: Never hardcode hex colors (e.g.,
#0078d4). Use semanticColors (e.g., theme.semanticColors.bodyText).
- Tokens: Prefer Fluent UI theme tokens over custom Sass variables for color and typography
Data Access Patterns
- Centralize data access in service classes
- Use PnPjs for most SharePoint operations if available
- Use SPHttpClient when:
- Performing simple or low-level REST calls
- Avoiding additional abstractions
- Handle errors, throttling and retries explicitly
- Prefer @pnp/sp and @pnp/graph for SharePoint and Graph REST interactions. Use native clients only when PnPjs is not available or when minimizing bundle size is a strictly stated priority.
Decision Matrix: PnPjs vs Native Clients
- Use @pnp/sp for SharePoint data access whenever possible
- Use @pnp/graph for Microsoft Graph when PnPjs is available
- Use MSGraphClientV3 only when PnPjs is not available or cannot be added
- Use SPHttpClient for minimal, low-level REST calls or bundle size constraints
Authentication & API Usage
- Use SPHttpClient or PnPjs for SharePoint REST APIs
- Use MSGraphClientV3 for Microsoft Graph access when PnPjs is not available
- Use AadTokenProvider for Entra ID–secured custom APIs
- Request least-privilege permissions
- Ensure Graph scopes align with
webApiPermissionRequests and require admin consent
- Never store secrets in client-side code
Performance
- Lazy-load heavy components and libraries
- Use dynamic imports when appropriate
- Minimize bundle size
- Avoid unnecessary re-renders and excessive state
- Virtualize large lists and tables
- Avoid state updates in render loops
Security
- Sanitize and validate all user input
- Respect tenant and site permissions
- Validate API responses before usage
- No Secrets: Never put client secrets or API keys in client-side code.
- Least Privilege: Suggest the minimum required
webApiPermissionRequests in package-solution.json.
- DOM Access: Never use
document.getElementById. Use React useRef.
- Avoid
dangerouslySetInnerHTML unless the content is sanitized
Testing & Quality
- Write unit tests for services and core logic
- Use Jest + React Testing Library for components and hooks
- Enforce ESLint and Prettier
- Keep dependencies updated
- Remove dead or commented-out code, unused imports and console logs before shipping
Accessibility
- Ensure keyboard navigation and visible focus states
- Provide labels and aria attributes for all interactive controls
- Validate color contrast when using theme tokens
Anti-Patterns to Avoid
- Hardcoded strings, colors, or dates
- Data access embedded in React components
- Direct DOM access instead of
useRef
- Skipping error states or swallowing exceptions
- Rendering large lists without virtualization
- Accessibility regressions (missing labels, focus traps, low contrast)
Do / Don't (Quick Scan)
| Do | Don't |
|---|
Use strings.<Key> and placeholders | Hardcode user-facing strings |
Use themeVariant and Fluent UI tokens | Hardcode hex colors |
| Centralize APIs in services | Call REST/Graph from components |
Use @pnp/graph when available | Default to MSGraphClientV3 |
| Add keyboard support and labels | Ship UI without a11y checks |
Telemetry & Logging
- Use
@pnp/logging or SPFx Log for error and diagnostic logging
- Never log secrets or PII
Checklist
Before generating SPFx code, follow these steps:
- Context Check: Is this a Web Part, an Extension (Application Customizer, ListView), or a Library Component?
- Environment Check: Check
Environment.type (Local, SharePoint, Classic) to avoid errors during local workbench testing.
- Dependency Check: Ensure
@pnp/sp and @pnp/graph imports match v4+ syntax (imports from @pnp/sp/presets/all are deprecated; use selective imports like @pnp/sp/webs).
- Error Handling: Wrap all async calls in
try/catch blocks and define a UI state for errors.
Code Template: Functional Web Part
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import { MyComponent } from './components/MyComponent';
import { IMyComponentProps } from './components/IMyComponentProps';
export interface IMyWebPartProps {
description: string;
}
export default class MyWebPart extends BaseClientSideWebPart<IMyWebPartProps> {
private _sp: ReturnType<typeof spfi>;
protected async onInit(): Promise<void> {
await super.onInit();
// Initialize PnPjs
this._sp = spfi().using(SPFx(this.context));
}
public render(): void {
const element: React.ReactElement<IMyComponentProps> = React.createElement(
MyComponent,
{
description: this.properties.description,
context: this.context,
sp: this._sp
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
}
Expected Outcomes
When this skill is applied, agent should:
- Generate idiomatic SPFx + React + TypeScript code
- Highlight and explain SPFx anti-patterns
- Enforce modular, service-based architecture
- Apply localization, Sass modules and API best practices
- Prefer modern tooling (Heft) and current guidance
Tone
- Clear, pragmatic and professional
- Explain why recommendations matter
Example Prompt
- Review this SPFx solution and refactor it using SPFx best practices, including localization, Sass modules, Graph & SharePoint access and Heft-based tooling.
Additional Prompt Examples
-
Scaffold a new SPFx React web part using PnPjs v4, strict TypeScript, localization with loc and .module.scss styling.
-
Refactor this web part to move all REST calls into services, add proper error handling and remove any hardcoded strings.
-
Build an Application Customizer that injects a command bar using Fluent UI, with theme-aware styling and no hardcoded colors.
-
Decide whether to use @pnp/graph or MSGraphClientV3 for this Graph call and explain why.
-
Audit this solution for performance and accessibility issues, then provide prioritized fixes.
-
Update this project to a Heft-based build and remove any nonstandard gulp customizations.
-
Add a new web part to this existing SPFx solution, matching its architecture, localization and theming patterns.
-
Add a Field Customizer to this solution using Fluent UI and theme tokens, with no direct DOM access.
-
Migrate this legacy SPFx web part to a service-based architecture with PnPjs v4 and strict TypeScript.
Non-Goals
- Classic (non-SPFx) SharePoint customizations
- Backend-only implementations
- Over-optimization at the expense of readability