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
1---2name: spfx-best-practices3description: Enforces SharePoint Framework (SPFx) best practices when generating, reviewing or refactoring SPFx code. Ensures solutions are modern, maintainable, performant, secure and aligned with official guidance and community patterns.4---56## When to Use7Use this skill when:8- Creating or scaffolding new SPFx **web parts**, **extensions** (Application Customizers, Field Customizers, Command Sets) or libraries9- Reviewing or refactoring existing SPFx projects10- Extending existing solutions with new web parts or extensions while maintaining consistent patterns11- Answering questions about SPFx architecture, React, TypeScript, localization, styling (Sass), data access, authentication, Microsoft Graph, SharePoint APIs or tooling1213## Scope14Applies to:15- SPFx **web parts**, **extensions** and **libraries**16- **React** with TypeScript17- **Localization** (`loc` resources)18- **Styling** with **Sass modules**19- **Data access** (SharePoint REST, Microsoft Graph, Entra ID–secured APIs)20- SPFx **toolchain** (Heft / gulp / webpack)21- Modern SPFx development workflows2223## Technology Stack Constraints24When generating code, adhere to these specific library versions and standards unless instructed otherwise:25* **Framework:** SharePoint Framework (SPFx)26* **UI Library:** Fluent UI React (`@fluentui/react`)27* **Data Access:** PnPjs v4 (`@pnp/sp`, `@pnp/graph`, `@pnp/logging`)28* **Language:** TypeScript29* **State Management:** React Hooks30* **Styling:** CSS Modules (`.module.scss`) or Fluent UI Styling (`mergeStyles`)3132## Best Practices to Enforce3334### Project Structure & Architecture35- Use a **feature-based** or **layered** folder structure:3637```text38src/39common/40controls/41helpers/42hooks/43models/44services/45webparts/46extensions/47```4849- Apply **Separation of Concerns**50- Keep UI, business logic and data access isolated51- Prefer reusable services over inline API logic5253### Toolchain & Build54- Target the **latest supported SPFx version** (e.g. 1.22.x+) if available.55 - Use **Heft** as the primary build orchestrator instead of gulp when starting new projects56- Avoid custom gulp hacks unless absolutely required57- Do not override toolchain defaults unless there is a documented, reproducible need58- Avoid unsupported patches and nonstandard build steps59- Keep configuration minimal and aligned with SPFx defaults60- Validate guidance against current SPFx release notes before shipping6162### TypeScript & Code Quality63- Enable strict TypeScript settings64- Avoid `any`; use interfaces, enums and generics65- Prefer `async/await`66- Keep utilities framework-agnostic where possible6768### React Best Practices69- Prefer **functional components** and **React Hooks**70- Keep components small and focused71- Extract logic into custom hooks or services72- Memoize expensive operations (`useMemo`, `useCallback`)73- Use Fluent UI for consistency and accessibility7475### Localization76- Use SPFx `loc` files for all user-facing strings77- Never hardcode display text78- Reference strings via `strings.<Key>`79- Ensure graceful fallback for missing translations80- Avoid string concatenation; use placeholders for plurals, dates and numbers8182### Styling (Sass)83- Use `.module.scss` files scoped to components84- Centralize shared variables, mixins and themes85- Avoid global CSS unless explicitly required86- Follow consistent naming conventions87- **Controls:** Use standard Fluent UI controls to match the M365 look and feel.88- **Theming:** strictly use `ThemeProvider` or the `themeVariant` object passed from the base context.89 * *Rule:* Never hardcode hex colors (e.g., `#0078d4`). Use `semanticColors` (e.g., `theme.semanticColors.bodyText`).90- **Tokens:** Prefer Fluent UI theme tokens over custom Sass variables for color and typography9192### Data Access Patterns93- Centralize data access in service classes94- Use **PnPjs** for most SharePoint operations if available95- Use **SPHttpClient** when:96 - Performing simple or low-level REST calls97 - Avoiding additional abstractions98- Handle errors, throttling and retries explicitly99- 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.100101#### Decision Matrix: PnPjs vs Native Clients102- Use **@pnp/sp** for SharePoint data access whenever possible103- Use **@pnp/graph** for Microsoft Graph when PnPjs is available104- Use **MSGraphClientV3** only when PnPjs is not available or cannot be added105- Use **SPHttpClient** for minimal, low-level REST calls or bundle size constraints106107### Authentication & API Usage108- Use **SPHttpClient** or PnPjs for SharePoint REST APIs109- Use **MSGraphClientV3** for Microsoft Graph access when PnPjs is not available110- Use **AadTokenProvider** for Entra ID–secured custom APIs111- Request **least-privilege** permissions112- Ensure Graph scopes align with `webApiPermissionRequests` and require admin consent113- Never store secrets in client-side code114115### Performance116- Lazy-load heavy components and libraries117- Use dynamic imports when appropriate118- Minimize bundle size119- Avoid unnecessary re-renders and excessive state120- Virtualize large lists and tables121- Avoid state updates in render loops122123### Security124- Sanitize and validate all user input125- Respect tenant and site permissions126- Validate API responses before usage127- **No Secrets:** Never put client secrets or API keys in client-side code.128- **Least Privilege:** Suggest the minimum required `webApiPermissionRequests` in `package-solution.json`.129- **DOM Access:** Never use `document.getElementById`. Use React `useRef`.130- Avoid `dangerouslySetInnerHTML` unless the content is sanitized131132### Testing & Quality133- Write unit tests for services and core logic134- Use **Jest** + **React Testing Library** for components and hooks135- Enforce ESLint and Prettier136- Keep dependencies updated137- Remove dead or commented-out code, unused imports and console logs before shipping138139### Accessibility140- Ensure keyboard navigation and visible focus states141- Provide labels and aria attributes for all interactive controls142- Validate color contrast when using theme tokens143144### Anti-Patterns to Avoid145- Hardcoded strings, colors, or dates146- Data access embedded in React components147- Direct DOM access instead of `useRef`148- Skipping error states or swallowing exceptions149- Rendering large lists without virtualization150- Accessibility regressions (missing labels, focus traps, low contrast)151152### Do / Don't (Quick Scan)153| Do | Don't |154| --- | --- |155| Use `strings.<Key>` and placeholders | Hardcode user-facing strings |156| Use `themeVariant` and Fluent UI tokens | Hardcode hex colors |157| Centralize APIs in services | Call REST/Graph from components |158| Use `@pnp/graph` when available | Default to `MSGraphClientV3` |159| Add keyboard support and labels | Ship UI without a11y checks |160161### Telemetry & Logging162- Use `@pnp/logging` or SPFx `Log` for error and diagnostic logging163- Never log secrets or PII164165## Checklist166Before generating SPFx code, follow these steps:1671. **Context Check:** Is this a Web Part, an Extension (Application Customizer, ListView), or a Library Component?1682. **Environment Check:** Check `Environment.type` (Local, SharePoint, Classic) to avoid errors during local workbench testing.1693. **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`).1704. **Error Handling:** Wrap all async calls in `try/catch` blocks and define a UI state for errors.171172## Code Template: Functional Web Part173174```typescript175import * as React from 'react';176import * as ReactDom from 'react-dom';177import { Version } from '@microsoft/sp-core-library';178import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';179import { spfi, SPFx } from "@pnp/sp";180import "@pnp/sp/webs";181import "@pnp/sp/lists";182import "@pnp/sp/items";183184import { MyComponent } from './components/MyComponent';185import { IMyComponentProps } from './components/IMyComponentProps';186187export interface IMyWebPartProps {188 description: string;189}190191export default class MyWebPart extends BaseClientSideWebPart<IMyWebPartProps> {192 private _sp: ReturnType<typeof spfi>;193194 protected async onInit(): Promise<void> {195 await super.onInit();196 // Initialize PnPjs197 this._sp = spfi().using(SPFx(this.context));198 }199200 public render(): void {201 const element: React.ReactElement<IMyComponentProps> = React.createElement(202 MyComponent,203 {204 description: this.properties.description,205 context: this.context,206 sp: this._sp207 }208 );209 ReactDom.render(element, this.domElement);210 }211212 protected onDispose(): void {213 ReactDom.unmountComponentAtNode(this.domElement);214 }215216 protected get dataVersion(): Version {217 return Version.parse('1.0');218 }219}220```221222223## Expected Outcomes224When this skill is applied, agent should:225- Generate idiomatic SPFx + React + TypeScript code226- Highlight and explain SPFx anti-patterns227- Enforce modular, service-based architecture228- Apply localization, Sass modules and API best practices229- Prefer modern tooling (Heft) and current guidance230231## Tone232- Clear, pragmatic and professional233- Explain *why* recommendations matter234235## Example Prompt236- Review this SPFx solution and refactor it using SPFx best practices, including localization, Sass modules, Graph & SharePoint access and Heft-based tooling.237238## Additional Prompt Examples239- Scaffold a new SPFx React web part using PnPjs v4, strict TypeScript, localization with `loc` and `.module.scss` styling.240241- Refactor this web part to move all REST calls into services, add proper error handling and remove any hardcoded strings.242243- Build an Application Customizer that injects a command bar using Fluent UI, with theme-aware styling and no hardcoded colors.244245- Decide whether to use `@pnp/graph` or `MSGraphClientV3` for this Graph call and explain why.246247- Audit this solution for performance and accessibility issues, then provide prioritized fixes.248249- Update this project to a Heft-based build and remove any nonstandard gulp customizations.250251- Add a new web part to this existing SPFx solution, matching its architecture, localization and theming patterns.252253- Add a Field Customizer to this solution using Fluent UI and theme tokens, with no direct DOM access.254255- Migrate this legacy SPFx web part to a service-based architecture with PnPjs v4 and strict TypeScript.256257## Non-Goals258- Classic (non-SPFx) SharePoint customizations259- Backend-only implementations260- Over-optimization at the expense of readability