<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:media="http://search.yahoo.com/mrss/" >

<channel>
	<title>SharePoint Framework &#8211; SharePoint &amp; Microsoft Power Platform Tutorials &#8211; SPGuides</title>
	<atom:link href="https://www.spguides.com/category/sharepoint-framework/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.spguides.com</link>
	<description>Learn SharePoint, Power Platform, SPFx, etc, SharePoint training courses</description>
	<lastBuildDate>Sun, 03 May 2026 16:44:48 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.5</generator>

<image>
	<url>https://www.spguides.com/wp-content/uploads/2022/11/cropped-spguides-favicon-32x32.png</url>
	<title>SharePoint Framework &#8211; SharePoint &amp; Microsoft Power Platform Tutorials &#8211; SPGuides</title>
	<link>https://www.spguides.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>SPFx Environment Variables: A Practical Guide for Every Scenario</title>
		<link>https://www.spguides.com/spfx-environment-variables/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Sun, 03 May 2026 16:44:46 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[SPFx Environment Variables]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=132838</guid>

					<description><![CDATA[If you&#8217;ve ever worked on an SPFx project with a team, you&#8217;ve probably hit this problem: your&#160;serve.json&#160;has your personal SharePoint URL hardcoded, your colleague has a different tenant, and every time someone pulls the latest code from Git, something breaks. Sound familiar? That&#8217;s exactly what environment variables fix. And once you understand how they work ... <a title="SPFx Environment Variables: A Practical Guide for Every Scenario" class="read-more" href="https://www.spguides.com/spfx-environment-variables/" aria-label="Read more about SPFx Environment Variables: A Practical Guide for Every Scenario">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>If you&#8217;ve ever worked on an<a href="https://www.spguides.com/spfx-training-course/"> SPFx project</a> with a team, you&#8217;ve probably hit this problem: your&nbsp;<code>serve.json</code>&nbsp;has your personal SharePoint URL hardcoded, your colleague has a different tenant, and every time someone pulls the latest code from Git, something breaks. Sound familiar?</p>



<p>That&#8217;s exactly what environment variables fix. And once you understand how they work in SPFx, you&#8217;ll wonder how you ever managed without them.</p>



<p>Let me walk you through everything, from the simplest one-liner fix to more advanced patterns for build-time config injection, so you can pick the approach that fits your project.</p>



<p>Let me explain how to use <strong>SharePoint Framework (SPFx) environment variables</strong>.</p>



<h2 class="wp-block-heading" id="what-are-spfx-environment-variables-really">What Are SPFx Environment Variables, Really?</h2>



<p>Think of environment variables as settings that live&nbsp;<em>outside</em>&nbsp;your code. Instead of hardcoding&nbsp;<code>https://mytenant.sharepoint.com</code>&nbsp;directly in a config file or <a href="https://www.spguides.com/typescript-import-json-file/">TypeScript file</a>, you store it in your operating system (or a&nbsp;<code>.env</code>&nbsp;file), and your project just reads it from there.</p>



<p>This is incredibly useful when:</p>



<ul class="wp-block-list">
<li>You work in a team where everyone has a different SharePoint tenant URL</li>



<li>You deploy to multiple environments — dev, staging, production</li>



<li>You don&#8217;t want API keys or secrets accidentally committed to your Git repo</li>



<li>You want your CI/CD pipeline to inject the right values at build time</li>
</ul>



<p>If you want to learn SPFx development, check out our <a href="https://www.spguides.com/spfx-training-course/" target="_blank" rel="noreferrer noopener">SPFx training course</a>.</p>



<h2 class="wp-block-heading">Method 1: The <strong>SPFX_SERVE_TENANT_DOMAIN</strong> Built-In Variable</h2>



<p>This is the easiest method and requires zero npm packages. Microsoft built it directly into the SPFx toolchain.</p>



<p>Here&#8217;s how it works: when you run gulp serve or heft start, the build system looks for an OS environment variable called <code>SPFX_SERVE_TENANT_DOMAIN</code> and swaps out the <code>{tenantDomain}</code> placeholder in your <code>serve.json</code> automatically.</p>



<p><strong>Step 1 — Update your&nbsp;<code>serve.json</code></strong></p>



<p>Open&nbsp;<code>config/serve.json</code>&nbsp;and use the placeholder instead of a hardcoded URL:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/serve.schema.json",<br>  "port": 4321,<br>  "https": true,<br>  "initialPage": "https://{tenantDomain}/sites/mysite/_layouts/workbench.aspx"<br>}</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="e3e3e7" data-has-transparency="false" style="--dominant-color: #e3e3e7;" fetchpriority="high" decoding="async" width="1024" height="236" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-in-spfx-1024x236.avif" alt="environment variables in spfx" class="wp-image-134253 not-transparent" title="environment variables in spfx" srcset="https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-in-spfx-1024x236.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-in-spfx-300x69.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-in-spfx-768x177.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-in-spfx.avif 1334w" /></figure></div>


<p>Notice&nbsp;<code>{tenantDomain}</code>&nbsp;— The toolchain will replace this at runtime with the value of your OS environment variable.</p>



<p><strong>Step 2 — Set the environment variable</strong></p>



<p>On&nbsp;<strong>Windows (PowerShell)</strong>&nbsp;— temporary for this session only:</p>



<pre class="wp-block-preformatted">$env:SPFX_SERVE_TENANT_DOMAIN = "contoso.sharepoint.com"</pre>



<p>To make it permanent (so you don&#8217;t have to set it every time):</p>



<pre class="wp-block-preformatted">[System.Environment]::SetEnvironmentVariable("SPFX_SERVE_TENANT_DOMAIN", "contoso.sharepoint.com", "User")</pre>



<p>Here, update <span style="box-sizing: border-box; margin: 0px; padding: 0px;"><strong>&#8216;con</strong></span><strong>toso</strong>&#8216; with your tenant domain name.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="1d1b1c" data-has-transparency="false" style="--dominant-color: #1d1b1c;" decoding="async" width="1024" height="180" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/Environment-Variables-with-SPFx-1024x180.avif" alt="Environment Variables with SPFx" class="wp-image-134255 not-transparent" title="Environment Variables with SPFx" srcset="https://www.spguides.com/wp-content/uploads/2026/04/Environment-Variables-with-SPFx-1024x180.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/Environment-Variables-with-SPFx-300x53.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/Environment-Variables-with-SPFx-768x135.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/Environment-Variables-with-SPFx.avif 1476w" /></figure></div>


<p>After some time, reopen your <a href="https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/">SPFx web part </a>Terminal pane, and check whether the variable contains a value or not with this command <code>echo $env:SPFX_SERVE_TENANT_DOMAIN</code></p>



<p>On&nbsp;<strong>macOS / Linux</strong>:</p>



<pre class="wp-block-preformatted">export SPFX_SERVE_TENANT_DOMAIN="contoso.sharepoint.com"</pre>



<p>To persist it, add that line to your&nbsp;<code>~/.bashrc</code>&nbsp;or&nbsp;<code>~/.zshrc</code>.</p>



<p><strong>Step 3 — Run&nbsp;<code>gulp serve</code>&nbsp;as usual</strong></p>



<p>That&#8217;s it. The build toolchain replaces&nbsp;<code>{tenantDomain}</code>&nbsp;on the fly before opening the browser. No code changes, no config file edits per developer. </p>



<blockquote class="wp-block-quote has-base-background-color has-background is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>NOTE: </strong>If you are using SPFx solutions with gulp packages, then run the <code>gulp serve </code>command to test. In case you are on <code>SPFx version 1.22.*,</code> with the Heft-based tool chain, run the <code>Heft start</code> command.</p>
</blockquote>



<p>In the image below, you can see that the <strong>initialPage </strong>URL in <strong>serve.json</strong> has a placeholder called <strong>{tenantDomain}</strong>. Now, instead of hardcoding our SharePoint tenant domain directly in this URL, we created an environment variable called <strong>SPFX_SERVE_TENANT_DOMAIN</strong> and stored our tenant domain value in it. </p>



<p>So now when we run the heft start command, SPFx is smart enough to automatically read that environment variable and replace the {tenantDomain} placeholder with our actual tenant domain in the URL.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="647795" data-has-transparency="false" style="--dominant-color: #647795;" decoding="async" width="1024" height="482" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-1024x482.avif" alt="using environment variables in sharepoint framework" class="wp-image-134258 not-transparent" title="using environment variables in sharepoint framework" srcset="https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-1024x482.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-300x141.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-768x361.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-1536x723.avif 1536w, https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework.avif 1560w" /></figure></div>


<p><strong>Why I like this method:</strong>&nbsp;It&#8217;s the simplest possible solution for the most common pain point. It works out of the box with every SPFx version and requires no extra packages. The downside is it only handles the tenant domain/URL for&nbsp;<code>serve.json</code>&nbsp;— it doesn&#8217;t help with injecting variables into your TypeScript code.</p>



<h2 class="wp-block-heading" id="method-2-os-environment-variables-in-powershell-qu">Method 2: OS Environment Variables in PowerShell (Quick and Practical)</h2>



<p>Sometimes you just need to pass a value temporarily before running a command. <a href="https://www.spguides.com/install-pnp-powershell/">PowerShell </a>makes this very easy.</p>



<p><strong>Temporary (session only):</strong></p>



<pre class="wp-block-preformatted">$env:SPFX_API_KEY = "my-api-key-12345"<br>gulp serve</pre>



<p>This variable exists only until you close the terminal window.</p>



<p><strong>Permanent (User scope):</strong></p>



<pre class="wp-block-preformatted">[System.Environment]::SetEnvironmentVariable("SPFX_API_KEY", "my-api-key-12345", "User")</pre>



<p><strong>Permanent (Machine scope — needs admin):</strong></p>



<pre class="wp-block-preformatted">[System.Environment]::SetEnvironmentVariable("SPFX_API_KEY", "my-api-key-12345", "Machine")</pre>



<p><strong>Check if it&#8217;s set:</strong></p>



<pre class="wp-block-preformatted">$env:SPFX_API_KEY</pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="506685" data-has-transparency="false" style="--dominant-color: #506685;" loading="lazy" decoding="async" width="766" height="164" sizes="(max-width: 766px) 100vw, 766px" src="https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-for-current-session.avif" alt="using environment variables in sharepoint framework for current session" class="wp-image-134262 not-transparent" title="using environment variables in sharepoint framework for current session" srcset="https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-for-current-session.avif 766w, https://www.spguides.com/wp-content/uploads/2026/04/using-environment-variables-in-sharepoint-framework-for-current-session-300x64.avif 300w" /></figure></div>


<p><strong>Remove it:</strong></p>



<pre class="wp-block-preformatted"><em># From session only</em><br>Remove-Item Env:\SPFX_API_KEY<br><br><em># Permanently (User scope)</em><br>[System.Environment]::SetEnvironmentVariable("SPFX_API_KEY", $null, "User")</pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="395377" data-has-transparency="false" style="--dominant-color: #395377;" loading="lazy" decoding="async" width="812" height="244" sizes="(max-width: 812px) 100vw, 812px" src="https://www.spguides.com/wp-content/uploads/2026/04/remove-environment-variables-in-spfx-for-current-session.avif" alt="remove environment variables in spfx for current session" class="wp-image-134263 not-transparent" title="remove environment variables in spfx for current session" srcset="https://www.spguides.com/wp-content/uploads/2026/04/remove-environment-variables-in-spfx-for-current-session.avif 812w, https://www.spguides.com/wp-content/uploads/2026/04/remove-environment-variables-in-spfx-for-current-session-300x90.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/remove-environment-variables-in-spfx-for-current-session-768x231.avif 768w" /></figure></div>


<p>In the image above, you can see I removed the current session variable. When I check back, does it still contain a value? It shows empty.</p>



<p>This method is great for quick local testing. But if you&#8217;re working in a team, it gets tedious; every developer has to remember to set all the right variables manually. That&#8217;s where&nbsp;<code>.env</code>&nbsp;files come in.</p>



<h2 class="wp-block-heading">Method 3: Using .env Files with <code>dotenv</code> (Recommended for Teams)</h2>



<p>This is my favorite approach for team projects with the&nbsp;<strong>gulp-based toolchain</strong>&nbsp;(SPFx versions before 1.22). You define all your variables in a&nbsp;<code>.env</code>&nbsp;file, exclude them from version control, and dynamically inject them into Webpack during the build process.</p>



<p><strong>Step 1 — &nbsp;Install Required Packages</strong></p>



<p>Install dotenv to read the files, and cross-env to easily switch environments across Windows, Mac, and CI/CD pipelines.</p>



<pre class="wp-block-preformatted">npm install dotenv cross-env --save-dev</pre>



<p><strong>Step 2 — Create your Environment Files</strong></p>



<p>Create a folder named <strong>env </strong>at the root of your project, and create a file named <strong>dev.env</strong> (for local development) and prod.env (for production).</p>



<pre class="wp-block-preformatted"># env/dev.env<br>SPFX_API_BASE_URL=https://dev-api.contoso.com<br>SPFX_APP_INSIGHTS_KEY=dev-abc123-xyz<br>SPFX_ENVIRONMENT=development</pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f1eeee" data-has-transparency="false" style="--dominant-color: #f1eeee;" loading="lazy" decoding="async" width="836" height="238" sizes="(max-width: 836px) 100vw, 836px" src="https://www.spguides.com/wp-content/uploads/2026/04/setup-environment-variables-in-spfx-web-part.avif" alt="setup environment variables in spfx web part" class="wp-image-134287 not-transparent" title="setup environment variables in spfx web part" srcset="https://www.spguides.com/wp-content/uploads/2026/04/setup-environment-variables-in-spfx-web-part.avif 836w, https://www.spguides.com/wp-content/uploads/2026/04/setup-environment-variables-in-spfx-web-part-300x85.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/setup-environment-variables-in-spfx-web-part-768x219.avif 768w" /></figure></div>


<p><strong>Step 3 — Add environment files to .gitignore</strong></p>



<p>This is critical. You never want to commit API keys or production secrets to your repository.</p>



<pre class="wp-block-preformatted"># .gitignore<br>env/*.env<br>!env/sample.env</pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f2f2f2" data-has-transparency="false" style="--dominant-color: #f2f2f2;" loading="lazy" decoding="async" width="680" height="454" sizes="(max-width: 680px) 100vw, 680px" src="https://www.spguides.com/wp-content/uploads/2026/04/spfx-development-environment-variables-setup.avif" alt="spfx development environment variables setup" class="wp-image-134288 not-transparent" title="spfx development environment variables setup" srcset="https://www.spguides.com/wp-content/uploads/2026/04/spfx-development-environment-variables-setup.avif 680w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-development-environment-variables-setup-300x200.avif 300w" /></figure></div>


<p>(Tip: It is good practice to commit a sample.env with dummy values so new developers know what variables they need to configure).</p>



<p><strong>Step 4 — Update gulpfile.js for Dynamic Injection</strong></p>



<p>Instead of hardcoding every variable, we can configure Webpack to automatically find and inject any variable that starts with SPFX_. Replace your gulpfile.js with this:</p>



<pre class="wp-block-preformatted">'use strict';<br><br>const gulp = require('gulp');<br>const build = require('@microsoft/sp-build-web');<br>const webpack = require('webpack');<br>const dotenv = require('dotenv');<br>const fs = require('fs');<br>const path = require('path');<br><br>// 1. Determine the environment (default to 'dev')<br>const environment = process.env.NODE_ENV || 'dev';<br>const envPath = path.resolve(__dirname, `./env/${environment}.env`);<br><br>// 2. Load the file if it exists<br>let envConfig = {};<br>if (fs.existsSync(envPath)) {<br>  envConfig = dotenv.config({ path: envPath }).parsed || {};<br>} else {<br>  console.warn(`[!] Warning: ${envPath} not found. Proceeding without env injection.`);<br>}<br><br>// 3. Merge into Webpack configuration<br>build.configureWebpack.mergeConfig({<br>  additionalConfiguration: (generatedConfig) =&gt; {<br>    const definitions = {};<br><br>    Object.keys(envConfig).forEach((key) =&gt; {<br>      if (key.startsWith('SPFX_')) {<br>        definitions[`process.env.${key}`] = JSON.stringify(envConfig[key]);<br>      }<br>    });<br><br>    generatedConfig.plugins.push(new webpack.DefinePlugin(definitions));<br>    return generatedConfig;<br>  }<br>});<br><br>// 4. Force task registration (Fixes "Task never defined" error)<br>let getTasks = build.rig.getTasks;<br>build.rig.getTasks = function () {<br>  let result = getTasks.call(build.rig);<br>  // Ensure serve is properly mapped<br>  result.set('serve', result.get('serve-deprecated') || result.get('serve'));<br>  return result;<br>};<br><br>// 5. Initialize build<br>build.initialize(gulp);<br></pre>



<p><strong>Step 5 — Add TypeScript Typings (Crucial for SPFx)</strong></p>



<p>To prevent <a href="https://www.spguides.com/get-key-by-value-from-enum-string-in-typescript/">TypeScript </a>from complaining that process.env is undefined, create or update a <strong>global.d.ts</strong> file inside your <strong>src </strong>folder:</p>



<pre class="wp-block-preformatted">// src/global.d.ts<br>declare interface NodeJS {<br>  env: {<br>    NODE_ENV: 'dev' | 'prod';<br>    SPFX_API_BASE_URL: string;<br>    SPFX_APP_INSIGHTS_KEY: string;<br>    SPFX_ENVIRONMENT: string;<br>    [key: string]: string | undefined;<br>  };<br>}<br>declare var process: NodeJS;</pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f1f0f0" data-has-transparency="false" style="--dominant-color: #f1f0f0;" loading="lazy" decoding="async" width="796" height="400" sizes="(max-width: 796px) 100vw, 796px" src="https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-in-gulp-tool-chain.avif" alt="spfx environment variables setup in gulp tool chain" class="wp-image-134289 not-transparent" title="spfx environment variables setup in gulp tool chain" srcset="https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-in-gulp-tool-chain.avif 796w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-in-gulp-tool-chain-300x151.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-in-gulp-tool-chain-768x386.avif 768w" /></figure></div>


<p><strong>Step 6 — Use Variables in your TypeScript/React Code</strong></p>



<p>Because of the typings in Step 5, you no longer need&nbsp;<code>as string</code>. You get full IntelliSense autocomplete natively in<a href="https://www.spguides.com/run-powershell-script-in-visual-studio-code/"> VS Code</a>.</p>



<pre class="wp-block-preformatted">import * as React from 'react';<br>import styles from './Listitems.module.scss';<br>import type { IListitemsProps } from './IListitemsProps';<br>import { escape } from '@microsoft/sp-lodash-subset';<br><br>export default class Listitems extends React.Component&lt;IListitemsProps&gt; {<br>  public render(): React.ReactElement&lt;IListitemsProps&gt; {<br>    const {<br>      description,<br>      isDarkTheme,<br>      environmentMessage,<br>      hasTeamsContext,<br>      userDisplayName<br>    } = this.props;<br><br>    return (<br>      &lt;section className={`${styles.listitems} ${hasTeamsContext ? styles.teams : ''}`}&gt;<br>        &lt;div className={styles.welcome}&gt;<br>          &lt;img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} /&gt;<br>          &lt;h2&gt;Well done, {escape(userDisplayName)}!&lt;/h2&gt;<br>          &lt;div&gt;{environmentMessage}&lt;/div&gt;<br>          &lt;div&gt;Web part property value: &lt;strong&gt;{escape(description)}&lt;/strong&gt;&lt;/div&gt;<br>        &lt;/div&gt;<br><br>        {/* --- CUSTOM ENVIRONMENT VARIABLES BLOCK --- */}<br>        &lt;div style={{ backgroundColor: '#e1dfdd', padding: '15px', margin: '20px 0', borderRadius: '4px', color: '#323130' }}&gt;<br>          &lt;h3 style={{ marginTop: 0 }}&gt;Environment Variables Test&lt;/h3&gt;<br>          &lt;p style={{ margin: '5px 0' }}&gt;&lt;strong&gt;Environment:&lt;/strong&gt; {process.env.SPFX_ENVIRONMENT}&lt;/p&gt;<br>          &lt;p style={{ margin: '5px 0' }}&gt;&lt;strong&gt;API Base URL:&lt;/strong&gt; {process.env.SPFX_API_BASE_URL}&lt;/p&gt;<br>          &lt;p style={{ margin: '5px 0' }}&gt;&lt;strong&gt;App Insights Key:&lt;/strong&gt; {process.env.SPFX_APP_INSIGHTS_KEY}&lt;/p&gt;<br>        &lt;/div&gt;<br>        {/* ---------------------------------------- */}<br>      &lt;/section&gt;<br>    );<br>  }<br>}</pre>



<p><strong>Step 7 — Running and Building for Different Environments<br></strong>Now, you can easily switch between environments using&nbsp;<code>cross-env</code>. You can add these commands directly to the&nbsp;<code>"scripts"</code>&nbsp;section of your&nbsp;<code>package.json</code>:</p>



<pre class="wp-block-code"><code>"scripts": {
  "serve": "cross-env NODE_ENV=dev gulp serve",
  "build:prod": "cross-env NODE_ENV=prod gulp bundle --ship &amp;&amp; gulp package-solution --ship"
}</code></pre>



<p>Then run the gulp serve command. In the <a href="https://www.spguides.com/retrieve-sharepoint-list-items-using-sharepoint-framework/">SPFx web part</a>, you&#8217;ll see the environment variables we defined:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f0f0ee" data-has-transparency="false" style="--dominant-color: #f0f0ee;" loading="lazy" decoding="async" width="1016" height="686" sizes="(max-width: 1016px) 100vw, 1016px" src="https://www.spguides.com/wp-content/uploads/2026/04/configure-environment-variables-for-spfx-with-gulp-package-tool-chain.avif" alt="configure environment variables for spfx with gulp package tool chain" class="wp-image-134282 not-transparent" title="configure environment variables for spfx with gulp package tool chain" srcset="https://www.spguides.com/wp-content/uploads/2026/04/configure-environment-variables-for-spfx-with-gulp-package-tool-chain.avif 1016w, https://www.spguides.com/wp-content/uploads/2026/04/configure-environment-variables-for-spfx-with-gulp-package-tool-chain-300x203.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/configure-environment-variables-for-spfx-with-gulp-package-tool-chain-768x519.avif 768w" /></figure></div>


<h2 class="wp-block-heading" id="method-4-webpack-defineplugin--injecting-variables">Method 4: Webpack DefinePlugin — Injecting Variables at Build Time</h2>



<p>The Webpack DefinePlugin is the engine behind method 3. Sometimes it&#8217;s useful to understand it directly, especially for CI/CD pipelines where you want the pipeline itself to inject values.</p>



<p>Here&#8217;s a standalone example:</p>



<pre class="wp-block-preformatted"><em>// gulpfile.js</em><br>build.configureWebpack.mergeConfig({<br>  additionalConfiguration: (generatedConfig) =&gt; {<br>    const isDebugMode = generatedConfig.plugins<br>      .find(p =&gt; p instanceof webpack.DefinePlugin)<br>      ?.definitions?.DEBUG;<br><br>    generatedConfig.plugins.find(p =&gt; p instanceof webpack.DefinePlugin)<br>      .definitions['process.env.API_ENDPOINT'] = isDebugMode<br>        ? JSON.stringify('https://dev-api.contoso.com')<br>        : JSON.stringify(process.env.API_ENDPOINT);<br><br>    return generatedConfig;<br>  }<br>});</pre>



<p>In this case, during&nbsp;<code>gulp serve</code>&nbsp;(debug mode), it uses the dev URL. During&nbsp;<code>gulp bundle --ship</code>&nbsp;(production), it reads from the OS environment variable&nbsp;<code>API_ENDPOINT</code>&nbsp;— which in a DevOps pipeline you&#8217;d set as a secret pipeline variable.</p>



<p>This is perfect for things like:</p>



<ul class="wp-block-list">
<li>Azure Application Insights instrumentation keys</li>



<li>Backend API endpoints</li>



<li>Feature flags</li>
</ul>



<h2 class="wp-block-heading" id="method-5-spfx-122-with-heft-new-build-system">Method 5: SPFx 1.22+ with Heft (New Build System)</h2>



<p>If you&#8217;re <a href="https://www.spguides.com/set-up-spfx-project-with-heft/" target="_blank" rel="noreferrer noopener">starting a fresh project with SPFx 1.22</a> or later, you&#8217;ll notice that <code>gulp</code> has been replaced by <strong>Heft</strong> as the default build system. Heft is a config-driven task orchestrator from Rush Stack that Microsoft now recommends for all new projects.</p>



<p>With Heft, you can&#8217;t use&nbsp;<code>gulpfile.js</code>&nbsp;the same way. Here are the main approaches.</p>



<h2 class="wp-block-heading" id="the-recommended-approach-webpack-patch-plugin">The Recommended Approach: Webpack Patch Plugin</h2>



<p>Microsoft&#8217;s official way to customize WebPack in Heft projects is through a&nbsp;<code>webpack-patch.json</code>&nbsp;config file.</p>



<p><strong>Step 1: Create the JSON Configuration File</strong></p>



<p>In your project&#8217;s <strong>config </strong>folder, create a new file named <strong>webpack-patch.json</strong> and add the following content:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/webpack-patch.schema.json",<br>  "patchFiles": ["./config/webpack-patch/env-inject.js"]<br>}</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f3f2f3" data-has-transparency="false" style="--dominant-color: #f3f2f3;" loading="lazy" decoding="async" width="1024" height="313" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/Environment-variables-in-a-React-SharePoint-Webpart-1024x313.avif" alt="Environment variables in a React SharePoint Webpart" class="wp-image-134271 not-transparent" title="Environment variables in a React SharePoint Webpart" srcset="https://www.spguides.com/wp-content/uploads/2026/04/Environment-variables-in-a-React-SharePoint-Webpart-1024x313.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/Environment-variables-in-a-React-SharePoint-Webpart-300x92.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/Environment-variables-in-a-React-SharePoint-Webpart-768x234.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/Environment-variables-in-a-React-SharePoint-Webpart.avif 1304w" /></figure></div>


<p><strong>Step 2: Create the JavaScript Patch File</strong></p>



<p>You need to create a new folder inside the <strong>config </strong>folder to hold your script.</p>



<ul class="wp-block-list">
<li>Create a folder named webpack-patch inside the config folder.</li>



<li>Inside that new folder, create a file named <strong>env-inject.js</strong> and add this code:</li>
</ul>



<pre class="wp-block-preformatted">const dotenv = require('dotenv');<br>const fs = require('fs');<br>const path = require('path');<br><br>// Resolve webpack from your project root — no rig path guessing needed<br>const webpackPath = require.resolve('webpack', { paths: [path.resolve(__dirname, '../../')] });<br>const webpack = require(webpackPath);<br><br>module.exports = function(webpackConfig) {<br>  const NODE_ENV = process.env.NODE_ENV || 'dev';<br>  const envPath = path.resolve(__dirname, `../../env/${NODE_ENV}.env`);<br><br>  if (!fs.existsSync(envPath)) {<br>    console.warn(`Warning: ${envPath} not found. Skipping env injection.`);<br>    return webpackConfig;<br>  }<br><br>  const envConfig = dotenv.parse(fs.readFileSync(envPath));<br>  const definitions = {};<br><br>  Object.entries(envConfig)<br>    .filter(([key]) =&gt; key.startsWith('SPFX_'))<br>    .forEach(([key, value]) =&gt; {<br>      definitions[`process.env.${key}`] = JSON.stringify(value);<br>    });<br><br>  webpackConfig.plugins.push(new webpack.DefinePlugin(definitions));<br>  return webpackConfig;<br>};</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f4f4f5" data-has-transparency="false" style="--dominant-color: #f4f4f5;" loading="lazy" decoding="async" width="1024" height="606" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-step-by-step-1024x606.avif" alt="spfx environment variables setup step by step" class="wp-image-134272 not-transparent" title="spfx environment variables setup step by step" srcset="https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-step-by-step-1024x606.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-step-by-step-300x177.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-step-by-step-768x454.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-environment-variables-setup-step-by-step.avif 1278w" /></figure></div>


<p><strong>Step 3: Install Dependencies and Create Environment Files</strong></p>



<p>Your patch file uses dotenv to parse environment files, so you need to install it.</p>



<ul class="wp-block-list">
<li>Open your terminal and run:</li>
</ul>



<pre class="wp-block-code"><code>npm install dotenv --save-dev</code></pre>



<ul class="wp-block-list">
<li>In the root of your project (the same level as&nbsp;<code>src</code>&nbsp;and&nbsp;<code>config</code>), create a folder named&nbsp;<code>env</code>.</li>



<li>Inside the&nbsp;<strong><code>env</code>&nbsp;</strong>folder, create a file named&nbsp;<strong><code>dev.env</code>&nbsp;</strong>and define your variables. They&nbsp;<strong>must</strong>&nbsp;start with&nbsp;<code>SPFX_</code>:</li>
</ul>



<pre class="wp-block-code"><code>SPFX_API_BASE_URL=https://my-dev-api.azurewebsites.net
SPFX_GREETING_MESSAGE=Hello from Dev Environment</code></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f4f3f3" data-has-transparency="false" style="--dominant-color: #f4f3f3;" loading="lazy" decoding="async" width="912" height="236" sizes="(max-width: 912px) 100vw, 912px" src="https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-setup-in-windows-10-for-spfx.avif" alt="environment variables setup in windows 10 for spfx" class="wp-image-134275 not-transparent" title="environment variables setup in windows 10 for" srcset="https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-setup-in-windows-10-for-spfx.avif 912w, https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-setup-in-windows-10-for-spfx-300x78.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/environment-variables-setup-in-windows-10-for-spfx-768x199.avif 768w" /></figure></div>


<p><strong>Step 4: Add TypeScript Typings (Crucial for SPFx)<br></strong>By default, TypeScript will throw an error if you try to type process.env.SPFX_API_BASE_URL because it doesn&#8217;t know what process.env is. You need to define these types so your SPFx web part compiles successfully.</p>



<ul class="wp-block-list">
<li>In your&nbsp;<code>src</code>&nbsp;folder, create a file named&nbsp;<code><strong>global.d.ts</strong></code>&nbsp;(or open it if it already exists).</li>



<li>Add the following TypeScript declaration to let the compiler know about your custom variables:</li>
</ul>



<pre class="wp-block-code"><code>declare interface NodeJS {
  env: {
    NODE_ENV: 'dev' | 'production';
    SPFX_API_BASE_URL: string;
    SPFX_GREETING_MESSAGE: string;
    &#91;key: string]: string | undefined;
  };
}
declare var process: NodeJS;</code></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f2f0f1" data-has-transparency="false" style="--dominant-color: #f2f0f1;" loading="lazy" decoding="async" width="738" height="440" sizes="(max-width: 738px) 100vw, 738px" src="https://www.spguides.com/wp-content/uploads/2026/04/Configuring-Environment-Variables-for-SPFx-Development.avif" alt="Configuring Environment Variables for SPFx Development" class="wp-image-134276 not-transparent" title="Configuring Environment Variables for SPFx Development" srcset="https://www.spguides.com/wp-content/uploads/2026/04/Configuring-Environment-Variables-for-SPFx-Development.avif 738w, https://www.spguides.com/wp-content/uploads/2026/04/Configuring-Environment-Variables-for-SPFx-Development-300x179.avif 300w" /></figure></div>


<p><strong>Step 5: How to Test and Use It</strong></p>



<p>Now you can safely use your environment variables anywhere inside your web part component (e.g., inside src/webparts/yourWebPart/components/YourWebPart.tsx).</p>



<ul class="wp-block-list">
<li>Open your main <a href="https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/">React component</a> or web part TypeScript file.</li>



<li>Add a simple HTML tags to render it on the screen:</li>
</ul>



<pre class="wp-block-code"><code>public render(): React.ReactElement&lt;IHeftProjectProps&gt; {
    const {
      description,
      isDarkTheme,
      environmentMessage,
      hasTeamsContext,
      userDisplayName
    } = this.props;

    return (
      &lt;section className={`${styles.heftProject} ${hasTeamsContext ? styles.teams : ''}`}&gt;
        &lt;div className={styles.welcome}&gt;
          &lt;img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} /&gt;
          &lt;h2&gt;Well done, {escape(userDisplayName)}!&lt;/h2&gt;
          &lt;div&gt;{environmentMessage}&lt;/div&gt;
          &lt;div&gt;Web part property value: &lt;strong&gt;{escape(description)}&lt;/strong&gt;&lt;/div&gt;
        &lt;/div&gt;
        
        {/* --- CUSTOM ENVIRONMENT VARIABLES BLOCK --- */}
        &lt;div style={{ backgroundColor: '#f4f4f4', padding: '15px', marginTop: '20px', borderRadius: '4px' }}&gt;
          &lt;h3&gt;Environment Variables Test&lt;/h3&gt;
          &lt;p&gt;&lt;strong&gt;Greeting:&lt;/strong&gt; {process.env.SPFX_GREETING_MESSAGE}&lt;/p&gt;
          &lt;p&gt;&lt;strong&gt;API Base URL:&lt;/strong&gt; {process.env.SPFX_API_BASE_URL}&lt;/p&gt;
        &lt;/div&gt;
        {/* ---------------------------------------- */}

      &lt;/section&gt;
    );
  }</code></pre>



<p>To test the <strong>dev.env</strong> variables, simply run your standard Heft command. Because the script defaults to dev, it will automatically pick up <strong>dev.env</strong></p>



<pre class="wp-block-code"><code>heft start</code></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f3f4f2" data-has-transparency="false" style="--dominant-color: #f3f4f2;" loading="lazy" decoding="async" width="1004" height="676" sizes="(max-width: 1004px) 100vw, 1004px" src="https://www.spguides.com/wp-content/uploads/2026/04/access-environment-variables-within-spfx-web-part.avif" alt="access environment variables within spfx web part" class="wp-image-134269 not-transparent" title="access environment variables within spfx web part" srcset="https://www.spguides.com/wp-content/uploads/2026/04/access-environment-variables-within-spfx-web-part.avif 1004w, https://www.spguides.com/wp-content/uploads/2026/04/access-environment-variables-within-spfx-web-part-300x202.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/access-environment-variables-within-spfx-web-part-768x517.avif 768w" /></figure></div>


<p><strong>Note:</strong> If you want to test a production environment (e.g., prod.env), you would run cross-env NODE_ENV=prod npm run build (assuming you have cross-env installed and configured in your package.json scripts)</p>



<h2 class="wp-block-heading" id="alternative-pre-build-typescript-generation-type-s">Alternative: Pre-Build TypeScript Generation (Type-Safe)</h2>



<p>If you want full TypeScript type safety and IDE autocomplete on your environment variables, this is the cleanest approach.</p>



<p><strong>Create&nbsp;<code>scripts/generate-env-config.js</code>:</strong></p>



<pre class="wp-block-preformatted">const fs = require('fs');<br>const dotenv = require('dotenv');<br><br>const NODE_ENV = process.env.NODE_ENV || 'dev';<br>const envConfig = dotenv.parse(fs.readFileSync(`./env/${NODE_ENV}.env`));<br><br>const spfxVars = Object.entries(envConfig)<br>  .filter(([key]) =&gt; key.startsWith('SPFX_'))<br>  .map(([key, value]) =&gt; `  ${key}: '${value}'`)<br>  .join(',\n');<br><br>const output = `// AUTO-GENERATED — Do not edit manually<br>export const ENV_CONFIG = {<br>${spfxVars}<br>} as const;<br>`;<br><br>fs.writeFileSync('src/utils/envConfig.generated.ts', output);<br>console.log('Environment config generated successfully.');</pre>



<p><strong>Update&nbsp;<code>package.json</code>&nbsp;scripts:</strong></p>



<pre class="wp-block-preformatted">"scripts": {<br>  "generate-env": "node scripts/generate-env-config.js",<br>  "start:dev": "cross-env NODE_ENV=dev npm run generate-env &amp;&amp; heft start",<br>  "start:prod": "cross-env NODE_ENV=prod npm run generate-env &amp;&amp; heft start"<br>}</pre>



<p><strong>Use it in your components:</strong></p>



<pre class="wp-block-preformatted">import { ENV_CONFIG } from '../utils/envConfig.generated';<br><br><em>// Full autocomplete and type checking!</em><br>const apiUrl = ENV_CONFIG.SPFX_API_BASE_URL;<br>const timeout = ENV_CONFIG.SPFX_API_TIMEOUT;</pre>



<p>The generated file is committed to&nbsp;<code>.gitignore</code>&nbsp;and rebuilt every time you run the start script.</p>



<h2 class="wp-block-heading" id="choosing-the-right-method">Choosing the Right Method</h2>



<p>Here&#8217;s a quick summary of when to use what:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Scenario</th><th>Best Method</th></tr></thead><tbody><tr><td>Just need the right tenant URL for&nbsp;<code>gulp serve</code></td><td><code>SPFX_SERVE_TENANT_DOMAIN</code>&nbsp;OS variable</td></tr><tr><td>Quick local testing, no team coordination needed</td><td>PowerShell&nbsp;<code>$env:</code>&nbsp;temporary variable</td></tr><tr><td>Team project on gulp-based SPFx (before v1.22)</td><td><code>.env</code>&nbsp;files +&nbsp;<code>dotenv</code>&nbsp;+ DefinePlugin in&nbsp;<code>gulpfile.js</code></td></tr><tr><td>CI/CD pipeline injecting secrets</td><td>OS env variables + DefinePlugin in&nbsp;<code>gulpfile.js</code>&nbsp;or webpack-patch</td></tr><tr><td>New project on SPFx 1.22+ with Heft</td><td>Webpack Patch method (<code>webpack-patch.json</code>)</td></tr><tr><td>Need type safety and autocomplete</td><td>Pre-Build TypeScript generation script</td></tr></tbody></table></figure>



<h2 class="wp-block-heading" id="common-mistakes-to-avoid">Common Mistakes to Avoid</h2>



<ul class="wp-block-list">
<li><strong>Committing&nbsp;<code>.env</code>&nbsp;files to Git.</strong>&nbsp;Always add&nbsp;<code>.env</code>,&nbsp;<code>*.env</code>, and&nbsp;<code>env/</code>&nbsp;to&nbsp;<code>.gitignore</code>.</li>



<li><strong>Forgetting the&nbsp;<code>SPFX_</code>&nbsp;prefix.</strong>&nbsp;Variables without this prefix often end up as&nbsp;<code>undefined</code>&nbsp;at runtime.</li>



<li><strong>Using&nbsp;<code>require('webpack')</code>&nbsp;in Heft projects.</strong>&nbsp;This causes silent build failures. Use the SPFx rig import instead.</li>



<li><strong>Not providing fallback values.</strong>&nbsp;Always use&nbsp;<code>process.env.MY_VAR || 'fallback'</code>&nbsp;so your build doesn&#8217;t break in environments where the variable isn&#8217;t set.</li>



<li><strong>Expecting runtime env access.</strong>&nbsp;Remember — DefinePlugin replaces values at&nbsp;<em>build time</em>, not runtime. The browser never sees&nbsp;<code>process.env</code>; it only sees the already-substituted string.</li>
</ul>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download Complete SPFx Solutions</a></div>
</div>



<h2 class="wp-block-heading">Conclusion</h2>



<p>I hope you found this article helpful. In this guide, I explained different ways to use <strong>environment variables in SPFx</strong>. I covered built-in variables, PowerShell options, .env files, and Webpack methods. I also shared recommended approaches and alternatives for different scenarios.</p>



<p>If you are working on SPFx projects, choose the method that fits your setup and needs. Start with simple options and move to advanced ones as required. Using environment variables will make your solution more flexible and easier to manage.</p>



<p>Also, you may like:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/sharepoint-framework-crud-operations-using-react/">SharePoint Framework: CRUD Operations using ReactJS</a></li>



<li><a href="https://www.spguides.com/pnp-react-pagination-control-spfx/">PnP React Pagination Control in SharePoint Framework (SPFx) Web Part</a></li>



<li><a href="https://www.spguides.com/spfx-fluent-ui-react-choicegroup-and-checkbox/">SPFx Fluent UI React Control: ChoiceGroup and Checkbox</a></li>



<li><a href="https://www.spguides.com/fluent-ui-react-combobox-control-in-spfx/">Fluent UI React ComboBox Control in SPFx</a></li>
</ul>



<p></p>



<p></p>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Migrate from Gulp based to Heft based Toolchain in SharePoint Framework (SPFx)</title>
		<link>https://www.spguides.com/migrate-gulp-to-heft-in-spfx/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Tue, 28 Apr 2026 16:34:21 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Migrate from Gulp based to Heft based Toolchain in SPFx]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=132844</guid>

					<description><![CDATA[If you&#8217;ve been building SharePoint Framework solutions for a while, you already know Gulp. It&#8217;s been the backbone of every SPFx project since day one — running your builds, serving the workbench, packaging your&#160;.sppkg&#160;files. But that era is officially over. With&#160;SPFx v1.22, Microsoft replaced the Gulp-based toolchain with&#160;Heft&#160;— a config-driven build orchestrator from the Rush ... <a title="Migrate from Gulp based to Heft based Toolchain in SharePoint Framework (SPFx)" class="read-more" href="https://www.spguides.com/migrate-gulp-to-heft-in-spfx/" aria-label="Read more about Migrate from Gulp based to Heft based Toolchain in SharePoint Framework (SPFx)">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>If you&#8217;ve been <a href="https://www.spguides.com/spfx-training-course/" target="_blank" rel="noreferrer noopener">building SharePoint Framework solutions</a> for a while, you already know Gulp. It&#8217;s been the backbone of every SPFx project since day one — running your builds, serving the workbench, packaging your&nbsp;<code>.sppkg</code>&nbsp;files. But that era is officially over.</p>



<p>With&nbsp;<strong>SPFx v1.22</strong>, Microsoft replaced the Gulp-based toolchain with&nbsp;<strong>Heft</strong>&nbsp;— a config-driven build orchestrator from the Rush Stack ecosystem. Starting with SPFx v1.23, all new projects will use Heft by default. And by v1.24, the Gulp-based pipeline will be officially unsupported.</p>



<p>So if you have existing projects still running on Gulp, now is the time to migrate. In this tutorial, I will explain how to <strong>migrate from a Gulp-based to a Heft-based toolchain in the SharePoint Framework (SPFx)</strong> step by step.</p>



<h2 class="wp-block-heading">What is Heft in SharePoint Framework?</h2>



<p>In&nbsp;<strong>SPFx (SharePoint Framework)</strong>,&nbsp;<strong>Heft</strong>&nbsp;is basically a&nbsp;<strong>build and task management tool</strong>&nbsp;that helps run and organize all the behind-the-scenes processes when you develop a SharePoint solution.</p>



<p>Think of Heft as a&nbsp;<strong>modern replacement for older tools like Gulp</strong>&nbsp;in SPFx. Starting from SPFx v1.22, Microsoft officially switched from Gulp to Heft to make builds cleaner and faster.</p>



<p>When you&#8217;re building an SPFx project, a lot of things need to happen automatically:</p>



<ul class="wp-block-list">
<li>Compile&nbsp;<strong>TypeScript → JavaScript</strong></li>



<li><strong>Bundle</strong>&nbsp;your code</li>



<li>Run&nbsp;<strong>linting</strong>&nbsp;(check code quality)</li>



<li>Execute&nbsp;<strong>tests</strong></li>



<li>Build the&nbsp;<strong>final package</strong>&nbsp;ready for SharePoint</li>
</ul>



<p><strong>Heft handles all of this automatically</strong>&nbsp;— you just run one command like&nbsp;<code>heft build</code>&nbsp;or&nbsp;<code>heft start</code>, and it takes care of the rest behind the scenes.</p>



<p>Instead of writing custom task scripts like you used to with Gulp, Heft uses simple&nbsp;<strong>JSON configuration files</strong>&nbsp;to define what to do, making your project easier to maintain and understand.</p>



<p>A new SPFx project already comes&nbsp;<strong>pre-configured with Heft</strong>&nbsp;through something called a&nbsp;<strong>rig</strong>&nbsp;(a shared settings package). So you don&#8217;t need to set anything up yourself — it just works out of the box.</p>



<p>Here&#8217;s a quick comparison between Gulp and Heft.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Area</th><th>Gulp (Legacy)</th><th>Heft (SPFx v1.22+)</th></tr></thead><tbody><tr><td>Core model</td><td>Custom JS tasks in&nbsp;<code>gulpfile.js</code></td><td>Config-driven with plugins and rigs</td></tr><tr><td>Extensibility</td><td>Write custom tasks per project</td><td>Use Heft plugins or patch files</td></tr><tr><td>Performance</td><td>Sequential tasks, no caching</td><td>Incremental builds and caching</td></tr><tr><td>Config location</td><td>Scattered across&nbsp;<code>gulpfile.js</code></td><td>Centralized JSON files (<code>heft.json</code>, etc.)</td></tr><tr><td>Scale</td><td>Hard to keep consistent across repos</td><td>Built to scale with Rush Stack monorepos</td></tr></tbody></table></figure>



<p>Heft makes SPFx development&nbsp;<strong>cleaner and more modern</strong>&nbsp;by replacing the old Gulp-based system with a structured, configuration-driven approach.</p>



<p>Check out <a href="https://www.spguides.com/set-up-spfx-project-with-heft/">Set Up Your SharePoint Framework (SPFx) Development Environment using Heft Toolchain</a></p>



<h2 class="wp-block-heading" id="before-you-start--a-few-things-to-check">Before You Start — A Few Things to Check</h2>



<p>Don&#8217;t jump straight to uninstalling packages. Do these first:</p>



<ul class="wp-block-list">
<li><strong>Back up your project.</strong>&nbsp;Either copy the folder or make sure all your code is committed to source control. The migration makes sweeping changes to your config files and&nbsp;<code>package.json</code>.</li>



<li><strong>Check your Node.js version.</strong>&nbsp;SPFx v1.22 requires Node v22. Run&nbsp;<code>node -v</code>&nbsp;to confirm. If you&#8217;re on an older version, update first.</li>



<li><strong>Check for gulp customizations.</strong>&nbsp;Open your&nbsp;<code>gulpfile.js</code>&nbsp;and look for any custom tasks — things like&nbsp;<code>build.configureWebpack.mergeConfig()</code>,&nbsp;<code>build.rig.addPreBuildTask()</code>, or custom copy/lint steps. You&#8217;ll need to translate these to Heft plugins after the migration. Note these down before you delete anything.</li>
</ul>



<h2 class="wp-block-heading">Migrate from Gulp based to Heft based Toolchain in SPFx</h2>



<p>Follow the steps below to migrate from Gulp based to Heft based Toolchain in SharePoint Framework (SPFx).</p>



<h3 class="wp-block-heading" id="step-1-uninstall-the-gulp-toolchain">Step 1: Uninstall the Gulp Toolchain</h3>



<p>The first thing to do is rip out the old <a href="https://www.spguides.com/no-gulpfile-found-spfx/" target="_blank" rel="noreferrer noopener">Gulp-based packages</a>. Run this command from your project root:</p>



<pre class="wp-block-preformatted">npm uninstall @microsoft/sp-build-web ajv gulp</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="161515" data-has-transparency="false" style="--dominant-color: #161515;" loading="lazy" decoding="async" width="1024" height="452" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/uninstall-gulp-cli-1024x452.avif" alt="uninstall gulp-cli" class="wp-image-133914 not-transparent" title="uninstall gulp cli" srcset="https://www.spguides.com/wp-content/uploads/2026/04/uninstall-gulp-cli-1024x452.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/uninstall-gulp-cli-300x133.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/uninstall-gulp-cli-768x339.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/uninstall-gulp-cli.avif 1082w" /></figure></div>


<p>Next, uninstall the TypeScript compiler wrapper. The default SPFx v1.21.1 project uses TypeScript 5.3, so:</p>



<pre class="wp-block-preformatted">npm uninstall @microsoft/rush-stack-compiler-5.3</pre>



<p>If your project uses a different <a href="https://www.spguides.com/typescript-enums/">TypeScript</a> version, replace&nbsp;<code>5.3</code>&nbsp;with whatever version you have. Check your&nbsp;<code>package.json</code>&nbsp;devDependencies — look for&nbsp;<code>@microsoft/rush-stack-compiler-*</code>.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="161515" data-has-transparency="false" style="--dominant-color: #161515;" loading="lazy" decoding="async" width="1024" height="422" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/install-specific-version-of-gulp-1024x422.avif" alt="install specific version of gulp" class="wp-image-133917 not-transparent" title="install specific version of gulp" srcset="https://www.spguides.com/wp-content/uploads/2026/04/install-specific-version-of-gulp-1024x422.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/install-specific-version-of-gulp-300x124.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/install-specific-version-of-gulp-768x317.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/install-specific-version-of-gulp.avif 1082w" /></figure></div>


<h3 class="wp-block-heading" id="step-2-install-the-heft-toolchain">Step 2: Install the Heft Toolchain</h3>



<p>Now install all the Heft-related packages your project needs:</p>



<pre class="wp-block-preformatted">npm install @microsoft/spfx-web-build-rig@1.22.1 @microsoft/spfx-heft-plugins@1.22.1 @microsoft/eslint-config-spfx@1.22.1 @microsoft/eslint-plugin-spfx@1.22.1 @microsoft/sp-module-interfaces@1.22.1 @rushstack/eslint-config@4.5.2 @rushstack/heft@1.1.2 @types/heft-jest@1.0.2 @typescript-eslint/parser@8.46.2 --save-dev --save-exact --force</pre>



<p>That&nbsp;<code>--force</code>&nbsp;flag is there because some peer dependency conflicts can pop up during migration. It&#8217;s fine to use here — you&#8217;re intentionally replacing the old toolchain.</p>



<p>If you also want to upgrade TypeScript to v5.8 (optional but recommended), run:</p>



<pre class="wp-block-preformatted">npm install typescript@~5.8.0 --save-dev</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="1c1a1a" data-has-transparency="false" style="--dominant-color: #1c1a1a;" loading="lazy" decoding="async" width="1024" height="294" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/spfx-gulp-migration-with-heft-1024x294.avif" alt="spfx gulp migration with heft" class="wp-image-133938 not-transparent" title="spfx gulp migration with heft" srcset="https://www.spguides.com/wp-content/uploads/2026/04/spfx-gulp-migration-with-heft-1024x294.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-gulp-migration-with-heft-300x86.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-gulp-migration-with-heft-768x221.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-gulp-migration-with-heft.avif 1266w" /></figure></div>


<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Heads up:</strong>&nbsp;If you run into issues installing TypeScript v5.8 during migration, you can skip this for now. The toolchain works fine with TypeScript v5.3 too.</p>
</blockquote>



<h3 class="wp-block-heading" id="step-3-update-your-npm-scripts">Step 3: Update Your NPM Scripts</h3>



<p>Open your&nbsp;<code>package.json</code>&nbsp;and replace the old Gulp-based scripts with Heft equivalents. Find the&nbsp;<code>scripts</code>&nbsp;section and update it like this:</p>



<pre class="wp-block-preformatted">{<br>  "scripts": {<br>    "build": "heft build --clean",<br>    "clean": "heft clean",<br>    "test": "heft test",<br>    "test-only": "heft run --only test --",<br>    "deploy": "heft dev-deploy",<br>    "start": "heft start --clean",<br>    "build-watch": "heft build --lite",<br>    "package-solution": "heft package-solution",<br>    "deploy-azure-storage": "heft deploy-azure-storage",<br>    "eject-webpack": "heft eject-webpack",<br>    "trust-dev-cert": "heft trust-dev-cert",<br>    "untrust-dev-cert": "heft untrust-dev-cert"<br>  }<br>}<br></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f3f0f1" data-has-transparency="false" style="--dominant-color: #f3f0f1;" loading="lazy" decoding="async" width="892" height="610" sizes="(max-width: 892px) 100vw, 892px" src="https://www.spguides.com/wp-content/uploads/2026/04/heft-configuration-in-spfx.avif" alt="heft configuration in spfx" class="wp-image-133920 not-transparent" title="heft configuration in" srcset="https://www.spguides.com/wp-content/uploads/2026/04/heft-configuration-in-spfx.avif 892w, https://www.spguides.com/wp-content/uploads/2026/04/heft-configuration-in-spfx-300x205.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/heft-configuration-in-spfx-768x525.avif 768w" /></figure></div>


<p>Here&#8217;s how the old Gulp commands map to Heft:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Gulp command</th><th>Heft equivalent</th></tr></thead><tbody><tr><td><code>gulp serve</code></td><td><code>heft start</code></td></tr><tr><td><code>gulp build</code></td><td><code>heft build</code></td></tr><tr><td><code>gulp bundle --ship</code></td><td><code>heft build --production</code></td></tr><tr><td><code>gulp package-solution --ship</code></td><td><code>heft package-solution --production</code></td></tr><tr><td><code>gulp clean</code></td><td><code>heft clean</code></td></tr></tbody></table></figure>



<p>Read <a href="https://www.spguides.com/change-solution-name-in-spfx/">How to Change Solution Name in SPFx</a></p>



<h3 class="wp-block-heading" id="step-4-add-the-spfx-heft-rig">Step 4: Add the SPFx Heft Rig</h3>



<p>Heft uses a concept called&nbsp;<strong>rigs</strong>&nbsp;— shared build configurations that multiple projects can extend. This is what replaces the old&nbsp;<code>sp-build-web</code>&nbsp;rig from the Gulp days.</p>



<p>Create a new file at&nbsp;<code>./config/rig.json</code>&nbsp;with this content:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",<br>  "rigPackageName": "@microsoft/spfx-web-build-rig"<br>}</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f6f3f3" data-has-transparency="false" style="--dominant-color: #f6f3f3;" loading="lazy" decoding="async" width="1024" height="312" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/spfx-heft-commands-1024x312.avif" alt="spfx heft commands" class="wp-image-133922 not-transparent" title="spfx heft commands" srcset="https://www.spguides.com/wp-content/uploads/2026/04/spfx-heft-commands-1024x312.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-heft-commands-300x92.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-heft-commands-768x234.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-heft-commands.avif 1154w" /></figure></div>


<p>This one file tells Heft: &#8220;use the SPFx web build rig for all the default build settings.&#8221; You don&#8217;t have to define TypeScript paths, Webpack entry points, or ESLint configs from scratch — the rig handles all of that for you.</p>



<h3 class="wp-block-heading" id="step-5-replace-the-sass-configuration">Step 5: Replace the Sass Configuration</h3>



<p>Open&nbsp;<code>./config/sass.json</code>&nbsp;and replace everything in it with:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json",<br>  "extends": "@microsoft/spfx-web-build-rig/profiles/default/config/sass.json"<br>}<br></pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f6f3f3" data-has-transparency="false" style="--dominant-color: #f6f3f3;" loading="lazy" decoding="async" width="1024" height="281" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/heft-commands-in-spfx-1024x281.avif" alt="heft commands in spfx" class="wp-image-133926 not-transparent" title="heft commands in spfx" srcset="https://www.spguides.com/wp-content/uploads/2026/04/heft-commands-in-spfx-1024x281.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/heft-commands-in-spfx-300x82.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/heft-commands-in-spfx-768x210.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/heft-commands-in-spfx.avif 1270w" /></figure></div>


<p>This hooks your project&#8217;s Sass compilation into the Heft Sass plugin defined by the rig. If you had custom Sass settings in the old file (like&nbsp;<code>useCSSModules</code>&nbsp;or&nbsp;<code>postProcessedFileExtensions</code>), you can add those back here — they&#8217;ll override the rig&#8217;s defaults.</p>



<h3 class="wp-block-heading" id="step-6-add-the-typescript-plugin-configuration">Step 6: Add the TypeScript Plugin Configuration</h3>



<p>Create a new file at&nbsp;<code>./config/typescript.json</code>:</p>



<pre class="wp-block-preformatted">{<br>  "extends": "@microsoft/spfx-web-build-rig/profiles/default/config/typescript.json",<br>  "staticAssetsToCopy": {<br>    "fileExtensions": [".resx", ".jpg", ".png", ".woff", ".eot", ".ttf", ".svg", ".gif"],<br>    "includeGlobs": ["webparts/*/loc/*.js"]<br>  }<br>}</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f5f2f3" data-has-transparency="false" style="--dominant-color: #f5f2f3;" loading="lazy" decoding="async" width="1024" height="311" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/sharepoint-framework-gulp-migration-1024x311.avif" alt="sharepoint framework gulp migration" class="wp-image-133928 not-transparent" title="sharepoint framework gulp migration" srcset="https://www.spguides.com/wp-content/uploads/2026/04/sharepoint-framework-gulp-migration-1024x311.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/sharepoint-framework-gulp-migration-300x91.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/sharepoint-framework-gulp-migration-768x234.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/sharepoint-framework-gulp-migration.avif 1184w" /></figure></div>


<p>The&nbsp;<code>staticAssetsToCopy</code>&nbsp;section tells Heft which non-TypeScript files to copy over during the build. This replaces what&nbsp;<code>gulp copy-assets</code>&nbsp;or similar custom tasks used to handle. Adjust the file extensions and globs to match whatever your project actually needs.</p>



<p>Check out <a href="https://www.spguides.com/install-nvm-in-windows/">How to Install NVM in Windows</a></p>



<h3 class="wp-block-heading" id="step-7-update-tsconfigjson">Step 7: Update tsconfig.json</h3>



<p>Replace the contents of your existing&nbsp;<code>./tsconfig.json</code>&nbsp;with this:</p>



<pre class="wp-block-preformatted">{<br>  "extends": "./node_modules/@microsoft/spfx-web-build-rig/profiles/default/tsconfig-base.json"<br>}</pre>



<p>Your old&nbsp;<code>tsconfig.json</code>&nbsp;probably had a long list of compiler options. All of those are now inherited from the rig&#8217;s base config. You only need to add project-specific overrides here if you have them.</p>



<h3 class="wp-block-heading" id="step-8-delete-gulpfilejs">Step 8: Delete gulpfile.js</h3>



<p>Just delete it.</p>



<pre class="wp-block-preformatted">rm gulpfile.js</pre>



<p>If you had custom tasks in your&nbsp;<code>gulpfile.js</code>&nbsp;— like custom Webpack config, pre-build steps, or post-build file operations —&nbsp;<strong>don&#8217;t delete it yet.</strong>&nbsp;Keep it open in a separate window for reference while you set up the equivalent Heft plugins in the next section.</p>



<h3 class="wp-block-heading" id="step-9-upgrade-your-spfx-production-dependencies">Step 9: Upgrade Your SPFx Production Dependencies</h3>



<p>Update the core SPFx packages to v1.22:</p>



<pre class="wp-block-preformatted">npm install @microsoft/sp-component-base@1.22.1 @microsoft/sp-core-library@1.22.1 @microsoft/sp-lodash-subset@1.22.1 @microsoft/sp-office-ui-fabric-core@1.22.1 @microsoft/sp-property-pane@1.22.1 @microsoft/sp-webpart-base@1.22.1 --save-exact</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="1c1a1a" data-has-transparency="false" style="--dominant-color: #1c1a1a;" loading="lazy" decoding="async" width="1024" height="435" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/upgrade-spfx-production-dependencies-1024x435.avif" alt="upgrade spfx production dependencies" class="wp-image-133935 not-transparent" title="upgrade spfx production dependencies" srcset="https://www.spguides.com/wp-content/uploads/2026/04/upgrade-spfx-production-dependencies-1024x435.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/upgrade-spfx-production-dependencies-300x127.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/upgrade-spfx-production-dependencies-768x326.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/upgrade-spfx-production-dependencies.avif 1474w" /></figure></div>


<p>After making so many changes to packages, I&#8217;d strongly recommend doing a full clean reinstall:</p>



<pre class="wp-block-preformatted"><em># Windows (PowerShell)</em><br>Remove-Item -Recurse -Force node_modules<br>Remove-Item -Force package-lock.json<br><br><em># Mac/Linux</em><br>rm -rf node_modules package-lock.json<br><br><em># Then reinstall everything cleanly</em><br>npm install<br></pre>



<p>This ensures your dependency tree is consistent and you&#8217;re not carrying over any stale Gulp-related packages.</p>



<h3 class="wp-block-heading" id="step-10-test-the-migration">Step 10: Test the Migration</h3>



<p>Run a build to verify everything works:</p>



<pre class="wp-block-preformatted">npm run build</pre>



<p>Or if you have Heft installed globally:</p>



<pre class="wp-block-preformatted">heft build --production</pre>



<p>If the build completes without errors, you&#8217;re done with the core migration. Fire up the dev server with:</p>



<pre class="wp-block-preformatted">npm run start<br><em># or</em><br>heft start --clean</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="203f69" data-has-transparency="false" style="--dominant-color: #203f69;" loading="lazy" decoding="async" width="1024" height="569" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/microsoft-spfx-heft-plugins-1024x569.avif" alt="microsoft spfx heft plugins" class="wp-image-133941 not-transparent" title="microsoft spfx heft plugins" srcset="https://www.spguides.com/wp-content/uploads/2026/04/microsoft-spfx-heft-plugins-1024x569.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/microsoft-spfx-heft-plugins-300x167.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/microsoft-spfx-heft-plugins-768x426.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/microsoft-spfx-heft-plugins.avif 1232w" /></figure></div>


<p>This will automatically open the workbench url. In case you are getting an error like in the image below. </p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="e3e8eb" data-has-transparency="false" style="--dominant-color: #e3e8eb;" loading="lazy" decoding="async" width="982" height="298" sizes="(max-width: 982px) 100vw, 982px" src="https://www.spguides.com/wp-content/uploads/2026/04/Unable-to-load-SPFx-webpart-after-deploy.avif" alt="Unable to load SPFx webpart after deploy" class="wp-image-133944 not-transparent" title="Unable to load SPFx webpart after deploy" srcset="https://www.spguides.com/wp-content/uploads/2026/04/Unable-to-load-SPFx-webpart-after-deploy.avif 982w, https://www.spguides.com/wp-content/uploads/2026/04/Unable-to-load-SPFx-webpart-after-deploy-300x91.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/Unable-to-load-SPFx-webpart-after-deploy-768x233.avif 768w" /></figure></div>


<p>Just run the following command.</p>



<pre class="wp-block-code"><code>npm run trust-dev-cert</code></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="10325d" data-has-transparency="false" style="--dominant-color: #10325d;" loading="lazy" decoding="async" width="696" height="246" sizes="(max-width: 696px) 100vw, 696px" src="https://www.spguides.com/wp-content/uploads/2026/04/spfx-failed-to-load-component.avif" alt="spfx failed to load component" class="wp-image-133945 not-transparent" title="spfx failed to load component" srcset="https://www.spguides.com/wp-content/uploads/2026/04/spfx-failed-to-load-component.avif 696w, https://www.spguides.com/wp-content/uploads/2026/04/spfx-failed-to-load-component-300x106.avif 300w" /></figure></div>


<p>Then, re-run the <code>npm run start</code> command; this time, without errors, you can get your web part as shown below.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="eeece3" data-has-transparency="false" style="--dominant-color: #eeece3;" loading="lazy" decoding="async" width="1024" height="524" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/migrating-gulp-packages-to-heft-in-sharepoint-framework-1024x524.avif" alt="migrating gulp packages to heft in sharepoint framework" class="wp-image-133949 not-transparent" title="migrating gulp packages to heft in sharepoint framework" srcset="https://www.spguides.com/wp-content/uploads/2026/04/migrating-gulp-packages-to-heft-in-sharepoint-framework-1024x524.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/migrating-gulp-packages-to-heft-in-sharepoint-framework-300x153.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/migrating-gulp-packages-to-heft-in-sharepoint-framework-768x393.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/migrating-gulp-packages-to-heft-in-sharepoint-framework.avif 1232w" /></figure></div>


<h2 class="wp-block-heading" id="handling-custom-gulpfilejs-tasks">Handling Custom gulpfile.js Tasks</h2>



<p>This is where it gets more involved. If your old&nbsp;<code>gulpfile.js</code>&nbsp;was just the default SPFx boilerplate, you&#8217;re done. But if you had custom tasks, here&#8217;s how to handle the most common ones:</p>



<h2 class="wp-block-heading" id="custom-webpack-configuration">Custom Webpack Configuration</h2>



<p>If you were using&nbsp;<code>build.configureWebpack.mergeConfig()</code>&nbsp;to inject custom Webpack settings, you have two options in Heft:</p>



<p><strong>Option 1 — Use the webpack patch file (simpler):</strong></p>



<p>Create a file at&nbsp;<code>./config/webpack.extend.js</code>:</p>



<pre class="wp-block-preformatted">module.exports = function (existingConfig) {<br>  existingConfig.resolve = existingConfig.resolve || {};<br>  existingConfig.resolve.alias = {<br>    ...existingConfig.resolve.alias,<br>    '@myAlias': require('path').resolve(__dirname, '../src/helpers')<br>  };<br>  return existingConfig;<br>};<br></pre>



<p>Then reference it in your&nbsp;<code>heft.json</code>&nbsp;(more on that file below).</p>



<p><strong>Option 2 — Eject Webpack entirely (for complex cases):</strong></p>



<pre class="wp-block-preformatted">heft eject-webpack</pre>



<p>This generates a full&nbsp;<code>webpack.config.js</code>&nbsp;in your project that you can modify directly. It&#8217;s the escape hatch for when you need complete control.</p>



<h2 class="wp-block-heading" id="custom-prepost-build-tasks">Custom Pre/Post Build Tasks</h2>



<p>If you had&nbsp;<code>build.rig.addPreBuildTask()</code>&nbsp;or&nbsp;<code>addPostBuildTask()</code>&nbsp;For things like copying extra files or running scripts, use Heft&#8217;s&nbsp;<code>run-script-plugin</code>.</p>



<p>Create&nbsp;<code>./config/heft.json</code>:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json",<br>  "extends": "@microsoft/spfx-web-build-rig/profiles/default/config/heft.json",<br>  "phasesByName": {<br>    "build": {<br>      "tasksByName": {<br>        "my-custom-script": {<br>          "taskPlugin": {<br>            "pluginPackage": "@rushstack/heft",<br>            "pluginName": "run-script-plugin",<br>            "options": {<br>              "scriptPath": "./scripts/my-custom-task.js"<br>            }<br>          }<br>        }<br>      }<br>    }<br>  }<br>}<br></pre>



<p>Create&nbsp;<code>./scripts/my-custom-task.js</code>&nbsp;and put your custom logic there. This script runs as part of the build phase.</p>



<h2 class="wp-block-heading" id="copying-files">Copying Files</h2>



<p>The old&nbsp;<code>build.copyStaticAssets</code>&nbsp;type of operations now live in&nbsp;<code>typescript.json</code>&nbsp;under&nbsp;<code>staticAssetsToCopy</code>&nbsp;(which we already configured in Step 6). For more complex copy scenarios, use the&nbsp;<code>copy-files-plugin</code>&nbsp;in&nbsp;<code>heft.json</code>.</p>



<h2 class="wp-block-heading" id="common-issues-and-fixes">Common Issues and Fixes</h2>



<p>A few things that tend to trip people up during migration:</p>



<ul class="wp-block-list">
<li><strong>ESLint errors after migration:</strong>&nbsp;Your old&nbsp;<code>.eslintrc.js</code>&nbsp;may reference&nbsp;<code>@microsoft/eslint-config-spfx</code>&nbsp;in a way that conflicts with the new package. Update the&nbsp;<code>extends</code>&nbsp;in your ESLint config to use&nbsp;<code>@rushstack/eslint-config</code>&nbsp;and re-run the build.</li>



<li><strong>&#8220;Cannot find module&#8221; errors:</strong>&nbsp;Usually means stale&nbsp;<code>node_modules</code>. Do the clean reinstall from Step 9.</li>



<li><strong>TypeScript errors you didn&#8217;t have before:</strong>&nbsp;If you upgraded to TypeScript v5.8, some stricter type checks may now flag issues that were silently ignored before. Fix them or stay on TypeScript v5.3 for now.</li>



<li><strong>PnP SPFx Controls not working:</strong>&nbsp;If you use&nbsp;<code>@pnp/spfx-controls-react</code>, make sure you&#8217;re on a version that supports SPFx v1.22. Run&nbsp;<code>npm ls @pnp/spfx-controls-react</code>&nbsp;to check your current version and compare with their release notes.</li>



<li><strong>Dev cert issues:</strong>&nbsp;If HTTPS fails on the local workbench, run&nbsp;<code>heft trust-dev-cert</code>&nbsp;to re-trust the certificate.</li>
</ul>



<h2 class="wp-block-heading" id="using-the-m365-cli-to-generate-an-upgrade-report-o">Using the M365 CLI to Generate an Upgrade Report (Optional but Helpful)</h2>



<p>If you want a full list of every change needed for your specific project before you manually edit anything, the Microsoft 365 CLI can generate an upgrade report for you:</p>



<pre class="wp-block-preformatted"><em># Install M365 CLI if you don't have it</em><br>npm i -g @pnp/cli-microsoft365<br><br><em># Generate the upgrade report</em><br>m365 spfx project upgrade --toVersion 1.22.0 --preview --output md &gt; upgrade-report.md<br></pre>



<p>Open&nbsp;<code>upgrade-report.md</code>&nbsp;— it will list every dependency that needs to change, every script to update, and any manual steps specific to your project. It&#8217;s a great way to audit before you start making changes.</p>



<h2 class="wp-block-heading" id="what-the-final-project-structure-looks-like">What the Final Project Structure Looks Like</h2>



<p>After migration, here&#8217;s what your key config files should look like:</p>



<pre class="wp-block-preformatted">your-spfx-project/<br>├── config/<br>│   ├── rig.json          ← NEW (points to spfx-web-build-rig)<br>│   ├── heft.json         ← NEW (only if you have custom tasks)<br>│   ├── sass.json         ← UPDATED (now extends rig)<br>│   ├── typescript.json   ← NEW (configures TS plugin)<br>│   └── package-solution.json (unchanged)<br>├── tsconfig.json         ← UPDATED (now extends rig's base config)<br>├── package.json          ← UPDATED (scripts use heft commands)<br>├── gulpfile.js           ← DELETED<br>└── src/                  (unchanged)<br></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="eeeded" data-has-transparency="false" style="--dominant-color: #eeeded;" loading="lazy" decoding="async" width="494" height="804" sizes="(max-width: 494px) 100vw, 494px" src="https://www.spguides.com/wp-content/uploads/2026/04/migrate-from-the-gulp-based-to-the-heft-based-toolchain.avif" alt="migrate from the gulp-based to the heft-based toolchain" class="wp-image-133930 not-transparent" title="migrate from the gulp based to the heft based toolchain" srcset="https://www.spguides.com/wp-content/uploads/2026/04/migrate-from-the-gulp-based-to-the-heft-based-toolchain.avif 494w, https://www.spguides.com/wp-content/uploads/2026/04/migrate-from-the-gulp-based-to-the-heft-based-toolchain-184x300.avif 184w" /></figure></div>


<h2 class="wp-block-heading" id="wrapping-up">Wrapping Up</h2>



<p>In this tutorial, I explained how to migrate from Gulp based toolchain to Heft based toolchain in the SharePoint Framework (SPFx). Follow the above steps, and you should be able to migrate your project.</p>



<p>The key things to remember:</p>



<ul class="wp-block-list">
<li>Uninstall the old Gulp packages and install the Heft equivalents</li>



<li>Add&nbsp;<code>rig.json</code>&nbsp;to point to&nbsp;<code>@microsoft/spfx-web-build-rig</code></li>



<li>Update your config files (sass.json, typescript.json, tsconfig.json)</li>



<li>Replace your npm scripts with&nbsp;<code>heft</code>&nbsp;commands</li>



<li>Delete&nbsp;<code>gulpfile.js</code>&nbsp;(but migrate any custom tasks first)</li>



<li>Do a clean&nbsp;<code>npm install</code>&nbsp;at the end to flush out any stale dependencies</li>
</ul>



<p>If you&#8217;ve got custom Gulp tasks, the translation to Heft plugins takes a bit of extra thought — but the&nbsp;<code>run-script-plugin</code>&nbsp;and&nbsp;<code>copy-files-plugin</code>&nbsp;cover most real-world scenarios.</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download SPFx Solutions</a></div>
</div>



<p>Also, you may like:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/create-modal-popup-in-spfx/">Create a Modal Popup in SPFx</a></li>



<li><a href="https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/">Bind SharePoint List Items to SPFx Fluent UI React Dropdown</a></li>



<li><a href="https://www.spguides.com/customize-sharepoint-list-command-bar-download-button-using-spfx-extension/">Customize SharePoint List Command Bar Download Button Using SPFx Extension</a></li>



<li><a href="https://www.spguides.com/spfx-upload-file-to-sharepoint-document-library-with-metadata/">Upload File to SharePoint Document Library With Metadata in SPFx</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Set Up Your SharePoint Framework (SPFx) Development Environment using Heft Toolchain</title>
		<link>https://www.spguides.com/set-up-spfx-project-with-heft/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Mon, 27 Apr 2026 13:37:31 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Set Up SPFx Project with Heft]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=133980</guid>

					<description><![CDATA[If you&#8217;ve been wanting to build custom web parts or extensions for SharePoint, the very first thing you need to do is set up your&#160;SharePoint Framework (SPFx)&#160;development environment. With SPFx 1.22, things have changed. Microsoft has introduced a new build system called Heft, which replaces Gulp and handles the build process more structurally. I&#8217;m going ... <a title="Set Up Your SharePoint Framework (SPFx) Development Environment using Heft Toolchain" class="read-more" href="https://www.spguides.com/set-up-spfx-project-with-heft/" aria-label="Read more about Set Up Your SharePoint Framework (SPFx) Development Environment using Heft Toolchain">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>If you&#8217;ve been wanting to <a href="https://www.spguides.com/spfx-training-course/" target="_blank" rel="noreferrer noopener">build custom web parts</a> or extensions for SharePoint, the very first thing you need to do is <strong>set up your&nbsp;SharePoint Framework (SPFx)&nbsp;development environment</strong>.</p>



<p>With SPFx 1.22, things have changed. Microsoft has introduced a new build system called Heft, which replaces Gulp and handles the build process more structurally.</p>



<p>I&#8217;m going to walk you through every step — explain what each tool actually does, why you&#8217;re installing it, and flag the important gotchas along the way. By the end, your machine will be fully ready to build real SharePoint solutions.</p>



<p>This tutorial walks you through <strong>setting up your SPFx development environment using the Heft toolchain</strong> step by step. After this, i </p>



<h2 class="wp-block-heading" id="this-guide-is-for-spfx-v122-and-above-heft-based-t">This Guide Is for SPFx v1.22 and Above (Heft-Based Toolchain)</h2>



<p>Here&#8217;s something you absolutely need to know before anything else:&nbsp;<strong>SPFx v1.22 introduced a brand-new toolchain called Heft</strong>, replacing the older Gulp-based build system that was used from SPFx v1.0 all the way through v1.21.1.</p>



<p>This matters because:</p>



<ul class="wp-block-list">
<li>If you&#8217;re building on&nbsp;<strong>SPFx v1.22 or newer</strong>&nbsp;→ you&#8217;re on the&nbsp;<strong>Heft-based toolchain</strong>. This guide is for you.</li>



<li>If you&#8217;re building on&nbsp;<strong>SPFx v1.0 through v1.21.1</strong>, including any on-premises SharePoint Server deployment → you&#8217;re on the&nbsp;<strong>Gulp-based (legacy) toolchain</strong>. Then check this: <a href="https://www.spguides.com/set-up-development-environment-for-sharepoint-framework/" target="_blank" rel="noreferrer noopener">Set up your SharePoint Framework Gulp-based development environment</a>.</li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Not sure which version you need?</strong>&nbsp;If you&#8217;re building for SharePoint Online with no constraints, just follow this guide — it uses the latest SPFx. If you need to support a specific version of SharePoint Server on-premises, check the version number requirements first before installing anything.</p>
</blockquote>



<p>The toolchain change is significant. Build configurations, commands, and customizations all changed between these two toolchains. The command you&#8217;ll use to run your project locally, for example, is&nbsp;<code>heft</code>&nbsp;in the new toolchain — not&nbsp;<code>gulp serve</code>. I&#8217;ll cover all of that clearly as we go.</p>



<p>Let&#8217;s first understand what Heft is in SPFx.</p>



<h2 class="wp-block-heading">What is Heft in SharePoint Framework (SPFx) and Why Do We Need This?</h2>



<p>In <strong>SharePoint Framework (SPFx)</strong>, <strong>Heft</strong> is the modern tool that handles everything required to build and package your solution. Earlier, SPFx relied on <strong>Gulp</strong>, which required developers to manage multiple tasks and configurations manually.</p>



<p>Heft simplifies this by providing a standardized and optimized way to run all build-related activities with minimal setup. For a beginner, you can think of Heft as the system that quietly takes your code, processes it, and prepares it so SharePoint can use it.</p>



<p>When you work on an SPFx project, you typically write code in TypeScript and use modern libraries like React. However, SharePoint cannot directly use that raw code. This is where Heft comes in. It compiles your code, bundles all the files together, checks for errors, and prepares the final package that can be deployed. All of this happens behind the scenes when you run simple commands in your terminal.</p>



<p>Heft provides a set of commands that you’ll use regularly during development. The most common one is:</p>



<ul class="wp-block-list">
<li><code>heft build</code> → Compiles your project and prepares the build output.</li>
</ul>



<p>If you want to remove old build files and start fresh, you can use:</p>



<ul class="wp-block-list">
<li><code>heft clean</code> → Deletes previously generated files and clears the build cache.</li>
</ul>



<p>For local development, especially when testing your web part in the browser, you’ll use:</p>



<ul class="wp-block-list">
<li><code>heft start</code> → Starts the local development environment and serves your solution.</li>
</ul>



<p>Once your solution is ready, you need to package it so it can be deployed to SharePoint. For that, Heft provides:</p>



<ul class="wp-block-list">
<li><code>heft package-solution</code> → Creates the <code>.sppkg</code> file used for deployment.</li>
</ul>



<p>If you’re preparing your solution for production, you should use:</p>



<ul class="wp-block-list">
<li><code>heft package-solution --production</code> → Generates an optimized, production-ready package.</li>
</ul>



<p>During development, especially when testing locally over HTTPS, you might need:</p>



<ul class="wp-block-list">
<li><code>heft trust-dev-cert</code> → Installs and trusts a development certificate for secure local testing.</li>
</ul>



<p>In simple terms, Heft is what keeps your SPFx development smooth and consistent. Instead of worrying about how your code is compiled or packaged, you just run these commands, and Heft takes care of the rest. As you grow more comfortable with SPFx, you might explore customizing Heft, but for most developers—especially beginners—it works perfectly out of the box.</p>



<p>Check out <a href="https://www.spguides.com/change-solution-name-in-spfx/">How to Change Solution Name in SPFx</a></p>



<h2 class="wp-block-heading" id="set-up-your-microsoft-365-tenant-first">Set Up Your Microsoft 365 Tenant First</h2>



<p>SPFx solutions run in SharePoint Online, so you need somewhere to test them. Before following the installation steps below, make sure you have a&nbsp;<strong>Microsoft 365 tenant</strong>&nbsp;ready. If you don&#8217;t have one, go to&nbsp;<code>developer.microsoft.com</code>&nbsp;and sign up for the free&nbsp;<strong>Microsoft 365 Developer Program</strong>&nbsp;— it gives you a sandbox tenant you can use freely for development.</p>



<p>You Can Use Any Operating System</p>



<p>One of the great things about SPFx is that you are not locked into Windows. You can use&nbsp;<strong>macOS, Windows, or Linux</strong>&nbsp;— all are fully supported.</p>



<h2 class="wp-block-heading" id="step-1-install-nodejs-v22-lts">Step 1: Install Node.js v22 LTS</h2>



<p>The first thing to install is&nbsp;<strong>Node.js</strong>. Think of Node.js as the engine that powers all the SPFx developer tools. Without it, nothing else will work.</p>



<p><strong>The version you need is Node.js v22 LTS (also known by its codename &#8220;Jod&#8221;).</strong></p>



<p>This is the recommended version for SPFx v1.22.*. If you&#8217;re working on a project using a different SPFx version, verify that your Node.js version is supported for that particular SPFx release before installing.</p>



<h3 class="wp-block-heading" id="lts-vs-current--what-you-need-to-know">LTS vs. Current — What You Need to Know</h3>



<p>Node.js always maintains two release tracks simultaneously:</p>



<ul class="wp-block-list">
<li><strong>LTS (Long Term Support):</strong>&nbsp;Stable, thoroughly tested, and the version that SPFx officially supports.</li>



<li><strong>Current:</strong>&nbsp;Has newer features but is&nbsp;<strong>not supported by SPFx</strong>. Avoid it for SPFx development.</li>
</ul>



<p>Always install an LTS version. SPFx is only supported on LTS versions of Node.js, so do not install the &#8220;Current&#8221; release even if it looks newer on the Node.js website.</p>



<h3 class="wp-block-heading" id="how-to-download-nodejs">How to Download Node.js</h3>



<p>Here&#8217;s how to find the right installer:</p>



<ul class="wp-block-list">
<li>Go to the&nbsp;<strong>Node.js website</strong>&nbsp;(<code>nodejs.org</code>) and navigate to the Downloads page to find a specific version.</li>



<li><strong>Windows users:</strong>&nbsp;Look for the&nbsp;<code>.msi</code>&nbsp;installer files. There are usually two — one for x86 and one for x64 systems. The filenames look like&nbsp;<code>node-v{version-number}-x86.msi</code>&nbsp;or&nbsp;<code>node-v{version-number}-x64.msi</code>. Most modern Windows machines are 64-bit, so you&#8217;ll want the x64 version.</li>



<li><strong>macOS users:</strong>&nbsp;Look for the&nbsp;<code>.pkg</code>&nbsp;installer, usually named&nbsp;<code>node-v{version-number}.pkg</code>.</li>
</ul>



<h3 class="wp-block-heading" id="verify-your-installation">Verify Your Installation</h3>



<p>After installing Node.js, open your terminal (Command Prompt or PowerShell on Windows, Terminal on macOS/Linux) and run:</p>



<pre class="wp-block-preformatted">node --version</pre>



<p>You should see a version number like&nbsp;<code>v22.x.x</code>. If that appears, Node.js is successfully installed, and you&#8217;re ready to move on.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Already have Node.js installed?</strong>&nbsp;Run&nbsp;<code>node --version</code>&nbsp;first. If you have v22 LTS already, you&#8217;re good to go. If you have a different version and need to work with multiple SPFx versions across different projects, consider using&nbsp;<strong>Node Version Manager (NVM)</strong>&nbsp;— more on that later.</p>
</blockquote>



<p>Read <a href="https://www.spguides.com/create-modal-popup-in-spfx/">How to Create a Modal Popup in SPFx</a></p>



<h2 class="wp-block-heading" id="step-2-install-a-code-editor">Step 2: Install a Code Editor</h2>



<p>Next, you need a code editor to write your TypeScript and configuration files. You can use any editor you&#8217;re comfortable with — SPFx has no requirement here.</p>



<p>That said, I <span style="box-sizing: border-box; margin: 0px; padding: 0px;">recommended using</span>&nbsp;Visual Studio Code (VS Code)&nbsp;for all its examples, and I&#8217;d strongly recommend it for beginners and experienced developers alike. It&#8217;s free, cross-platform, has a built-in terminal (which is super handy for running SPFx commands without switching windows), and has excellent extension support.</p>



<p>If you prefer&nbsp;<strong>WebStorm</strong>&nbsp;from JetBrains, that&#8217;s also a perfectly valid choice.</p>



<p>Download VS Code from&nbsp;<code>code.visualstudio.com</code>&nbsp;and install it for your platform.</p>



<h2 class="wp-block-heading" id="step-3-install-the-development-toolchain-prerequis">Step 3: Install the Development Toolchain Prerequisites</h2>



<p>This is the most important step of the entire setup. SPFx&#8217;s build and development toolchain relies on several open-source tools. While most project-level dependencies install automatically when you create a new project, there are&nbsp;<strong>three tools you need to install globally on your machine</strong>:</p>



<ol class="wp-block-list">
<li><strong>Heft</strong>&nbsp;— the build tool (new in SPFx v1.22)</li>



<li><strong>Yeoman (yo)</strong>&nbsp;— the project scaffolding wizard</li>



<li><strong>Yeoman SharePoint Generator</strong>&nbsp;— the SPFx-specific plugin for Yeoman</li>
</ol>



<p>Microsoft gives you a helpful shortcut — you can install all three with a single command:</p>



<pre class="wp-block-preformatted">npm install @rushstack/heft yo @microsoft/generator-sharepoint --global</pre>



<p>Or, if you prefer to install them one at a time and understand what each does, here&#8217;s the breakdown:</p>



<h3 class="wp-block-heading" id="install-heft">Install Heft</h3>



<p><strong>Heft</strong>&nbsp;is the new build toolchain introduced with SPFx v1.22. It replaces Gulp as the primary build engine and orchestrates other popular tools like TypeScript, ESLint, Jest, Webpack, and API Extractor under the hood. If you&#8217;re familiar with task runners like Gulp or Grunt, Heft plays a very similar role — but it&#8217;s designed for large-scale, consistent use across many projects.</p>



<p>To install Heft globally:</p>



<pre class="wp-block-preformatted">npm install @rushstack/heft --global</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Why install it globally?</strong>&nbsp;Technically, Heft doesn&#8217;t need to be installed globally — it&#8217;s included inside each project you create. But installing it globally makes it much easier to run Heft commands directly from your terminal without navigating into each project&#8217;s local binaries. The Microsoft documentation recommends global installation for this reason.</p>
</blockquote>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Important — What if you&#8217;re on SPFx v1.21.x or older?</strong>&nbsp;You should&nbsp;<strong>not</strong>&nbsp;install Heft. Older projects use the Gulp-based toolchain, and their setup guide tells you to install&nbsp;<code>gulp-cli</code>&nbsp;globally instead. The tools are different, the commands are different, and mixing them up will cause confusion.</p>
</blockquote>



<h3 class="wp-block-heading" id="install-yeoman">Install Yeoman</h3>



<p><strong>Yeoman (yo)</strong>&nbsp;is a project scaffolding tool. It asks you a series of questions in an interactive wizard and then automatically generates a complete, correctly structured SPFx project for you — with all the right folders, TypeScript configuration, build settings, and boilerplate code already in place.</p>



<p>To install Yeoman globally:</p>



<pre class="wp-block-preformatted">npm install yo --global</pre>



<h3 class="wp-block-heading" id="install-the-yeoman-sharepoint-generator">Install the Yeoman SharePoint Generator</h3>



<p>The&nbsp;<strong>Yeoman SharePoint Generator</strong>&nbsp;is the SPFx-specific plugin that powers the wizard when you create a new project. Without it, Yeoman wouldn&#8217;t know how to scaffold an SPFx solution. It&#8217;s what makes Yeoman ask you things like &#8220;What type of component do you want to create?&#8221; and &#8220;Which JavaScript framework do you want to use?&#8221;</p>



<p>To install it globally:</p>



<pre class="wp-block-preformatted">npm install @microsoft/generator-sharepoint --global</pre>



<p>Check out <a href="https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/">Bind SharePoint List Items to SPFx Fluent UI React Dropdown</a></p>



<h2 class="wp-block-heading" id="step-4-install-a-modern-web-browser">Step 4: Install a Modern Web Browser</h2>



<p>You&#8217;ll need a modern web browser for testing and debugging your solutions in the SharePoint workbench. The Microsoft documentation recommends any of the following:</p>



<ul class="wp-block-list">
<li><strong>Microsoft Edge</strong></li>



<li><strong>Google Chrome</strong></li>



<li><strong>Firefox</strong></li>
</ul>



<p>All three are excellent choices with strong developer tools. Avoid Internet Explorer — it&#8217;s not supported for SPFx development.</p>



<h2 class="wp-block-heading" id="step-5-trust-the-self-signed-developer-certificate">Step 5: Trust the Self-Signed Developer Certificate</h2>



<p>When you test an SPFx solution locally, it runs on a local development server that uses&nbsp;<strong>HTTPS by default</strong>. This local server uses a&nbsp;<strong>self-signed SSL certificate</strong>&nbsp;— a certificate that isn&#8217;t issued by a trusted certificate authority. By default, your operating system and browser will not trust this certificate, which means you&#8217;ll get a security warning or blocked page when you try to load the workbench.</p>



<p>To fix this, you need to register the certificate as trusted on your machine. SPFx includes a built-in Heft command to do this.</p>



<h3 class="wp-block-heading" id="when-to-run-this-command">When to Run This Command</h3>



<p>You can run this command either now or after you create your first project. I recommend running this command after you create your first project. The command needs to be run from inside an SPFx project folder (after running&nbsp;<code>npm install</code>&nbsp;to install the project dependencies), so if you haven&#8217;t created a project yet, you can come back to this step.</p>



<p>Once you have a project created and&nbsp;<code>npm install</code>&nbsp;has been run inside the project root, execute:</p>



<pre class="wp-block-preformatted">heft trust-dev-cert</pre>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Note for SPFx v1.21.x and older (Gulp-based projects):</strong>&nbsp;The equivalent command in the old toolchain was&nbsp;<code>gulp trust-dev-cert</code>. If you&#8217;re working on a legacy project, use the Gulp command instead.</p>
</blockquote>



<p>You only need to do this&nbsp;<strong>once per machine</strong>. After the certificate is trusted, all future SPFx projects on the same machine will work without needing to repeat this step.</p>



<p>Check out <a href="https://www.spguides.com/customize-sharepoint-list-command-bar-download-button-using-spfx-extension/">Customize SharePoint List Command Bar Download Button Using SPFx Extension</a></p>



<h2 class="wp-block-heading" id="step-6-set-the-spfxservetenantdomain-environment-v">Step 6: Set the SPFX_SERVE_TENANT_DOMAIN Environment Variable (Optional but Recommended)</h2>



<p>Starting with&nbsp;<strong>SPFx v1.17</strong>, the hosted workbench URL used during development was changed to use a dynamic placeholder. If you open a project&#8217;s&nbsp;<code>./config/serve.json</code>&nbsp;file, you&#8217;ll see this:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",<br>  "port": 4321,<br>  "https": true,<br>  "initialPage": "https://{tenantDomain}/_layouts/workbench.aspx"<br>}</pre>



<p>Notice the&nbsp;<code>{tenantDomain}</code>&nbsp;placeholder. When you run the serve command to test your solution, SPFx automatically replaces this placeholder with the value of an environment variable called&nbsp;<code>SPFX_SERVE_TENANT_DOMAIN</code>&nbsp;on your system.</p>



<p>This is useful because it means you configure your SharePoint tenant domain&nbsp;<strong>once</strong>&nbsp;at the operating system level, and every SPFx project you create picks it up automatically. You won&#8217;t need to manually edit the&nbsp;<code>serve.json</code>&nbsp;file in every project.</p>



<p>The variable supports not just the tenant domain but also full site URLs in other serve configurations — for example, if you&#8217;re building a Field Customizer and have a&nbsp;<code>pageUrl</code>&nbsp;in your serve config with a&nbsp;<code>{tenantDomain}</code>&nbsp;placeholder, it will be replaced the same way.</p>



<h3 class="wp-block-heading" id="how-to-set-it">How to Set It</h3>



<p><strong>On Windows:</strong></p>



<ol class="wp-block-list">
<li>Press&nbsp;<code>Win + S</code>&nbsp;and search for &#8220;Environment Variables&#8221;</li>



<li>Click &#8220;Edit the system environment variables&#8221;</li>



<li>Under &#8220;User variables&#8221;, click &#8220;New&#8221;</li>



<li>Set the&nbsp;<strong>Variable name</strong>&nbsp;to&nbsp;<code>SPFX_SERVE_TENANT_DOMAIN</code></li>



<li>Set the&nbsp;<strong>Variable value</strong>&nbsp;to your SharePoint tenant domain, e.g.,&nbsp;<code>contoso.sharepoint.com</code></li>



<li>Click OK and restart your terminal</li>
</ol>



<p><strong>On macOS/Linux:</strong><br>Add the following line to your shell profile file (<code>~/.zshrc</code>&nbsp;for Zsh,&nbsp;<code>~/.bashrc</code>&nbsp;for Bash):</p>



<pre class="wp-block-preformatted">export SPFX_SERVE_TENANT_DOMAIN=contoso.sharepoint.com</pre>



<p>Then restart your terminal or run&nbsp;<code>source ~/.zshrc</code>&nbsp;to apply the change immediately.</p>



<p>Read <a href="https://www.spguides.com/spfx-upload-file-to-sharepoint-document-library-with-metadata/">Upload File to SharePoint Document Library With Metadata in SPFx</a></p>



<h2 class="wp-block-heading" id="quick-verification-are-all-your-tools-installed">Quick Verification: Are All Your Tools Installed?</h2>



<p>Once you&#8217;ve completed the steps above, you can verify everything is in place by running this command in your terminal:</p>



<pre class="wp-block-preformatted">npm list --global --depth=0</pre>



<p>This lists all globally installed npm packages. You should see:</p>



<ul class="wp-block-list">
<li><code>@rushstack/heft</code></li>



<li><code>yo</code></li>



<li><code>@microsoft/generator-sharepoint</code></li>
</ul>



<p>If any of these are missing, re-run the install command for that specific package.</p>



<h2 class="wp-block-heading">Develop Your First Client-Side Web Part using SPFx</h2>



<p>With all the tools installed and your developer certificate trusted, your machine is completely set up for SharePoint Framework development. The next step is scaffolding your very first SPFx project. Now we will create our first SPFx client-side web part.</p>



<p>You can also create a folder:</p>



<pre class="wp-block-code"><code>md SPFxHeftProject
cd SPFxHeftProject</code></pre>



<p>Open your terminal, navigate to the folder where you&#8217;d like to create the project, and run:</p>



<pre class="wp-block-code"><code>yo @microsoft/sharepoint</code></pre>



<p>Yeoman will launch an interactive wizard. It will ask you for your solution name, the type of component you want to create (web part, extension, etc.), and your preferred JavaScript framework.</p>



<p id="block-1b499e8e-4fdf-47f2-b5ec-86ae465ee8f2">When prompted:</p>



<ul id="block-8d3f9afe-b686-4387-b1cd-5a9271cf39ae" class="wp-block-list">
<li>What is your solution name? <strong>sp-fx-heft-project</strong></li>



<li>Which type of client-side component to create? <strong>WebPart</strong></li>



<li>Add new Web part to solution sp-fx-heft-project.</li>



<li>What is your Web part name? <strong>HeftProject</strong></li>



<li>Which template would you like to use? <strong>React</strong></li>
</ul>



<p>Here is a screenshot for your reference.</p>


<div class="wp-block-image">
<figure class="aligncenter" id="block-a186e85a-90a8-4ed6-8c1a-b897aabdd70b"><img decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/04/setup-spfx-environment-with-heft-in-sharepoint-1024x712.avif" alt="setup spfx environment with heft in sharepoint" title="setup spfx environment with heft in sharepoint"></figure></div>


<p><strong>Understand What Just Changed</strong></p>



<p id="block-7fb2b5b8-1ad1-4d37-be71-85be9588410e">When the generator runs, it defaults to the Heft-based toolchain. You&#8217;ll notice immediately that the generated project looks slightly different from older projects:</p>



<ul id="block-9c417f2a-b3b9-4c81-9215-db8eac9be4ed" class="wp-block-list">
<li>There&#8217;s no&nbsp;<code>gulpfile.js</code></li>



<li>There&#8217;s a&nbsp;<code>./config/rig.json</code>&nbsp;file</li>



<li>There&#8217;s a&nbsp;<code>./config/sass.json</code>&nbsp;that extends the rig configuration</li>



<li>There&#8217;s a&nbsp;<code>./config/typescript.json</code>&nbsp;for TypeScript plugin settings</li>



<li>The&nbsp;<code>package.json</code>&nbsp;scripts call&nbsp;<code>heft</code>&nbsp;instead of&nbsp;<code>gulp</code></li>
</ul>


<div class="wp-block-image">
<figure class="aligncenter" id="block-9905c07d-8b7c-4d8f-a3fa-626b97ce31a1"><img decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/04/setting-up-a-new-spfx-project-with-heft.avif" alt="setting up a new spfx project with heft" title="setting up a new spfx project with heft"></figure></div>


<p id="block-b34caf17-6b9f-4829-adf7-d506de2d0002">This confirms you’re using the new Heft-based build system. This is the key difference compared to older SPFx projects. The Gulf file is also not there.</p>



<p id="block-05d37f3b-8752-42ca-9869-041c4e9a7646">Your new&nbsp;<code>package.json</code>&nbsp;scripts section will look like this:</p>



<pre id="block-51b3f370-676a-41df-a1f1-d0111a4aa6d4" class="wp-block-code"><code>  "scripts": {<br>    "build": "heft test --clean --production &amp;&amp; heft package-solution --production",<br>    "start": "heft start --clean",<br>    "clean": "heft clean",<br>    "eject-webpack": "heft eject-webpack"<br>  }</code></pre>



<p>You can refer to the screenshot below:</p>


<div class="wp-block-image">
<figure class="aligncenter" id="block-70817434-b848-48a3-ace4-1ca8bd3f839a"><img decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/04/heft-set-up-a-new-spfx-project-1024x555.avif" alt="heft set up a new spfx project" title="heft set up a new spfx project"></figure></div>


<p id="block-dfe39f90-01a6-43e2-8644-31a4f8b45383">Notice a couple of things here. First, the&nbsp;<code>bundle</code>&nbsp;task is gone — in Heft,&nbsp;<code>build</code>&nbsp;handles both building and bundling in one step. Second, there&#8217;s a brand new&nbsp;<code>deploy</code>&nbsp;command (<code>heft dev-deploy</code>) that didn&#8217;t exist in the Gulp world.</p>



<p>After&nbsp;<code>npm install</code>&nbsp;finishes, if you haven&#8217;t already, run:</p>



<pre class="wp-block-preformatted">heft trust-dev-cert</pre>



<h3 class="wp-block-heading">Update the Workbench URL</h3>



<p>Before testing your web part, make sure to update the <code>initialPage</code> in the <code>serve.json</code> file. Replace <code>{tenantDomain}</code> with your actual SharePoint tenant URL so the local workbench opens correctly in your environment. You can check the screenshot below.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f2f2f3" data-has-transparency="false" style="--dominant-color: #f2f2f3;" loading="lazy" decoding="async" width="1024" height="501" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-webpart-locally-1024x501.avif" alt="run spfx webpart locally" class="wp-image-134005 not-transparent" title="run spfx webpart locally" srcset="https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-webpart-locally-1024x501.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-webpart-locally-300x147.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-webpart-locally-768x376.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-webpart-locally.avif 1414w" /></figure></div>


<h3 class="wp-block-heading">Run the Project</h3>



<p>Instead of the old Gulp command:</p>



<pre class="wp-block-preformatted">gulp serve</pre>



<p>You now use:</p>



<pre class="wp-block-preformatted">npm run start<br># or<br>heft start --clean</pre>



<p>After running the command, the local workbench will open in your browser. At this point, you may see a prompt asking <strong>“Allow debug scripts?”</strong>. This is expected when running SPFx solutions locally, as the page is loading scripts from your development machine.</p>



<p>Since you are testing your own code, you can safely click <strong>“Load debug scripts”</strong> to proceed and continue testing your web part.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="d4d5d8" data-has-transparency="false" style="--dominant-color: #d4d5d8;" loading="lazy" decoding="async" width="976" height="430" sizes="(max-width: 976px) 100vw, 976px" src="https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-heft-configured-webpart-locally.avif" alt="run spfx heft configured webpart locally" class="wp-image-134008 not-transparent" title="run spfx heft configured webpart locally" srcset="https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-heft-configured-webpart-locally.avif 976w, https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-heft-configured-webpart-locally-300x132.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/run-spfx-heft-configured-webpart-locally-768x338.avif 768w" /></figure></div>


<p>Then, the page below will open. Click the + Add icon and find your web part. You can either search for your web part name, and it will display.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f3f0e9" data-has-transparency="false" style="--dominant-color: #f3f0e9;" loading="lazy" decoding="async" width="1024" height="530" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/deploy-spfx-webpart-to-sharepoint-online-1024x530.avif" alt="deploy spfx webpart to sharepoint online" class="wp-image-134009 not-transparent" title="deploy spfx webpart to sharepoint online" srcset="https://www.spguides.com/wp-content/uploads/2026/04/deploy-spfx-webpart-to-sharepoint-online-1024x530.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/deploy-spfx-webpart-to-sharepoint-online-300x155.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/deploy-spfx-webpart-to-sharepoint-online-768x398.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/deploy-spfx-webpart-to-sharepoint-online.avif 1302w" /></figure></div>


<p>Once you’re confident that your SPFx web part is working as expected, the next step is to prepare it for deployment. Run the command below to create the package, and once it completes, you’ll find the <code>.sppkg</code> file inside the <code>sharepoint</code> folder, as shown in the image below.</p>



<pre class="wp-block-code"><code>heft package-solution --production</code></pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="798ba4" data-has-transparency="false" style="--dominant-color: #798ba4;" loading="lazy" decoding="async" width="1024" height="524" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/add-custom-web-part-to-sharepoint-online-1024x524.avif" alt="add custom web part to sharepoint online" class="wp-image-134013 not-transparent" title="add custom web part to sharepoint online" srcset="https://www.spguides.com/wp-content/uploads/2026/04/add-custom-web-part-to-sharepoint-online-1024x524.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/add-custom-web-part-to-sharepoint-online-300x153.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/add-custom-web-part-to-sharepoint-online-768x393.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/add-custom-web-part-to-sharepoint-online-1536x785.avif 1536w, https://www.spguides.com/wp-content/uploads/2026/04/add-custom-web-part-to-sharepoint-online.avif 1776w" /></figure></div>


<p>Now upload the generated <code>.sppkg</code> file to your <a href="https://www.spguides.com/sharepoint-online-app-catalog/" target="_blank" rel="noreferrer noopener">tenant app catalog</a> or site collection app catalog. The deployment process remains the same as before, so you can follow the usual steps you’ve already used for deploying SPFx solutions.</p>



<h2 class="wp-block-heading" id="the-building-blocks-actions-phases-tasks-and-rigs">The Building Blocks: Actions, Phases, Tasks, and Rigs</h2>



<p>Now you need to understand how Heft organizes work. It has a specific vocabulary, and once you know these four terms, everything clicks.</p>



<ul class="wp-block-list">
<li><strong>Actions</strong>&nbsp;are the top-level commands you run from the CLI. For example,&nbsp;heft build,&nbsp;heft test,&nbsp;heft start. These are similar to the gulp tasks you used to have.</li>



<li><strong>Phases</strong>&nbsp;are logical groupings of work within an action. The&nbsp;<code>build</code>&nbsp;action might contain a&nbsp;<code>build</code>&nbsp;phase and a&nbsp;<code>test</code>&nbsp;phase.</li>



<li><strong>Tasks</strong>&nbsp;live inside phases. A task is a single unit of work — like compiling TypeScript, compiling Sass, or running ESLint.</li>



<li><strong>Rigs</strong>&nbsp;are the really clever part. A rig is a shared, reusable configuration package. Instead of every SPFx project carrying its own massive&nbsp;<code>heft.json</code>&nbsp;file with all the build logic, your project points to a rig package (<code>@microsoft/spfx-web-build-rig</code>) that contains all the default build configuration. Your project only defines what&#8217;s different from the default.</li>
</ul>



<p>In practice, a new SPFx v1.22 project has a very lean&nbsp;<code>./config/rig.json</code>&nbsp;file that looks like this:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",<br>  "rigPackageName": "@microsoft/spfx-web-build-rig"<br>}</pre>



<p>That single file tells Heft:&nbsp;<em>&#8220;use all the build phases, tasks, and configurations defined in the SPFx rig package.&#8221;</em>&nbsp;Clean and simple.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="edf0f1" data-has-transparency="false" style="--dominant-color: #edf0f1;" loading="lazy" decoding="async" width="1024" height="280" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/setup-heft-in-sharepoint-framework-development-environment-1024x280.avif" alt="setup heft in sharepoint framework development environment" class="wp-image-134003 not-transparent" title="setup heft in sharepoint framework development environment" srcset="https://www.spguides.com/wp-content/uploads/2026/04/setup-heft-in-sharepoint-framework-development-environment-1024x280.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/setup-heft-in-sharepoint-framework-development-environment-300x82.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/setup-heft-in-sharepoint-framework-development-environment-768x210.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/setup-heft-in-sharepoint-framework-development-environment.avif 1366w" /></figure></div>


<p>Read <a href="https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/">Build a Custom Slides Manager in SPFx Web Part Property Pane</a></p>



<h2 class="wp-block-heading" id="heft-vs-gulp--a-clear-summary-for-beginners">Heft vs. Gulp — A Clear Summary</h2>



<p>Since this distinction causes a lot of confusion, let me summarize it clearly in one place:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th></th><th><strong>Heft-Based Toolchain</strong></th><th><strong>Gulp-Based Toolchain (Legacy)</strong></th></tr></thead><tbody><tr><td><strong>SPFx versions</strong></td><td>v1.22.0 and above</td><td>v1.0 through v1.21.1</td></tr><tr><td><strong>Targets</strong></td><td>SharePoint Online (latest)</td><td>SharePoint Online + on-premises</td></tr><tr><td><strong>Global install</strong></td><td><code>@rushstack/heft</code></td><td><code>gulp-cli</code></td></tr><tr><td><strong>Local dev command</strong></td><td><code>heft serve</code>&nbsp;or&nbsp;<code>npm run serve</code></td><td><code>gulp serve</code></td></tr><tr><td><strong>Trust certificate</strong></td><td><code>heft trust-dev-cert</code></td><td><code>gulp trust-dev-cert</code></td></tr></tbody></table></figure>



<p>If you&#8217;ve been using the old toolchain, here&#8217;s the side-by-side comparison you need:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>What you used to run (Gulp)</th><th>What you run now (Heft)</th></tr></thead><tbody><tr><td><code>gulp build</code></td><td><code>heft build</code></td></tr><tr><td><code>gulp bundle</code></td><td><em>(merged into&nbsp;<code>heft build</code>)</em></td></tr><tr><td><code>gulp clean</code></td><td><code>heft clean</code></td></tr><tr><td><code>gulp test</code></td><td><code>heft test</code></td></tr><tr><td><code>gulp serve</code></td><td><code>heft start</code></td></tr><tr><td><code>gulp package-solution</code></td><td><code>heft package-solution</code></td></tr><tr><td><code>gulp package-solution --ship</code></td><td><code>heft package-solution --production</code></td></tr><tr><td><code>gulp deploy-azure-storage</code></td><td><code>heft deploy-azure-storage</code></td></tr><tr><td><code>gulp trust-dev-cert</code></td><td><code>heft trust-dev-cert</code></td></tr><tr><td><em>(didn&#8217;t exist)</em></td><td><code>heft dev-deploy</code></td></tr></tbody></table></figure>



<p>If you&#8217;re starting fresh with SharePoint Online, always use the Heft-based toolchain. If you open someone else&#8217;s older project, check the SPFx version in&nbsp;<code>package.json</code>&nbsp;to know which toolchain applies.</p>



<h2 class="wp-block-heading" id="managing-multiple-spfx-versions-on-one-machine">Manage Multiple SPFx Versions on One Machine</h2>



<p>As you work on more projects over time, you may encounter situations where different projects require different SPFx versions — and therefore different Node.js versions. This is common when maintaining legacy solutions alongside new ones.</p>



<p>The Microsoft documentation suggests these approaches:</p>



<ul class="wp-block-list">
<li><strong>Node Version Manager (NVM):</strong>&nbsp;Install multiple Node.js versions side-by-side and switch between them with a single command. For macOS/Linux, use&nbsp;<code>nvm</code>. For Windows, use&nbsp;<code>nvm-windows</code>. This is the most practical approach for most developers.</li>



<li><strong>Virtual Machines:</strong>&nbsp;Run each environment in a completely isolated VM.</li>



<li><strong>Docker:</strong>&nbsp;Use Docker containers to fully isolate each environment.</li>
</ul>



<p>For most developers, NVM is the simplest solution. Once it&#8217;s installed, switching Node.js versions is as easy as typing&nbsp;<code>nvm use 22</code>&nbsp;or&nbsp;<code>nvm use 18</code>.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In this tutorial, I explained how to set up your SPFx development environment using the Heft toolchain step by step. The key things to remember are: use&nbsp;<strong>Node.js v22 LTS</strong>, install the&nbsp;<strong>Heft toolchain</strong>&nbsp;(not Gulp) since you&#8217;re on SPFx v1.22+, and trust your developer certificate before testing locally. If you ever switch machines or work with an older project that uses SPFx v1.21.1 or below, refer back to the Gulp-based setup guide — the commands and tools are different.</p>



<p>From here, every SPFx project you scaffold will follow the same pattern: run&nbsp;<code>yo @microsoft/sharepoint</code>, answer the wizard, run&nbsp;<code>npm install</code>, and start building.</p>



<p>Do let me know in the comments below if you face any issues.</p>



<p>You may also like the following tutorials:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/build-a-sharepoint-folder-tree-view-using-spfx/">Build a SharePoint Folder Tree View Using SharePoint Framework (SPFx)</a></li>



<li><a href="https://www.spguides.com/sharepoint-framework-interview-questions-and-answers/">SharePoint Framework (SPFx) Interview Questions and Answers</a></li>



<li><a href="https://www.spguides.com/retrieve-sharepoint-list-items-using-sharepoint-framework/">Display SharePoint List Items in SPFx Web Part</a></li>



<li><a href="https://www.spguides.com/spfx-fluent-ui-react-dropdown/">Fluent UI React Dropdown in SharePoint Framework (SPFx)</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Change Solution Name in SPFx (SharePoint Framework)</title>
		<link>https://www.spguides.com/change-solution-name-in-spfx/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Wed, 22 Apr 2026 16:38:02 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Change Solution Name in SPFx]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=132888</guid>

					<description><![CDATA[So you created an SPFx project, named it something like my-first-webpart in a rush, and now you&#8217;re staring at it thinking — this doesn&#8217;t look professional at all. Or maybe you downloaded a PnP sample from the community gallery, and now you need to rename it before deploying to production. In this tutorial, I will show you how ... <a title="How to Change Solution Name in SPFx (SharePoint Framework)" class="read-more" href="https://www.spguides.com/change-solution-name-in-spfx/" aria-label="Read more about How to Change Solution Name in SPFx (SharePoint Framework)">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>So you created an<a href="https://www.spguides.com/build-a-sharepoint-folder-tree-view-using-spfx/" target="_blank" rel="noreferrer noopener"> SPFx project</a>, named it something like <code>my-first-webpart</code> in a rush, and now you&#8217;re staring at it thinking — <em>this doesn&#8217;t look professional at all</em>. Or maybe you downloaded a PnP sample from the community gallery, and now you need to rename it before deploying to production.</p>



<p>In this tutorial, I will show you how to <strong>change the SPFx solution name</strong> that every developer is looking for. I will explain in detail which files you need to modify.</p>



<p>I&#8217;ll walk you through two methods:</p>



<ol class="wp-block-list">
<li><strong>The manual method</strong> — editing the files yourself (full control, always works)</li>



<li><strong>The CLI for Microsoft 365 method</strong>&nbsp;— a single command that does the heavy lifting for you</li>
</ol>



<p>Let&#8217;s get into it.</p>



<h2 class="wp-block-heading" id="why-the-solution-name-matters">Why the Solution Name Matters</h2>



<p>Before we start changing things, let me quickly explain what the solution name actually affects.</p>



<p>When you build and deploy an SPFx package (<code>.sppkg</code> file) to the <a href="https://www.spguides.com/sharepoint-online-app-catalog/" target="_blank" rel="noreferrer noopener">SharePoint App Catalog</a>, SharePoint reads the <strong>name</strong> from your project config to display in the App Catalog&#8217;s <strong>Title</strong> column. That&#8217;s the name your site admins and end users will see when they browse available apps.</p>



<p>If you left it as&nbsp;<code>helloworld-webpart-client-side-solution</code>&nbsp;from the Yeoman generator, that&#8217;s exactly what shows up in the App Catalog. Not a great look.</p>



<p>The name also shows up in:</p>



<ul class="wp-block-list">
<li>The&nbsp;<code>.sppkg</code>&nbsp;filename itself (the deployed package)</li>



<li>The Teams app manifest (if you&#8217;re targeting Microsoft Teams)</li>



<li>Internal references inside the solution package</li>
</ul>



<p>So yes, it&#8217;s worth getting right before you deploy.</p>



<h2 class="wp-block-heading" id="what-files-store-the-solution-name">What Files Store the SPFx Solution Name?</h2>



<p>Here&#8217;s a quick map of all the places where the name lives in a typical SPFx project:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>File</th><th>What it controls</th></tr></thead><tbody><tr><td><code>config/package-solution.json</code></td><td>The&nbsp;<strong>solution name</strong>&nbsp;shown in the App Catalog</td></tr><tr><td><code>config/package-solution.json</code>&nbsp;(paths)</td><td>The&nbsp;<strong><code>.sppkg</code>&nbsp;filename</strong></td></tr><tr><td><code>package.json</code></td><td>The&nbsp;<strong>npm package name</strong>&nbsp;for your project</td></tr><tr><td><code>.yo-rc.json</code></td><td>The&nbsp;<strong>Yeoman generator config</strong>&nbsp;(project name reference)</td></tr><tr><td><code>src/webparts/[name]/[name]WebPart.manifest.json</code></td><td>The&nbsp;<strong>web part title</strong>&nbsp;in the toolbox</td></tr><tr><td><code>README.md</code></td><td>Project docs (cosmetic, but worth updating)</td></tr></tbody></table></figure>



<p>The most important one is&nbsp;<code>package-solution.json</code>. That&#8217;s the one that controls what you see in SharePoint&#8217;s App Catalog.</p>



<p>Also check out <a href="https://www.spguides.com/install-nvm-in-windows/">How to Install NVM in Windows</a></p>



<h2 class="wp-block-heading" id="method-1-manual-rename-the-right-way-to-understand">Method 1: Manual Rename (The Right Way to Understand It)</h2>



<p>This is my preferred way when I want full control over which changes and which don&#8217;t. It takes about 5 minutes.</p>



<h3 class="wp-block-heading">Step 1 — Open config/package-solution.json in SPFx Solution</h3>



<p>This is the main config file for your solution package. It looks something like this by default:</p>



<pre class="wp-block-preformatted">{<br>  "$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",<br>  "solution": {<br>    "name": "helloworld-webpart-client-side-solution-client-side-solution",<br>    "id": "e1a41469-fed8-47ab-988f-d8236ad26d71",<br>    "version": "1.0.0.0",<br>    "includeClientSideAssets": true,<br>    "skipFeatureDeployment": true,<br>    "isDomainIsolated": false,<br>    "developer": {<br>      "name": "",<br>      "websiteUrl": "",<br>      "privacyUrl": "",<br>      "termsOfUseUrl": "",<br>      "mpnId": "Undefined-1.22.2"<br>    },<br>    "metadata": {<br>      "shortDescription": {<br>        "default": "helloworld-webpart-client-side-solution description"<br>      },<br>      "longDescription": {<br>        "default": "helloworld-webpart-client-side-solution description"<br>      },<br>      "screenshotPaths": [],<br>      "videoUrl": "",<br>      "categories": []<br>    },<br>    "features": [<br>      {<br>        "title": "helloworld-webpart-client-side-solution Feature",<br>        "description": "The feature that activates elements of the helloworld-webpart-client-side-solution solution.",<br>        "id": "6a150251-c8bc-478d-9baa-4bb221f1f157",<br>        "version": "1.0.0.0"<br>      }<br>    ]<br>  },<br>  "paths": {<br>    "zippedPackage": "solution/helloworld-webpart-client-side-solution.sppkg"<br>  }<br>}</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f4f3f4" data-has-transparency="false" style="--dominant-color: #f4f3f4;" loading="lazy" decoding="async" width="1024" height="650" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/change-spfx-solution-name-1024x650.avif" alt="change spfx solution name" class="wp-image-134161 not-transparent" title="change spfx solution name" srcset="https://www.spguides.com/wp-content/uploads/2026/04/change-spfx-solution-name-1024x650.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/change-spfx-solution-name-300x191.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/change-spfx-solution-name-768x488.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/change-spfx-solution-name.avif 1354w" /></figure></div>


<p>There are two things to change here:</p>



<p><strong>Change 1 — The solution name:</strong></p>



<pre class="wp-block-preformatted">"name": "tsinfo-employee-directory-client-side-solution<code>"</code></pre>



<p>This is what shows up in the <a href="https://www.spguides.com/sharepoint-online-app-catalog/">App Catalog&#8217;s</a>&nbsp;<strong>Title</strong>&nbsp;column. Keep it descriptive. Avoid using SharePoint or Teams feature keywords like &#8220;Files&#8221;, &#8220;Chat&#8221;, &#8220;Calendar&#8221;, etc., since that can confuse users.</p>



<p><strong>Change 2 — The&nbsp;<code>.sppkg</code>&nbsp;filename:</strong></p>



<pre class="wp-block-preformatted">"paths": {<br>  "zippedPackage": "solution/tsinfo-employee-directory.sppkg"<br>}</pre>



<p>Only update the part after the&nbsp;<code>/</code>. The&nbsp;<code>solution/</code>&nbsp;folder path stays the same.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Pro tip:</strong>&nbsp;You can also add an optional&nbsp;<code>title</code>&nbsp;field inside&nbsp;<code>solution</code>&nbsp;if you want a more human-friendly display name with spaces and special characters:</p>



<pre class="wp-block-preformatted">"title": "Tsinfo Employee Directory"</pre>



<p>The&nbsp;<code>title</code>&nbsp;field supports localized strings, while&nbsp;<code>name</code>&nbsp;is the non-localized internal identifier.</p>
</blockquote>



<p>In metadata, you can also update the solution name.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f6f5f5" data-has-transparency="false" style="--dominant-color: #f6f5f5;" loading="lazy" decoding="async" width="1024" height="630" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-solution-name-1024x630.avif" alt="how to change spfx solution name" class="wp-image-134163 not-transparent" title="how to change spfx solution name" srcset="https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-solution-name-1024x630.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-solution-name-300x185.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-solution-name-348x215.avif 348w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-solution-name-768x473.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-solution-name.avif 1394w" /></figure></div>


<h3 class="wp-block-heading">Step 2 — Open package.json in SPFx Solution</h3>



<p>This is your npm project file in the root of your SPFx project. Find the&nbsp;<code>name</code>&nbsp;field:</p>



<pre class="wp-block-preformatted">{<br>  "name": "helloworld-webpart-client-side-solution",<br>  ...<br>}</pre>



<p>Change it to match your new name:</p>



<pre class="wp-block-preformatted">{<br>  "name": "tsinfo-employee-directory",<br>  ...<br>}</pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f7f5f6" data-has-transparency="false" style="--dominant-color: #f7f5f6;" loading="lazy" decoding="async" width="566" height="472" sizes="(max-width: 566px) 100vw, 566px" src="https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-solution-name.avif" alt="how to rename spfx solution name" class="wp-image-134173 not-transparent" title="how to rename spfx solution name" srcset="https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-solution-name.avif 566w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-solution-name-300x250.avif 300w" /></figure></div>


<p>Note: npm package names must be lowercase, with no spaces — use hyphens instead.</p>



<h3 class="wp-block-heading">Step 3 — Open .yo-rc.json in SPFx Solution</h3>



<p>This file stores the Yeoman generator&#8217;s memory of your project. Open it and look for the&nbsp;<code>solutionName</code>&nbsp;property:</p>



<pre class="wp-block-preformatted">{<br>  "@microsoft/generator-sharepoint": {<br>    "solutionName": "helloworld-webpart-client-side-solution",<br>    ...<br>  }<br>}</pre>



<p>Update it to your new name:</p>



<pre class="wp-block-preformatted">{<br>  "@microsoft/generator-sharepoint": {<br>    "solutionName": "tsinfo-employee-directory",<br>    ...<br>  }<br>}</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f7f5f6" data-has-transparency="false" style="--dominant-color: #f7f5f6;" loading="lazy" decoding="async" width="1024" height="300" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-webpart-1024x300.avif" alt="how to rename spfx webpart" class="wp-image-134176 not-transparent" title="how to rename spfx webpart" srcset="https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-webpart-1024x300.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-webpart-300x88.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-webpart-768x225.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-webpart-1536x450.avif 1536w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-rename-spfx-webpart.avif 1592w" /></figure></div>


<h3 class="wp-block-heading" id="step-4--update-the-web-part-manifest-optional-but">Step 4 — Update the SPFx Web Part Manifest (Optional but Recommended)</h3>



<p>If you also want to rename what appears in the SharePoint web part toolbox (the &#8220;add a web part&#8221; panel), open the web part manifest file. It&#8217;s usually at:</p>



<pre class="wp-block-preformatted">src/webparts/[yourWebPartName]/[YourWebPartName]WebPart.manifest.json</pre>



<p>Look for this section:</p>



<pre class="wp-block-preformatted"> "preconfiguredEntries": [{<br>    "groupId": "5c03119e-3074-46fd-976b-c60198311f70",<br>    "group": { "default": "Advanced" },<br>    "title": { "default": "helloworld" },<br>    "description": { "default": "helloworld description" },<br>    "officeFabricIconFontName": "Page",<br>    "properties": {<br>      "description": "helloworld"<br>    }<br>  }]</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f8f6f6" data-has-transparency="false" style="--dominant-color: #f8f6f6;" loading="lazy" decoding="async" width="1024" height="324" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-web-part-name-in-spfx-1024x324.avif" alt="how to change web part name in spfx" class="wp-image-134185 not-transparent" title="how to change web part name in spfx" srcset="https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-web-part-name-in-spfx-1024x324.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-web-part-name-in-spfx-300x95.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-web-part-name-in-spfx-768x243.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-web-part-name-in-spfx-1536x486.avif 1536w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-web-part-name-in-spfx.avif 1840w" /></figure></div>


<p>Update the&nbsp;<code>title.default</code>&nbsp;value to your new display name. This is what end users see when they search for your web part.</p>



<h3 class="wp-block-heading" id="step-5--rebuild-and-repackage">Step 5 — Rebuild and Repackage The SPFx Solution</h3>



<p>After all changes are saved, run the standard build commands:</p>



<pre class="wp-block-preformatted">heft build --clean<br>heft package-solution --production</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="1f3e6a" data-has-transparency="false" style="--dominant-color: #1f3e6a;" loading="lazy" decoding="async" width="1024" height="526" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-web-part-solution-name-1024x526.avif" alt="how to change spfx web part solution name" class="wp-image-134192 not-transparent" title="how to change spfx web part solution name" srcset="https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-web-part-solution-name-1024x526.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-web-part-solution-name-300x154.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-web-part-solution-name-768x395.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/how-to-change-spfx-web-part-solution-name.avif 1152w" /></figure></div>


<p>This regenerates the&nbsp;<code>.sppkg</code>&nbsp;file with the new name. Upload it to the App Catalog, and you&#8217;re done.</p>



<p>Check out <a href="https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/">Build a Custom Slides Manager in SPFx Web Part Property Pane</a></p>



<h2 class="wp-block-heading" id="method-2-cli-for-microsoft-365-the-fast-way">Method 2: CLI for Microsoft 365 (The Fast Way)</h2>



<p>If you&#8217;d rather not touch multiple files manually, the&nbsp;<strong>CLI for Microsoft 365</strong>&nbsp;has a dedicated command that handles renaming for you in one shot. This is especially useful when you&#8217;re working with a PnP sample and just need a quick rename.</p>



<h2 class="wp-block-heading" id="install-or-use-without-installing">Install (or use without installing)</h2>



<p>You can run it without a global install using&nbsp;<code>npx</code>:</p>



<pre class="wp-block-preformatted">npx -p @pnp/cli-microsoft365 -- m365 spfx project rename --newName tsinfo-employees-directory</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="385076" data-has-transparency="false" style="--dominant-color: #385076;" loading="lazy" decoding="async" width="1024" height="166" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/04/cli-for-microsoft-365-to-rename-spfx-solution-1024x166.avif" alt="cli for microsoft 365 to rename spfx solution" class="wp-image-134201 not-transparent" title="cli for microsoft 365 to rename spfx solution" srcset="https://www.spguides.com/wp-content/uploads/2026/04/cli-for-microsoft-365-to-rename-spfx-solution-1024x166.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/04/cli-for-microsoft-365-to-rename-spfx-solution-300x49.avif 300w, https://www.spguides.com/wp-content/uploads/2026/04/cli-for-microsoft-365-to-rename-spfx-solution-768x125.avif 768w, https://www.spguides.com/wp-content/uploads/2026/04/cli-for-microsoft-365-to-rename-spfx-solution.avif 1404w" /></figure></div>


<p>Or if you have it installed globally:</p>



<pre class="wp-block-preformatted">m365 spfx project rename --newName tsinfo-employees-directory</pre>



<p>Make sure you run this command from&nbsp;<strong>inside your SPFx project folder</strong>.</p>



<h2 class="wp-block-heading" id="what-this-command-updates-automatically">What This Command Updates Automatically</h2>



<p>When you run the rename command, it updates the project name in all of these files at once:</p>



<ul class="wp-block-list">
<li><code>package.json</code></li>



<li><code>.yo-rc.json</code></li>



<li><code>config/package-solution.json</code></li>



<li><code>config/deploy-azure-storage.json</code></li>



<li><code>README.md</code></li>
</ul>



<h2 class="wp-block-heading" id="generate-a-new-solution-id-important-for-cloned-pr">Generate a New SPFx Solution ID (Important for Cloned Projects)</h2>



<p>If you&#8217;re renaming a project that was cloned or copied from another one (like a <a href="https://www.spguides.com/pnp-react-pagination-control-spfx/">PnP sample</a>), you should also generate a fresh solution ID. Two solutions with the same GUID will conflict in the App Catalog:</p>



<pre class="wp-block-preformatted">m365 spfx project rename --newName contoso-employee-directory --generateNewId</pre>



<p>The&nbsp;<code>--generateNewId</code>&nbsp;flag creates a brand-new GUID for the&nbsp;<code>id</code>&nbsp;field in&nbsp;<code>package-solution.json</code>. Always use this when renaming a cloned or downloaded sample.</p>



<h2 class="wp-block-heading" id="common-mistakes-to-avoid">Common Mistakes to Avoid</h2>



<p>Here are a few mistakes that you should look at as a SPFx developer while renaming the SharePoint Framework solution name.</p>



<ul class="wp-block-list">
<li><strong>Only changing one file</strong>&nbsp;— Forgetting to update&nbsp;<code>package.json</code>&nbsp;or&nbsp;<code>.yo-rc.json</code>&nbsp;won&#8217;t break your build, but it creates confusing mismatches between your npm package name and what&#8217;s deployed.</li>



<li><strong>Not repackaging after the rename</strong>&nbsp;— Your changes only take effect after you run&nbsp;<code>heft build --clean</code>&nbsp;and&nbsp;<code>heft package-solution --production</code>&nbsp;again.</li>



<li><strong>Uploading without replacing</strong>&nbsp;— When you re-upload the&nbsp;<code>.sppkg</code>&nbsp;to the App Catalog, make sure you check&nbsp;<strong>&#8220;Replace it&#8221;</strong>&nbsp;if the old file is still there.</li>



<li><strong>Using the same GUID for cloned solutions</strong>&nbsp;— If you copied a solution from somewhere, always use&nbsp;<code>--generateNewId</code>&nbsp;or manually generate a new GUID. Duplicate IDs cause deployment errors.</li>



<li><strong>Special characters in the&nbsp;<code>name</code>&nbsp;field</strong>&nbsp;— The&nbsp;<code>name</code>&nbsp;property in&nbsp;<code>package-solution.json</code>&nbsp;doesn&#8217;t support special characters. If you want spaces or symbols in what users see, use the&nbsp;<code>title</code>&nbsp;field instead.</li>
</ul>



<h2 class="wp-block-heading" id="which-method-should-you-use">Which Method Should You Use?</h2>



<p>Honestly, if you&#8217;re comfortable in VS Code and understand your project structure, the manual method gives you the most clarity and control. You see exactly what changed and why.</p>



<p>If you&#8217;re in a hurry or you&#8217;re doing this regularly across multiple projects (like spinning up new projects from PnP samples), the CLI for Microsoft 365 method saves real time. The&nbsp;<code>--generateNewId</code>&nbsp;flag especially is a lifesaver if you work with community samples.</p>



<p>Both methods get you to the same end result — a properly renamed, clean SPFx solution ready for deployment.</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download Complete SPFx Solutions</a></div>
</div>



<h2 class="wp-block-heading">Conclusion</h2>



<p>I hope you found this article helpful! In this tutorial, I explained two methods for <strong>renaming an existing SPFx solution</strong>, along with example images. Additionally, I also explained which method to use at which time. Follow these methods when you are also trying to rename your SPFx project.</p>



<p>Also, you may like:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/">Bind SharePoint List Items to SPFx Fluent UI React Dropdown</a></li>



<li><a href="https://www.spguides.com/create-modal-popup-in-spfx/">Create a Modal Popup in SPFx</a></li>



<li><a href="https://www.spguides.com/customize-sharepoint-list-command-bar-download-button-using-spfx-extension/">Customize SharePoint List Command Bar Download Button Using SPFx Extension</a></li>



<li><a href="https://www.spguides.com/spfx-upload-file-to-sharepoint-document-library-with-metadata/">Upload File to SharePoint Document Library With Metadata in SPFx</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Install NVM in Windows</title>
		<link>https://www.spguides.com/install-nvm-in-windows/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Tue, 14 Apr 2026 15:38:53 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Install NVM in Windows]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=125352</guid>

					<description><![CDATA[One of my clients recently faced an issue with the SPFx web part. Actually, their web part triggers emails when specific changes are made to the files they uploaded. To fix their problem, I have imported their SPFx solution package into my system to update the code. After updating the code, I need to build ... <a title="How to Install NVM in Windows" class="read-more" href="https://www.spguides.com/install-nvm-in-windows/" aria-label="Read more about How to Install NVM in Windows">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>One of my clients recently faced an issue with the <a href="https://www.spguides.com/sharepoint-framework-client-web-part/">SPFx web part</a>. Actually, their web part triggers emails when specific changes are made to the files they uploaded. To fix their problem, I have imported their SPFx solution package into my system to update the code.</p>



<p>After updating the code, I need to build the package for deployment, but we got stuck because Im using the latest SPFx V1.21.11 and my Node version is V22. But the client&#8217;s SPFx solution is using the old version 10. To work on the client solution, I had to downgrade my Node version. </p>



<p>But side by side, Im also working for some other clients who are using the latest versions. In this case, I can&#8217;t downgrade or upgrade my Node version every time, which isn&#8217;t a good option either. </p>



<p>After researching, I found the best solution: NVM [Node Version Manager], which makes switching between node versions easy with simple commands. In this tutorial, I will explain how to use NVM and how to resolve issues that may arise during installation.</p>



<h2 class="wp-block-heading">What is NVM?</h2>



<p>NVM (Node Version Manager) is a tool that helps you use different versions of Node.js on the same computer. If one project needs an older Node version and another project needs a newer one, NVM lets you switch between them easily using simple commands. You don&#8217;t need to uninstall or reinstall Node again and again.</p>



<p>There are two types of NVM:</p>



<ul class="wp-block-list">
<li><strong>nvm-windows</strong> = For Windows computers</li>



<li><strong>nvm-sh</strong> = For macOS, Linux, and WSL.</li>
</ul>



<p>NVM allows you to easily upgrade to the latest Node.js versions while keeping older versions available for legacy projects.</p>



<h2 class="wp-block-heading">Download NVM for Windows</h2>



<p>When you go to the official <a href="https://www.nvmnode.com/guide/download.html" target="_blank" rel="noopener">NVM download page</a>, you&#8217;ll notice that there are many versions of nvm-windows available. Beginners often get confused about which version to download, so I suggest downloading the latest NVM version or an older one based on your project&#8217;s needs.</p>



<p>In most cases, the latest version works fine. <a href="https://github.com/coreybutler/nvm-windows/releases/download/1.2.2/nvm-setup.zip" target="_blank" rel="noopener">Download the latest version 1.2.2 from GitHub</a>. In my case, I had a special requirement, so Im downloading the <a href="https://github.com/coreybutler/nvm-windows/releases/download/1.1.12/nvm-setup.zip" target="_blank" rel="noopener">nvm version 1.1.12 from GitHub</a>.</p>



<p><strong>Note: </strong>Before installing NVM for Windows, uninstall any existing Node.js versions, as they may conflict with Node.js versions managed by NVM.</p>



<ol class="wp-block-list">
<li>Once you click the link above, a zip file named <strong>nvm-setup</strong> is downloaded to your local system, either to the Downloads folder or to any other folder you choose. Unzip that one, and within that, you will see nvm-setup as below.<a href="https://stackoverflow.com/questions/78279551/how-to-install-nvm-in-windows" target="_blank" rel="noopener"></a></li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="1004" height="360" sizes="(max-width: 1004px) 100vw, 1004px" src="https://www.spguides.com/wp-content/uploads/2025/12/nvm-for-windows.png" alt="nvm for windows" class="wp-image-125369" title="nvm for windows" srcset="https://www.spguides.com/wp-content/uploads/2025/12/nvm-for-windows.png 1004w, https://www.spguides.com/wp-content/uploads/2025/12/nvm-for-windows-300x108.png 300w, https://www.spguides.com/wp-content/uploads/2025/12/nvm-for-windows-768x275.png 768w" /></figure></div>


<ol start="2" class="wp-block-list">
<li>Click nvm-setup; it will open a wizard to allow NVM into your system. Click <strong>Yes</strong>. Then, the following image will appear<span style="box-sizing: border-box; margin: 0px; padding: 0px;">. I chose the&nbsp;<strong>I accept the agreement</strong>&nbsp;option and clicked the&nbsp;</span><strong>Next </strong>button.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="572" height="478" sizes="(max-width: 572px) 100vw, 572px" src="https://www.spguides.com/wp-content/uploads/2025/12/nvm-install-windows.png" alt="nvm install windows" class="wp-image-125370" title="nvm install windows" srcset="https://www.spguides.com/wp-content/uploads/2025/12/nvm-install-windows.png 572w, https://www.spguides.com/wp-content/uploads/2025/12/nvm-install-windows-300x251.png 300w" /></figure></div>


<ol start="3" class="wp-block-list">
<li>Select the installation location by clicking <strong>Browse</strong>, and then click <strong>Next</strong>.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="584" height="480" sizes="(max-width: 584px) 100vw, 584px" src="https://www.spguides.com/wp-content/uploads/2025/12/nvm-for-windows-download.png" alt="nvm for windows download" class="wp-image-125372" title="nvm for windows download" srcset="https://www.spguides.com/wp-content/uploads/2025/12/nvm-for-windows-download.png 584w, https://www.spguides.com/wp-content/uploads/2025/12/nvm-for-windows-download-300x247.png 300w" /></figure></div>


<ol start="4" class="wp-block-list">
<li>Select the directory for the installation of <strong>Node.js</strong>. Then click on <strong>Next</strong>.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="582" height="478" sizes="(max-width: 582px) 100vw, 582px" src="https://www.spguides.com/wp-content/uploads/2025/12/nvm-windows-github-releases-page.png" alt="nvm-windows github releases page" class="wp-image-125373" title="nvm windows github releases page" srcset="https://www.spguides.com/wp-content/uploads/2025/12/nvm-windows-github-releases-page.png 582w, https://www.spguides.com/wp-content/uploads/2025/12/nvm-windows-github-releases-page-300x246.png 300w" /></figure></div>


<ol start="5" class="wp-block-list">
<li>This is for email subscription notifications, which can be completely disabled. You can check all options and click <strong>Next</strong>.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="627" height="498" sizes="(max-width: 627px) 100vw, 627px" src="https://www.spguides.com/wp-content/uploads/2025/12/download-nvm-for-windows-11.png" alt="download nvm for windows 11" class="wp-image-125374" title="download nvm for windows 11" srcset="https://www.spguides.com/wp-content/uploads/2025/12/download-nvm-for-windows-11.png 627w, https://www.spguides.com/wp-content/uploads/2025/12/download-nvm-for-windows-11-300x238.png 300w" /></figure></div>


<ol start="6" class="wp-block-list">
<li>Provide your email for subscriptions. This is optional; you can leave it blank.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="620" height="492" sizes="(max-width: 620px) 100vw, 620px" src="https://www.spguides.com/wp-content/uploads/2025/12/nvm-windows-github-releases.png" alt="nvm windows github releases" class="wp-image-125375" title="nvm windows github releases" srcset="https://www.spguides.com/wp-content/uploads/2025/12/nvm-windows-github-releases.png 620w, https://www.spguides.com/wp-content/uploads/2025/12/nvm-windows-github-releases-300x238.png 300w" /></figure></div>


<ol start="7" class="wp-block-list">
<li>Click <span style="box-sizing: border-box; margin: 0px; padding: 0px;"><strong>Install&nbsp;</strong>if you&#8217;re ok with the Destination location; if</span> not, go back and change it.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="584" height="486" sizes="(max-width: 584px) 100vw, 584px" src="https://www.spguides.com/wp-content/uploads/2025/12/download-nvm-for-windows-11-64-bit.png" alt="download nvm for windows 11 64 bit" class="wp-image-125376" title="download nvm for windows 11 64 bit" srcset="https://www.spguides.com/wp-content/uploads/2025/12/download-nvm-for-windows-11-64-bit.png 584w, https://www.spguides.com/wp-content/uploads/2025/12/download-nvm-for-windows-11-64-bit-300x250.png 300w" /></figure></div>


<ol start="8" class="wp-block-list">
<li>This installs the nvm into your system. Once it is installed, open the command prompt and run the command below to check the nvm version.</li>
</ol>



<pre class="wp-block-code"><code>nvm --version</code></pre>



<p>If the nvm version number is displayed, the installation was successful.</p>



<ol start="9" class="wp-block-list">
<li>To see all available <strong>Node.js</strong> versions that you can install using nvm, run the command below.</li>
</ol>



<pre class="wp-block-code"><code>nvm list available</code></pre>



<p>In the image below, you can see the list of available Node.js versions that you can download with nvm.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="616" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2025/12/download-node-js-for-windows-using-nvm-1024x616.png" alt="download node js for windows using nvm" class="wp-image-125379" title="download node js for windows using nvm" srcset="https://www.spguides.com/wp-content/uploads/2025/12/download-node-js-for-windows-using-nvm-1024x616.png 1024w, https://www.spguides.com/wp-content/uploads/2025/12/download-node-js-for-windows-using-nvm-300x180.png 300w, https://www.spguides.com/wp-content/uploads/2025/12/download-node-js-for-windows-using-nvm-768x462.png 768w, https://www.spguides.com/wp-content/uploads/2025/12/download-node-js-for-windows-using-nvm.png 1098w" /></figure></div>


<p>Let&#8217;s see how to install Node.js using Node Version Manager in the section below.</p>



<h2 class="wp-block-heading">Commands to Install &amp; Uninstall Node.js</h2>



<p>To install a specific version of Node.js using nvm, run the following command.</p>



<pre class="wp-block-code"><code>nvm install &lt;version&gt;</code></pre>



<p>Here, inplace of version, please specify the version number, for example, as below:</p>



<pre class="wp-block-code"><code>nvm install 22.21.1</code></pre>



<p>If you want to <strong>install the latest version</strong>, then run the command below.</p>



<pre class="wp-block-code"><code>nvm install --lts</code></pre>



<p>To see <strong>all the Node.js versions</strong> installed in your system, run the command below.</p>



<pre class="wp-block-code"><code>nvm list</code></pre>



<p>To <strong>uninstall </strong>the <strong>Node.js </strong>version.</p>



<pre class="wp-block-code"><code>nvm uninstall &lt;version&gt;</code></pre>



<h2 class="wp-block-heading">Switching Node.js Versions</h2>



<p>Run the command below to switch to the specific Node.js version. </p>



<pre class="wp-block-code"><code>nvm use &lt;version&gt;</code></pre>



<p>Specify the version number inplace of &lt;version&gt;, for example: </p>



<pre class="wp-block-code"><code>nvm use 0.10.48</code></pre>



<p>To check the <strong>currently </strong>active <strong>Node.js</strong> <strong>version</strong>, run the command below.</p>



<pre class="wp-block-code"><code>nvm current</code></pre>



<h2 class="wp-block-heading">Working with NPM</h2>



<p>When we switch Node.js versions using Node Version Manager, npm is also switched to the version bundled with that Node.js version. So, to make a package available across all Node.js versions, we need to reinstall it for each version. Here is the command.</p>



<pre class="wp-block-code"><code>npm install -g &lt;package-name&gt;</code></pre>



<p>In the example below, I showed how to reinstall the <span style="box-sizing: border-box; margin: 0px; padding: 0px;"><strong>Gulp</strong>,&nbsp;<strong>Yeoman</strong>, and&nbsp;<strong>SharePoint Generator</strong>&nbsp;<strong>packages</strong>&nbsp;a</span>fter switching&nbsp;Node.js versions. Running this command is mandatory; otherwise, your gulp commands, such as build, serve, package, and yo @microsoft/sharepoint, etc., won&#8217;t work.</p>



<pre class="wp-block-code"><code>npm install -g gulp-cli
npm install -g yo
npm install -g @microsoft/generator-sharepoint</code></pre>



<h2 class="wp-block-heading">Error: Unable to install npm on older Node.js versions&nbsp;</h2>



<p>If you installed the <strong>NVM </strong>latest version and are trying to install the very old versions of <strong>Node.js</strong>, you might face the following error.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="165" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2025/12/Unable-to-install-npm-on-older-nodejs-versions-1024x165.png" alt="Unable to install npm on older nodejs versions" class="wp-image-125403" title="Unable to install npm on older nodejs versions" srcset="https://www.spguides.com/wp-content/uploads/2025/12/Unable-to-install-npm-on-older-nodejs-versions-1024x165.png 1024w, https://www.spguides.com/wp-content/uploads/2025/12/Unable-to-install-npm-on-older-nodejs-versions-300x48.png 300w, https://www.spguides.com/wp-content/uploads/2025/12/Unable-to-install-npm-on-older-nodejs-versions-768x123.png 768w, https://www.spguides.com/wp-content/uploads/2025/12/Unable-to-install-npm-on-older-nodejs-versions-1536x247.png 1536w, https://www.spguides.com/wp-content/uploads/2025/12/Unable-to-install-npm-on-older-nodejs-versions.png 1742w" /></figure></div>


<pre class="wp-block-code"><code>error installing 0.10.48: open C:\users\&lt;username&gt;\AppDate\Local\Temp\nvm-npm-978772599\npm-v2.15.1.zip: The system cannot find the file specified.</code></pre>



<p>This basically means NVM was unable to download the old npm file for that Node version. Some of the new NVM releases no longer support installing such very old Node.js versions, so the command fails.</p>



<p>After trying a few options and searching GitHub Issue threads, I found that <strong>NVM version 1.1.12 </strong>still supports installing older Node.js versions, such as 0.10.x and 4.x, etc. So I downloaded and installed the NVM 1.1.12, and everything worked perfectly. </p>



<ul class="wp-block-list">
<li>I was able to install Node.js 0.10.48 and later.</li>



<li>I was also able to install newer Node.js versions(16,18,20, etc)</li>



<li>Switching between them works without any issues.</li>
</ul>



<p>Even though<strong> NVM 1.1.12</strong> is not the latest version, it is more <strong>stable </strong>for working with very old Node versions.</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download SPFx Solutions</a></div>
</div>



<h2 class="wp-block-heading">Conclusion</h2>



<p>I hope you found this tutorial helpful! If you&#8217;re working with multiple versions of SPFx and Node.js on the same computer, then follow this article and use NVM to switch between the Node.js versions, without uninstalling and reinstalling.</p>



<p>In this tutorial, I explained what NVM is, how to download it, the basic commands for installing and uninstalling Node.js, how to switch between Node.js versions, how to work with npm, and how to resolve errors when installing very old Node.js versions.</p>



<p>Also, look at some SPFx blog posts below:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/delete-node-modules/">Delete node_modules from SPFx solution (rimraf)</a></li>



<li><a href="https://www.spguides.com/a-primitive-value-or-startobjectnode-was-expected/">a ‘primitive value’ or ‘StartObject’node was expected</a></li>



<li><a href="https://www.spguides.com/create-a-sharepoint-list-or-library-spfx/">Create a SharePoint List or Library Using No Framework in SPFx Web Part</a></li>



<li><a href="https://www.spguides.com/sharepoint-framework-crud-operations-no-javascript-framework/">SPFx CRUD Operations using No JavaScript Framework</a></li>



<li><a href="https://www.spguides.com/spfx-send-email-using-pnpjs/">Send Email in SPFx using Microsoft Graph API and PnP JS</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to Create a Modal Popup in SPFx (4 Methods with Full Examples)</title>
		<link>https://www.spguides.com/create-modal-popup-in-spfx/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Tue, 07 Apr 2026 13:09:00 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Create a Modal Popup in SPFx]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=132820</guid>

					<description><![CDATA[If you&#8217;ve been building SharePoint Framework web parts for a while, you&#8217;ve probably hit a point where you need to show a modal popup — maybe to confirm a delete action, collect some input, or display detailed info without navigating away from the page. The good news? SPFx gives you multiple ways to do this. ... <a title="How to Create a Modal Popup in SPFx (4 Methods with Full Examples)" class="read-more" href="https://www.spguides.com/create-modal-popup-in-spfx/" aria-label="Read more about How to Create a Modal Popup in SPFx (4 Methods with Full Examples)">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>If you&#8217;ve been <a href="https://www.spguides.com/sharepoint-framework-client-web-part/" target="_blank" rel="noreferrer noopener">building SharePoint Framework web parts</a> for a while, you&#8217;ve probably hit a point where you need to show a modal popup — maybe to confirm a delete action, collect some input, or display detailed info without navigating away from the page.</p>



<p>The good news? SPFx gives you multiple ways to do this. In this tutorial, I&#8217;ll walk you through&nbsp;<strong>three practical methods</strong>&nbsp;with real code so you can pick the one that fits your scenario.</p>



<p>Here&#8217;s what we&#8217;ll cover:</p>



<ul class="wp-block-list">
<li>Method 1 — Fluent UI&nbsp;<code>&lt;Modal&gt;</code>&nbsp;component (best for web parts)</li>



<li>Method 2 — Fluent UI&nbsp;<code>&lt;Dialog&gt;</code>&nbsp;component (great for confirmations)</li>



<li>Method 3 —&nbsp;<code>BaseDialog</code>&nbsp;from&nbsp;<code>@microsoft/sp-dialog</code>&nbsp;(best for extensions)</li>



<li>Method 4 — Using Native HTML&nbsp;&lt;dialog&gt;&nbsp;Element</li>
</ul>



<h2 class="wp-block-heading" id="prerequisites">Prerequisites</h2>



<p>Before we start, make sure you have:</p>



<ul class="wp-block-list">
<li>Node.js (v18.x recommended for SPFx 1.18+)</li>



<li>SPFx Yeoman generator installed (<code>@microsoft/generator-sharepoint</code>)</li>



<li>A React-based SPFx solution scaffolded and ready</li>



<li>Basic familiarity with TypeScript and React hooks</li>
</ul>



<p>If you haven&#8217;t scaffolded a solution yet, run:</p>



<pre class="wp-block-preformatted">yo @microsoft/sharepoint</pre>



<p>Choose&nbsp;<strong>WebPart</strong>,&nbsp;<strong>React</strong>&nbsp;framework, and give it a name like&nbsp;<code>ModalDemo</code>.</p>



<h2 class="wp-block-heading" id="a-quick-note-on-modal-vs-dialog-in-spfx">&#8220;Modal&#8221; vs &#8220;Dialog&#8221; in SPFx</h2>



<p>People often use these terms interchangeably, and honestly, in everyday SPFx work, they mean the same thing — a pop-up that appears over the page content. Technically, a&nbsp;<strong>modal</strong>&nbsp;blocks interaction with the rest of the page, while a&nbsp;<strong>dialog</strong>&nbsp;may or may not. But for this tutorial, I&#8217;m using both terms to mean the same thing.</p>



<h2 class="wp-block-heading">Create a Modal Popup in SharePoint Framework (SPFx)</h2>



<p>Now, let us see different methods to create a modal popup in SharePoint Framework (SPFx).</p>



<h3 class="wp-block-heading">Method 1: Fluent UI&nbsp;&lt;Modal&gt;&nbsp;Component</h3>



<p>This is my go-to method for <a href="https://www.spguides.com/sharepoint-framework-client-web-part/">web parts</a>. The&nbsp;<code>&lt;Modal&gt;</code>&nbsp;component from&nbsp;<code>@fluentui/react</code>&nbsp;gives you a lot of control over how your pop-up looks and behaves. It&#8217;s a proper overlay that blocks the rest of the page while it&#8217;s open.</p>



<h4 class="wp-block-heading" id="when-to-use-this">When to use this</h4>



<ul class="wp-block-list">
<li>You need a fully custom layout inside the pop-up</li>



<li>You want to show a form, a table, or rich content</li>



<li>You&#8217;re building inside a web part (not an extension)</li>
</ul>



<h4 class="wp-block-heading" id="step-1--install-fluent-ui-if-not-already-installed">Step 1 — Install Fluent UI (if not already installed)</h4>



<p>In most SPFx 1.16+ projects,&nbsp;<code>@fluentui/react</code>&nbsp;is already available. Just double-check your&nbsp;<code>package.json</code>. If it&#8217;s missing:</p>



<pre class="wp-block-preformatted">npm install @fluentui/react --save</pre>



<p>Also, install the hooks package:</p>



<pre class="wp-block-preformatted">npm install @fluentui/react-hooks --save</pre>



<h4 class="wp-block-heading" id="step-2--build-the-modal-component">Step 2 — Build the Modal Component</h4>



<p>Create a new file:&nbsp;<code>"\src\webparts\spFxModelPoPups\components\MyModal.tsx"</code></p>



<pre class="wp-block-preformatted">import * as React from 'react';<br>import { Modal } from '@fluentui/react/lib/Modal';<br>import { PrimaryButton, DefaultButton, IconButton } from '@fluentui/react/lib/Button';<br>import { mergeStyleSets, FontWeights } from '@fluentui/react/lib/Styling';<br><br>const contentStyles = mergeStyleSets({<br>  container: {<br>    display: 'flex',<br>    flexFlow: 'column nowrap',<br>    alignItems: 'stretch',<br>    width: 500,<br>  },<br>  header: {<br>    flex: '1 1 auto',<br>    display: 'flex',<br>    alignItems: 'center',<br>    fontWeight: FontWeights.semibold,<br>    padding: '12px 12px 14px 24px',<br>    backgroundColor: '#0078d4',<br>    color: '#fff',<br>  },<br>  body: {<br>    flex: '4 4 auto',<br>    padding: '0 24px 24px',<br>    overflowY: 'hidden',<br>  },<br>  footer: {<br>    padding: '0 24px 24px',<br>    display: 'flex',<br>    justifyContent: 'flex-end',<br>    gap: '8px',<br>  },<br>});<br><br>interface IMyModalProps {<br>  isOpen: boolean;<br>  onDismiss: () =&gt; void;<br>}<br><br>const MyModal: React.FC&lt;IMyModalProps&gt; = ({ isOpen, onDismiss }) =&gt; {<br>  return (<br>    &lt;Modal<br>      isOpen={isOpen}<br>      onDismiss={onDismiss}<br>      isBlocking={true}<br>      containerClassName={contentStyles.container}<br>    &gt;<br>      &lt;div className={contentStyles.header}&gt;<br>        &lt;span&gt;Employee Details&lt;/span&gt;<br>        &lt;IconButton<br>          iconProps={{ iconName: 'Cancel' }}<br>          ariaLabel="Close popup modal"<br>          onClick={onDismiss}<br>          styles={{ root: { marginLeft: 'auto', color: '#fff' } }}<br>        /&gt;<br>      &lt;/div&gt;<br>      &lt;div className={contentStyles.body}&gt;<br>        &lt;p&gt;Name: John Smith&lt;/p&gt;<br>        &lt;p&gt;Department: Engineering&lt;/p&gt;<br>        &lt;p&gt;Location: Bengaluru&lt;/p&gt;<br>      &lt;/div&gt;<br>      &lt;div className={contentStyles.footer}&gt;<br>        &lt;DefaultButton text="Close" onClick={onDismiss} /&gt;<br>        &lt;PrimaryButton text="Save" onClick={() =&gt; { alert('Saved!'); onDismiss(); }} /&gt;<br>      &lt;/div&gt;<br>    &lt;/Modal&gt;<br>  );<br>};<br><br>export default MyModal;</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f3f3f3" data-has-transparency="false" style="--dominant-color: #f3f3f3;" loading="lazy" decoding="async" width="1024" height="865" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/03/fluent-ui-modal-component-in-spfx-1024x865.avif" alt="fluent ui modal component in spfx" class="wp-image-133031 not-transparent" title="fluent ui modal component in spfx" srcset="https://www.spguides.com/wp-content/uploads/2026/03/fluent-ui-modal-component-in-spfx-1024x865.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/03/fluent-ui-modal-component-in-spfx-300x254.avif 300w, https://www.spguides.com/wp-content/uploads/2026/03/fluent-ui-modal-component-in-spfx-768x649.avif 768w, https://www.spguides.com/wp-content/uploads/2026/03/fluent-ui-modal-component-in-spfx.avif 1124w" /></figure></div>


<h4 class="wp-block-heading" id="step-3--use-it-in-your-main-web-part-component">Step 3 — Use it in Your Main Web Part Component</h4>



<p>Open&nbsp;<code>"\src\webparts\spFxModelPoPups\components\SpFxModelPoPups.tsx"</code>&nbsp;and update it:</p>



<p><strong>Note:</strong> The web part name and file names in the path above may vary based on your project structure. Please adjust them accordingly to match your actual file names.</p>



<pre class="wp-block-preformatted">import * as React from 'react';<br>import { useState } from 'react';<br>import { PrimaryButton } from '@fluentui/react/lib/Button';<br>import MyModal from './MyModal';<br><br>const SpFxModelPoPups: React.FC = () =&gt; {<br>  const [isModalOpen, setIsModalOpen] = useState(false);<br><br>  return (<br>    &lt;div style={{ padding: '20px' }}&gt;<br>      &lt;h2&gt;Employee Directory&lt;/h2&gt;<br>      &lt;PrimaryButton text="View Details" onClick={() =&gt; setIsModalOpen(true)} /&gt;<br>      &lt;MyModal<br>        isOpen={isModalOpen}<br>        onDismiss={() =&gt; setIsModalOpen(false)}<br>      /&gt;<br>    &lt;/div&gt;<br>  );<br>};<br><br>export default SpFxModelPoPups;</pre>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f4f2f3" data-has-transparency="false" style="--dominant-color: #f4f2f3;" loading="lazy" decoding="async" width="1024" height="545" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/03/fluentui-react-components-1024x545.avif" alt="fluentui react components" class="wp-image-133033 not-transparent" title="fluentui react components" srcset="https://www.spguides.com/wp-content/uploads/2026/03/fluentui-react-components-1024x545.avif 1024w, https://www.spguides.com/wp-content/uploads/2026/03/fluentui-react-components-300x160.avif 300w, https://www.spguides.com/wp-content/uploads/2026/03/fluentui-react-components-768x408.avif 768w, https://www.spguides.com/wp-content/uploads/2026/03/fluentui-react-components.avif 1068w" /></figure></div>


<p>That&#8217;s it for Method 1. Click the button, modal opens. Click the X or Close button, modal dismisses.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="eef1f1" data-has-transparency="false" style="--dominant-color: #eef1f1;" loading="lazy" decoding="async" width="670" height="710" sizes="(max-width: 670px) 100vw, 670px" src="https://www.spguides.com/wp-content/uploads/2026/03/spfx-popup-dialog.gif" alt="spfx popup dialog" class="wp-image-133037 not-transparent" title="spfx popup dialog"></figure></div>


<h4 class="wp-block-heading">Key&nbsp;<code>&lt;Modal&gt;</code>&nbsp;Props You Should Know</h4>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Prop</th><th>What it does</th></tr></thead><tbody><tr><td><code>isOpen</code></td><td>Controls whether the modal is visible</td></tr><tr><td><code>isBlocking</code></td><td>If&nbsp;<code>true</code>, user can&#8217;t click outside to close</td></tr><tr><td><code>onDismiss</code></td><td>Called when modal wants to close (Escape key, backdrop click)</td></tr><tr><td><code>containerClassName</code></td><td>Lets you apply custom styles to the outer container</td></tr><tr><td><code>dragOptions</code></td><td>Makes the modal draggable</td></tr></tbody></table></figure>



<p>Check out <a href="https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/">Bind SharePoint List Items to SPFx Fluent UI React Dropdown</a></p>



<h3 class="wp-block-heading">Method 2: Fluent UI&nbsp;&lt;Dialog&gt;&nbsp;Component</h3>



<p>If all you need is a&nbsp;<strong>confirm/cancel</strong>&nbsp;type popup in SPFx — like &#8220;Are you sure you want to delete this item?&#8221; — the&nbsp;<code>&lt;Dialog&gt;</code>&nbsp;component is cleaner and takes less code than&nbsp;<code>&lt;Modal&gt;</code>.</p>



<p>The&nbsp;<code>&lt;Dialog&gt;</code>&nbsp;component is purpose-built for quick confirmations and simple messages. It handles the layout for you: title, subtitle, buttons in the footer — all baked in.</p>



<h4 class="wp-block-heading" id="a-real-world-example-delete-confirmation">A Real-World Example: Delete Confirmation</h4>



<p>Here is a real world example to display a Delete confirmation message dialog box on a button click.</p>



<pre class="wp-block-preformatted">import * as React from 'react';<br>import { useState } from 'react';<br>import {<br>  Dialog,<br>  DialogType,<br>  DialogFooter,<br>} from '@fluentui/react/lib/Dialog';<br>import { PrimaryButton, DefaultButton } from '@fluentui/react/lib/Button';<br><br>const DeleteConfirmation: React.FC = () =&gt; {<br>  const [hideDialog, setHideDialog] = useState(true);<br><br>  const dialogContentProps = {<br>    type: DialogType.normal,<br>    title: 'Delete Item',<br>    subText: 'Are you sure you want to delete this item? This action cannot be undone.',<br>  };<br><br>  const modalProps = {<br>    isBlocking: true,<br>  };<br><br>  const handleDelete = () =&gt; {<br>    <em>// your delete logic here</em><br>    console.log('Item deleted!');<br>    setHideDialog(true);<br>  };<br><br>  return (<br>    &lt;div&gt;<br>      &lt;DefaultButton text="Delete Item" onClick={() =&gt; setHideDialog(false)} /&gt;<br>      &lt;Dialog<br>        hidden={hideDialog}<br>        onDismiss={() =&gt; setHideDialog(true)}<br>        dialogContentProps={dialogContentProps}<br>        modalProps={modalProps}<br>      &gt;<br>        &lt;DialogFooter&gt;<br>          &lt;PrimaryButton onClick={handleDelete} text="Delete" /&gt;<br>          &lt;DefaultButton onClick={() =&gt; setHideDialog(true)} text="Cancel" /&gt;<br>        &lt;/DialogFooter&gt;<br>      &lt;/Dialog&gt;<br>    &lt;/div&gt;<br>  );<br>};<br><br>export default DeleteConfirmation;</pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="fbfbf9" data-has-transparency="false" style="--dominant-color: #fbfbf9;" loading="lazy" decoding="async" width="434" height="400" sizes="(max-width: 434px) 100vw, 434px" src="https://www.spguides.com/wp-content/uploads/2026/03/fluent-ui-dialog-in-spfx.gif" alt="fluent ui dialog in spfx" class="wp-image-133041 not-transparent" title="fluent ui dialog in"></figure></div>


<p>Notice that&nbsp;<code>&lt;Dialog&gt;</code>&nbsp;uses&nbsp;<code>hidden</code>&nbsp;(the opposite of&nbsp;<code>isOpen</code>). It&#8217;s a small thing but it trips people up when switching between Dialog and Modal.</p>



<h4 class="wp-block-heading">Using&nbsp;useBoolean&nbsp;for Cleaner State Management</h4>



<p>One thing I love about the <a href="https://www.spguides.com/spfx-fluent-ui-react-choicegroup-and-checkbox/">Fluent UI</a> hooks package is&nbsp;<code>useBoolean</code>. Instead of managing&nbsp;<code>useState</code>&nbsp;manually for your open/close logic, you can do this:</p>



<pre class="wp-block-preformatted">import { useBoolean } from '@fluentui/react-hooks';<br><br>const [isDialogVisible, { setTrue: showDialog, setFalse: hideDialog }] = useBoolean(false);</pre>



<p>Now instead of&nbsp;<code>setIsDialogVisible(true)</code>&nbsp;you just call&nbsp;<code>showDialog()</code>. Much more readable, especially when you have multiple dialogs on a page.</p>



<h3 class="wp-block-heading">Method 3:&nbsp;BaseDialog&nbsp;from&nbsp;@microsoft/sp-dialog</h3>



<p>This method is specifically for <strong>SPFx Extensions</strong> — <a href="https://www.spguides.com/spfx-listview-command-set-extension/">ListView Command Sets</a> and Application Customizers. The <code>BaseDialog</code> class from <code>@microsoft/sp-dialog</code> is designed to render dialogs outside the normal React component tree, which is exactly what you need in extensions where you don&#8217;t have a typical component hierarchy.</p>



<p><strong>Important:</strong> When you scaffold a ListView Command Set, React is <strong>not included</strong> by default. So unlike web parts, you should build your dialog using vanilla DOM manipulation inside <code>BaseDialog</code> — no JSX, no Fluent UI imports needed.</p>



<h4 class="wp-block-heading">When to use this</h4>



<ul class="wp-block-list">
<li>You want to display selected item details in a dialog</li>



<li>You&#8217;re building a&nbsp;<strong>ListView Command Set</strong>&nbsp;extension</li>



<li>You need to trigger a popup from a&nbsp;<strong>toolbar button</strong>&nbsp;on a <a href="https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/">SharePoint list</a></li>
</ul>



<h4 class="wp-block-heading" id="step-1--scaffold-an-extension">Step 1 — Scaffold an Extension</h4>



<pre class="wp-block-code"><code>yo @microsoft/sharepoint</code></pre>



<p>Select:</p>



<ul class="wp-block-list">
<li><strong>Extension</strong>&nbsp;→&nbsp;<strong>ListView Command Set</strong></li>



<li>Name it:&nbsp;<code>TaskDialog</code></li>
</ul>



<h4 class="wp-block-heading">Step 2 — Create the Dialog File</h4>



<p>Create <code>src/extensions/taskDialog/TaskDialog.ts</code>.</p>



<p>This file contains a class that extends <code>BaseDialog</code>. Instead of using React or JSX, we build the dialog content using <strong>vanilla DOM methods</strong> — <code>document.createElement</code>, <code>textContent</code>, and <code>addEventListener</code>. SharePoint provides <code>this.domElement</code> as the dialog container, and we append our built elements directly into it.</p>



<p>The dialog shows five fields from the selected list item: ID, Title, Created By, Created date, and Modified date. A styled Close button calls <code>this.close()</code> to dismiss the dialog.</p>



<p>In <code>onAfterClose()</code>, we clear <code>this.domElement.innerHTML</code> to clean up the DOM between openings — this is the equivalent of <code>ReactDOM.unmountComponentAtNode</code> in React-based dialogs.</p>



<pre class="wp-block-preformatted">import { BaseDialog, IDialogConfiguration } from '@microsoft/sp-dialog';<br><br>export interface IItemDetails {<br>  id: string;<br>  title: string;<br>  createdBy: string;<br>  created: string;<br>  modified: string;<br>}<br><br>export default class TaskDialog extends BaseDialog {<br>  public itemDetails: IItemDetails;<br><br>  constructor(itemDetails: IItemDetails) {<br>    super({ isBlocking: true });<br>    this.itemDetails = itemDetails;<br>  }<br><br>  public render(): void {<br>    const { id, title, createdBy, created, modified } = this.itemDetails;<br><br>    const container = document.createElement('div');<br>    container.style.cssText = 'padding:24px;min-width:420px;font-family:"Segoe UI",sans-serif;';<br><br>    const heading = document.createElement('div');<br>    heading.style.cssText = 'font-size:20px;font-weight:600;margin-bottom:20px;color:#323130;';<br>    heading.textContent = 'Item Details';<br><br>    const table = document.createElement('table');<br>    table.style.cssText = 'width:100%;border-collapse:collapse;';<br><br>    const rows: [string, string][] = [<br>      ['ID',         id],<br>      ['Title',      title],<br>      ['Created By', createdBy],<br>      ['Created',    created],<br>      ['Modified',   modified],<br>    ];<br><br>    rows.forEach(([label, value]) =&gt; {<br>      const tr = document.createElement('tr');<br><br>      const td1 = document.createElement('td');<br>      td1.style.cssText = 'font-weight:600;padding:10px 12px;border-bottom:1px solid #edebe9;color:#605e5c;width:40%;';<br>      td1.textContent = label;<br><br>      const td2 = document.createElement('td');<br>      td2.style.cssText = 'padding:10px 12px;border-bottom:1px solid #edebe9;color:#323130;';<br>      td2.textContent = value;<br><br>      tr.appendChild(td1);<br>      tr.appendChild(td2);<br>      table.appendChild(tr);<br>    });<br><br>    const footer = document.createElement('div');<br>    footer.style.cssText = 'margin-top:24px;text-align:right;';<br><br>    const closeBtn = document.createElement('button');<br>    closeBtn.style.cssText = 'padding:8px 20px;background-color:#0078d4;color:#fff;border:none;border-radius:2px;cursor:pointer;font-size:14px;';<br>    closeBtn.textContent = 'Close';<br>    closeBtn.addEventListener('click', () =&gt; {<br>      this.close().catch(() =&gt; { /* handle error */ });<br>    });<br><br>    footer.appendChild(closeBtn);<br>    container.appendChild(heading);<br>    container.appendChild(table);<br>    container.appendChild(footer);<br><br>    this.domElement.appendChild(container);<br>  }<br><br>  public getConfig(): IDialogConfiguration {<br>    return { isBlocking: true };<br>  }<br><br>  protected onAfterClose(): void {<br>    super.onAfterClose();<br>    this.domElement.innerHTML = '';<br>  }<br>}</pre>



<h4 class="wp-block-heading" id="step-3--trigger-it-from-your-command-set">Step 3 — Trigger It from Your Command Set</h4>



<p>In <code>TaskDialogCommandSet.ts</code>, we import <code>TaskDialog</code> and wire it to <code>COMMAND_1</code>. The command stays <strong>hidden by default</strong> and only becomes visible when <strong>exactly one row is selected</strong> — handled inside <code>_onListViewStateChanged</code>.</p>



<p>When clicked, we read the selected row&#8217;s field values using <code>getValueByName()</code>. The <code>Author</code> field is a person field — SPFx returns it as an array of objects, so we extract the <code>title</code> property from the first element.</p>



<pre class="wp-block-preformatted">import { Log } from '@microsoft/sp-core-library';<br>import {<br>  BaseListViewCommandSet,<br>  type Command,<br>  type IListViewCommandSetExecuteEventParameters,<br>  type ListViewStateChangedEventArgs<br>} from '@microsoft/sp-listview-extensibility';<br>import TaskDialog from './TaskDialog';<br><br>export interface ITaskDialogCommandSetProperties {<br>  sampleTextOne: string;<br>}<br><br>const LOG_SOURCE: string = 'TaskDialogCommandSet';<br><br>export default class TaskDialogCommandSet extends BaseListViewCommandSet&lt;ITaskDialogCommandSetProperties&gt; {<br><br>  public onInit(): Promise&lt;void&gt; {<br>    Log.info(LOG_SOURCE, 'Initialized TaskDialogCommandSet');<br><br>    const viewDetailsCommand: Command = this.tryGetCommand('COMMAND_1');<br>    viewDetailsCommand.visible = false;<br><br>    this.context.listView.listViewStateChangedEvent.add(this, this._onListViewStateChanged);<br><br>    return Promise.resolve();<br>  }<br><br>  public onExecute(event: IListViewCommandSetExecuteEventParameters): void {<br>    switch (event.itemId) {<br>      case 'COMMAND_1': {<br>        const row = event.selectedRows[0];<br><br>        const id       = String(row.getValueByName('ID') || '');<br>        const title    = String(row.getValueByName('Title') || '');<br>        const created  = new Date(row.getValueByName('Created')  as string).toLocaleString();<br>        const modified = new Date(row.getValueByName('Modified') as string).toLocaleString();<br><br>        // Author is a person field — SPFx returns an array of objects with a title property<br>        const authorRaw = row.getValueByName('Author');<br>        let createdBy = '';<br>        if (Array.isArray(authorRaw) &amp;&amp; authorRaw.length &gt; 0) {<br>          const first = authorRaw[0];<br>          createdBy = typeof first === 'object' &amp;&amp; first !== null<br>            ? String((first as { title?: string; Title?: string }).title || (first as { title?: string; Title?: string }).Title || first)<br>            : String(first);<br>        }<br><br>        const dialog = new TaskDialog({ id, title, createdBy, created, modified });<br>        dialog.show().catch((err) =&gt; { console.error('TaskDialog error:', err); });<br>        break;<br>      }<br>      default:<br>        throw new Error('Unknown command');<br>    }<br>  }<br><br>  private _onListViewStateChanged = (_args: ListViewStateChangedEventArgs): void =&gt; {<br>    Log.info(LOG_SOURCE, 'List view state changed');<br><br>    const viewDetailsCommand: Command = this.tryGetCommand('COMMAND_1');<br>    if (viewDetailsCommand) {<br>      // Show only when exactly one row is selected<br>      viewDetailsCommand.visible = this.context.listView.selectedRows?.length === 1;<br>    }<br><br>    this.raiseOnChange();<br>  }<br>}</pre>



<h4 class="wp-block-heading">Manifest file (TaskDialogCommandSet.manifest.json)</h4>



<p>Only <code>COMMAND_1</code> is defined. The title is set to <strong>&#8220;View Details&#8221;</strong> so the toolbar button is meaningful to the user.</p>



<pre class="wp-block-code"><code>{
  "$schema": "https://developer.microsoft.com/json-schemas/spfx/command-set-extension-manifest.schema.json",
  "id": "0465f20d-8ea6-4117-9e72-4924124472e1",
  "alias": "TaskDialogCommandSet",
  "componentType": "Extension",
  "extensionType": "ListViewCommandSet",
  "version": "*",
  "manifestVersion": 2,
  "requiresCustomScript": false,
  "items": {
    "COMMAND_1": {
      "title": { "default": "View Details" },
      "iconImageUrl": "icons/request.png",
      "type": "command"
    }
  }
}</code></pre>



<h4 class="wp-block-heading" id="important-dont-forget-to-clean-up">Important: Always clean up the DOM</h4>



<p>Always clear <code>this.domElement.innerHTML</code> in <code>onAfterClose()</code>. If you skip this, the previous dialog content remains in the DOM, and you&#8217;ll see stale or duplicated data the next time the dialog is opened.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f6f4f1" data-has-transparency="false" style="--dominant-color: #f6f4f1;" loading="lazy" decoding="async" width="904" height="526" sizes="(max-width: 904px) 100vw, 904px" src="https://www.spguides.com/wp-content/uploads/2026/03/spfx-model-popup-on-list-view-command-set-extension.gif" alt="spfx model popup on list view command set extension" class="wp-image-133165 not-transparent" title="spfx model popup on list view command set"></figure></div>


<h3 class="wp-block-heading">Method 4: Native HTML&nbsp;&lt;dialog&gt;&nbsp;Element</h3>



<p>This one&#8217;s worth knowing about. Modern browsers have a built-in&nbsp;<code>&lt;dialog&gt;</code>&nbsp;HTML element that works perfectly fine in SPFx. No Fluent UI needed. No extra packages. Just plain HTML and <a href="https://www.spguides.com/typescript-check-if-string-is-number-or-float/">TypeScript</a>.</p>



<p>It&#8217;s a bit more of a &#8220;do it yourself&#8221; approach, but it&#8217;s lightweight, and it works well for non-React web parts.</p>



<pre class="wp-block-preformatted">export default class NativeDialogWebPart extends BaseClientSideWebPart&lt;{}&gt; {<br>  private _dialog: HTMLDialogElement;<br><br>  public render(): void {<br>    this.domElement.innerHTML = `<br>      &lt;div&gt;<br>        &lt;button id="openBtn"&gt;Open Dialog&lt;/button&gt;<br>        &lt;dialog id="myDialog"&gt;<br>          &lt;h2&gt;Hello from a native dialog!&lt;/h2&gt;<br>          &lt;p&gt;This is a lightweight modal using the HTML dialog element.&lt;/p&gt;<br>          &lt;button id="closeBtn"&gt;Close&lt;/button&gt;<br>        &lt;/dialog&gt;<br>      &lt;/div&gt;<br>    `;<br><br>    this._dialog = this.domElement.querySelector('#myDialog') as HTMLDialogElement;<br><br>    this.domElement.querySelector('#openBtn')!.addEventListener('click', () =&gt; {<br>      (this._dialog as any).showModal();<br>    });<br><br>    this.domElement.querySelector('#closeBtn')!.addEventListener('click', () =&gt; {<br>      this._dialog.close();<br>    });<br>  }<br>}<br></pre>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="e6e6e6" data-has-transparency="false" style="--dominant-color: #e6e6e6;" loading="lazy" decoding="async" width="524" height="298" sizes="(max-width: 524px) 100vw, 524px" src="https://www.spguides.com/wp-content/uploads/2026/03/native-dailog-html-in-spfx-web-part.avif" alt="native dailog html in spfx web part" class="wp-image-133055 not-transparent" title="native dailog html in spfx web part" srcset="https://www.spguides.com/wp-content/uploads/2026/03/native-dailog-html-in-spfx-web-part.avif 524w, https://www.spguides.com/wp-content/uploads/2026/03/native-dailog-html-in-spfx-web-part-300x171.avif 300w" /></figure></div>


<p>One heads-up: TypeScript&#8217;s type definitions in SPFx don&#8217;t always recognize the&nbsp;<code>showModal()</code>&nbsp;method on the&nbsp;<code>HTMLDialogElement</code>, so you may need to cast it to&nbsp;<code>any</code>&nbsp;like I did above. It&#8217;s a known limitation in the SPFx TypeScript setup, not a bug in your code.</p>



<h2 class="wp-block-heading" id="which-method-should-you-pick">Which Method Should You Pick?</h2>



<p>Here&#8217;s a simple way to think about it:</p>



<ul class="wp-block-list">
<li><strong>Building a web part?</strong>&nbsp;→ Use <a href="https://www.spguides.com/spfx-fluent-ui-react-dropdown/">Fluent UI</a>&nbsp;<code>&lt;Modal&gt;</code>&nbsp;(Method 1) for complex UIs, or&nbsp;<code>&lt;Dialog&gt;</code>&nbsp;(Method 2) for confirmations</li>



<li><strong>Building a ListView Command Set extension?</strong>&nbsp;→ Use&nbsp;<code>BaseDialog</code>&nbsp;(Method 3)</li>



<li><strong>Want something ultra-lightweight with no extra packages?</strong>&nbsp;→ Native HTML&nbsp;<code>&lt;dialog&gt;</code>&nbsp;(Method 4)</li>



<li><strong>Need clean state management code?</strong>&nbsp;→ Combine any React method with&nbsp;<code>useBoolean</code>&nbsp;from&nbsp;<code>@fluentui/react-hooks</code></li>
</ul>



<h2 class="wp-block-heading" id="common-issues-and-how-to-fix-them">Common Issues and How to Fix Them</h2>



<p>Here are some common issues that I faced and the fixes</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th><strong>Scenario</strong></th><th><strong>Best Approach</strong></th></tr></thead><tbody><tr><td>Modal is not blocking (user can click outside to close)</td><td>Set&nbsp;<code>isBlocking={true}</code>&nbsp;on your&nbsp;<code>&lt;Modal&gt;</code>&nbsp;or&nbsp;<code>&lt;Dialog&gt;</code>&nbsp;component, or set&nbsp;<code>isBlocking: true</code>&nbsp;in&nbsp;<code>modalProps</code>.</td></tr><tr><td>Dialog re-renders show stale data<br></td><td>This usually happens in&nbsp;<code>BaseDialog</code>&nbsp;if you forget to call&nbsp;<code>ReactDOM.unmountComponentAtNode</code>&nbsp;in&nbsp;<code>onAfterClose()</code>. Always clean up.</td></tr><tr><td>TypeScript error:&nbsp;<code>showModal is not a function</code><br></td><td>Cast your&nbsp;<code>HTMLDialogElement</code>&nbsp;to&nbsp;<code>any</code>&nbsp;before calling&nbsp;<code>showModal()</code>. It&#8217;s a TypeScript types issue, not a runtime issue.</td></tr><tr><td>Icons not rendering in Modal header<br></td><td>Make sure you&#8217;ve registered the Fluent UI icon set early in your component with&nbsp;<code>initializeIcons()</code>&nbsp;from&nbsp;<code>@fluentui/react/lib/Icons</code>.<br><br><code>import { initializeIcons } from '@fluentui/react/lib/Icons';<br>initializeIcons();</code></td></tr><tr><td>Modal appears behind other elements<br></td><td>This can happen if a parent element has a&nbsp;<code>z-index</code>&nbsp;or&nbsp;<code>overflow: hidden</code>&nbsp;set. SPFx&#8217;s modal should handle&nbsp;<code>z-index</code>&nbsp;automatically, but custom CSS on parent containers can interfere.</td></tr></tbody></table></figure>



<h2 class="wp-block-heading" id="testing-your-modal">Testing Your Modal Popup in SPFx</h2>



<p>Run your solution locally:</p>



<pre class="wp-block-preformatted">gulp serve</pre>



<p>For web parts, it opens your local workbench at&nbsp;<code>https://tenantname.sharepoint.com/sites/sitename/_layouts/15/workbench.aspx</code>. For extensions, update the&nbsp;<code>pageUrl</code>&nbsp;in&nbsp;<code>config/serve.json</code>&nbsp;to point to an actual SharePoint list URL in your tenant.</p>



<p>When prompted in the browser, click <strong>Load debug scripts</strong> to allow your local code to run on the SharePoint page.</p>



<h2 class="wp-block-heading">Download SPFx Modal Popup Solution</h2>



<p>Click the button below to download the SPFx solution packages for all examples covered in this post, plus access to 100+ additional solutions.</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download SPFx Solutions</a></div>
</div>



<h2 class="wp-block-heading" id="wrapping-up">Wrapping Up</h2>



<p>In this tutorial, I explained various methods to create modal popups in SharePoint Framework (SPFx). For most web part scenarios, the Fluent UI <code>&lt;Modal></code> or <code>&lt;Dialog></code> component is all you need. For extensions, <code>BaseDialog</code> it gives you the right structure.</p>



<p>The key thing to remember is that Fluent UI keeps things consistent with the SharePoint UI. Your modal will look and feel native to SharePoint rather than like something bolted on.</p>



<p>Also, you may like:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/spfx-fluent-ui-basic-list/">SharePoint Framework (SPFx) Fluent UI Basic List Example</a></li>



<li><a href="https://www.spguides.com/fluent-ui-documentcard-in-spfx-web-part/">Fluent UI DocumentCard in SPFx Web Part</a></li>



<li><a href="https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/">Build a Custom Slides Manager in SPFx Web Part Property Pane (Drag &amp; Drop, Reorder, Hide Slides)</a></li>



<li><a href="https://www.spguides.com/swatchcolorpicker/">SPFx SwatchColorPicker Office UI Fabric React Control example</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Bind SharePoint List Items to SPFx Fluent UI React Dropdown (Step-by-Step)</title>
		<link>https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Sun, 29 Mar 2026 13:09:00 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Bind SharePoint List Items to SPFx Fluent UI React Dropdown]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=65412</guid>

					<description><![CDATA[This tutorial explains how to bind SharePoint list items to a Fluent UI React dropdown in an SPFx React web part using PnP JS, so that any new items added to the list automatically appear in the dropdown. By the end, you will have an SPFx client-side web part where the dropdown is dynamically populated ... <a title="Bind SharePoint List Items to SPFx Fluent UI React Dropdown (Step-by-Step)" class="read-more" href="https://www.spguides.com/bind-sharepoint-list-items-to-spfx-fluent-ui-react-dropdown/" aria-label="Read more about Bind SharePoint List Items to SPFx Fluent UI React Dropdown (Step-by-Step)">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>This tutorial explains how to <strong>bind SharePoint list items to a Fluent UI React dropdown in an SPFx React web part using PnP JS</strong>, so that any new items added to the list automatically appear in the dropdown.</p>



<p>By the end, you will have an <a href="https://www.spguides.com/sharepoint-framework-client-web-part/" target="_blank" rel="noreferrer noopener">SPFx client-side web part</a> where the dropdown is dynamically populated from a SharePoint list and always stays in sync with the items in that list.</p>



<h2 class="wp-block-heading" id="prerequisites-and-scenario">Prerequisites and Scenario</h2>



<p>In this example, a <a href="https://www.spguides.com/sharepoint-list-view/" target="_blank" rel="noreferrer noopener">SharePoint list</a> named <strong>Product</strong> is used, with the columns: <strong>Title</strong> (Single line of text) and <strong>ProductName</strong> (Single line of text). Here is the SharePoint list in the screenshot below:</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="631" height="407" sizes="(max-width: 631px) 100vw, 631px" src="https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-webpart-dropdown.jpg" alt="bind SharePoint list item in the SPfx webpart dropdown" class="wp-image-65413" title="bind SharePoint list item in the SPfx webpart dropdown" srcset="https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-webpart-dropdown.jpg 631w, https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-webpart-dropdown-300x194.jpg 300w" /></figure></div>


<p>The goal is to fetch items from this Product list using PnP JS and bind them to a Fluent UI React dropdown in an SPFx web part. The output will come like the screenshot below:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="361" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items-in-spfx-webpart-dropdown-1024x361.jpg" alt="Bind SharePoint List Items to SPFx Fluent UI React Dropdown" class="wp-image-65419" title="How to populate the dropdown with list items in spfx webpart dropdown" srcset="https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items-in-spfx-webpart-dropdown-1024x361.jpg 1024w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items-in-spfx-webpart-dropdown-300x106.jpg 300w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items-in-spfx-webpart-dropdown-768x271.jpg 768w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items-in-spfx-webpart-dropdown.jpg 1177w" /></figure>



<p>Check out <a href="https://www.spguides.com/retrieve-sharepoint-list-items-using-sharepoint-framework/">Display SharePoint List Items in SPFx Web Part</a></p>



<h2 class="wp-block-heading" id="create-the-spfx-react-web-part">Create the SPFx React Web Part</h2>



<ol class="wp-block-list">
<li>Open&nbsp;<strong>Node.js command prompt</strong>&nbsp;and create a folder, then go inside it:</li>
</ol>



<pre class="wp-block-code"><code>mkdir ProductDropdown
cd ProductDropdown</code></pre>



<ol start="2" class="wp-block-list">
<li>Run the SharePoint Framework Yeoman generator:</li>
</ol>



<pre class="wp-block-code"><code>yo @microsoft/sharepoint</code></pre>



<ol start="3" class="wp-block-list">
<li>Answer the prompts (example values):
<ul class="wp-block-list">
<li>Solution name:&nbsp;<code>product-dropdown</code></li>



<li>Which type of client-side component to create?:&nbsp;<code>WebPart</code></li>



<li>Web part name:&nbsp;<code>ProductDropdown</code></li>



<li>Which template would you like to use?:&nbsp;<code>React</code></li>
</ul>
</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="217" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-dropdown-1024x217.jpg" alt="Bind SharePoint List Items to SPFx Fluent UI React Dropdown" class="wp-image-65414" title="bind SharePoint list item in the SPfx dropdown" srcset="https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-dropdown-1024x217.jpg 1024w, https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-dropdown-300x64.jpg 300w, https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-dropdown-768x163.jpg 768w, https://www.spguides.com/wp-content/uploads/2023/04/bind-SharePoint-list-item-in-the-SPfx-dropdown.jpg 1034w" /></figure></div>


<p>The generator will install all dependencies and scaffold the SPFx project.</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="787" height="272" sizes="(max-width: 787px) 100vw, 787px" src="https://www.spguides.com/wp-content/uploads/2023/04/bind-list-items-in-SharePoint-in-the-SPfx-dropdown.jpg" alt="bind list items in SharePoint in the SPfx dropdown" class="wp-image-65415" title="bind list items in SharePoint in the SPfx dropdown" srcset="https://www.spguides.com/wp-content/uploads/2023/04/bind-list-items-in-SharePoint-in-the-SPfx-dropdown.jpg 787w, https://www.spguides.com/wp-content/uploads/2023/04/bind-list-items-in-SharePoint-in-the-SPfx-dropdown-300x104.jpg 300w, https://www.spguides.com/wp-content/uploads/2023/04/bind-list-items-in-SharePoint-in-the-SPfx-dropdown-768x265.jpg 768w" /></figure></div>


<h2 class="wp-block-heading" id="install-fluent-ui-and-pnp-js">Install Fluent UI and PnP JS</h2>



<p>After project creation, install the required libraries.</p>



<ul class="wp-block-list">
<li>Fluent UI React:</li>
</ul>



<pre class="wp-block-code"><code>npm install @fluentui/react</code></pre>



<ul class="wp-block-list">
<li>PnP JS (sp-pnp-js):</li>
</ul>



<pre class="wp-block-code"><code>npm install sp-pnp-js</code></pre>



<p>Then open the project in VS Code:</p>



<pre class="wp-block-code"><code>Code .</code></pre>



<p>You can see the project structure on the left side of the code editor(VS Code editor).</p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="427" height="804" sizes="(max-width: 427px) 100vw, 427px" src="https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items.jpg" alt="How to populate the dropdown with list items" class="wp-image-65418" title="How to populate the dropdown with list items" srcset="https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items.jpg 427w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-populate-the-dropdown-with-list-items-159x300.jpg 159w" /></figure></div>


<p>Check out <a href="https://www.spguides.com/build-a-sharepoint-folder-tree-view-using-spfx/">Build a SharePoint Folder Tree View Using SharePoint Framework (SPFx)</a></p>



<h2 class="wp-block-heading" id="create-interfaces-and-classes-for-list-items">Create Interfaces and Classes for List Items</h2>



<p>Navigate to&nbsp;<code>src\webparts\productDropdown\components</code>.</p>



<h3 class="wp-block-heading" id="1-create-the-interface-file-iproductsts">1. Create the interface file&nbsp;IProducts.ts</h3>



<p>First, create an interface like below. This interface defines the shape of each SharePoint list item returned by PnP JS, mapping the&nbsp;<code>Id</code>,&nbsp;<code>Title</code>, and&nbsp;<code>ProductName</code>&nbsp;fields.</p>



<pre class="wp-block-preformatted">export interface ISPListProductItem{<br>    Id:any;<br>    Title:string;<br>    ProductName:string;<br>  }</pre>



<h3 class="wp-block-heading" id="2-create-the-class-file-classproductts">2. Create the class file&nbsp;ClassProduct.ts</h3>



<p>This class takes a raw SharePoint list item and exposes only the properties we need —&nbsp;<code>Id</code>&nbsp;and&nbsp;<code>ProductName</code>&nbsp;— to keep the dropdown logic clean and simple.</p>



<pre class="wp-block-preformatted">import { ISPListProductItem } from "./IProducts";<br><br>export class  ClassProduct{<br>    public ProductName:string;<br>    public Id:any<br>    constructor(item: ISPListProductItem) {<br>      this.ProductName = item.ProductName;<br>      this.Id=item.Id<br><br>  }<br>}</pre>



<p>This class wraps each SharePoint list item and exposes&nbsp;<strong>ProductName</strong>&nbsp;and&nbsp;<strong>Id</strong>&nbsp;that will be used in the dropdown options.</p>



<h2 class="wp-block-heading" id="implement-the-fluent-ui-dropdown-in-productdropdow">Implement the Fluent UI Dropdown in ProductDropdown.tsx</h2>



<p>Open&nbsp;<code>src\webparts\productDropdown\components\ProductDropdown.tsx</code>.</p>



<h3 class="wp-block-heading" id="1-import-required-modules">1. Import required modules</h3>



<p>Import PnP JS to fetch SharePoint list data, the&nbsp;<code>ClassProduct</code>&nbsp;class we created, and the Fluent UI&nbsp;<code>Dropdown</code>&nbsp;component along with its types.</p>



<pre class="wp-block-preformatted">import * as React from 'react';<br>import styles from './ProductDropdown.module.scss';<br>import { IProductDropdownProps } from './IProductDropdownProps';<br>import pnp from 'sp-pnp-js'<br>import { ClassProduct } from './ClassProduct';<br><em>// import { ISPListProductItem } from './IProducts';</em><br>import {Dropdown, IDropdownOption} from '@fluentui/react';</pre>



<h3 class="wp-block-heading" id="2-define-the-component-state">2. Define the component state</h3>



<p>The state holds the list of dropdown options fetched from SharePoint and tracks the currently selected item.</p>



<pre class="wp-block-preformatted">export interface IProductDropdownState {<br>  selectedProduct?: IDropdownOption;<br>  items: IDropdownOption[];<br>}</pre>



<h3 class="wp-block-heading" id="3-create-the-react-component-with-constructor">3. Create the React component with constructor</h3>



<p>The constructor initializes the component state with an empty&nbsp;<code>items</code>&nbsp;array and no selected product, which will be populated once the component mounts.</p>



<pre class="wp-block-preformatted">export default class ProductDropdown extends React.Component&lt;IProductDropdownProps, IProductDropdownState&gt; {<br>  constructor(props: IProductDropdownProps) {<br>    super(props);<br>    this.state = {<br>      selectedProduct: undefined,<br>      items: []<br>    };<br>  }</pre>



<h3 class="wp-block-heading" id="4-render-the-fluent-ui-dropdown-and-load-data">4. Render the Fluent UI dropdown and load data</h3>



<p>The&nbsp;<code>render</code>&nbsp;method displays the Fluent UI dropdown,&nbsp;<code>componentDidMount</code>&nbsp;triggers the SharePoint data fetch, and&nbsp;<code>_getListProductData</code>&nbsp;maps list items into dropdown options and updates the state.</p>



<p>Use the following full code in&nbsp;<code>ProductDropdown.tsx</code>:</p>



<pre class="wp-block-preformatted">export default class ProductDropdown extends React.Component&lt;IProductDropdownProps, IProductDropdownState&gt; {<br>  constructor(props: IProductDropdownProps) {<br>    super(props);<br>    this.state = {<br>      selectedProduct: undefined,<br>      items: []<br>    };<br>  }<br><br>  public render(): React.ReactElement&lt;IProductDropdownProps&gt; {<br>    return (<br>      &lt;section className={`${styles.productDropdown}`}&gt;<br>        &lt;Dropdown<br>          label="Select a product"<br>          options={this.state.items}<br>          selectedKey={this.state.selectedProduct?.key}<br>          onChange={this.onDropdownChange}<br>        /&gt;<br>      &lt;/section&gt;<br>    );<br>  }<br><br>  public componentDidMount(){<br>    this._getListProductData();<br>  }<br><br>  private _getListProductData() : void {<br>    pnp.sp.web.lists.getByTitle(`Product`).items.get().then((response: any) =&gt; {<br>      let productCollection = response.map((item: any) =&gt; new ClassProduct(item));<br>      let dropdownOptions = productCollection.map((product: ClassProduct) =&gt; {<br>        return {<br>          key: product.Id,<br>          text: product.ProductName<br>        };<br>      });<br>      this.setState({ items: dropdownOptions });<br>    });<br>  }<br><br>  private onDropdownChange = (event: React.FormEvent&lt;HTMLDivElement&gt;, item: IDropdownOption): void =&gt; {<br>    this.setState({ selectedProduct: item });<br>  }<br>}</pre>



<p>This code loads items from the&nbsp;<strong>Product</strong>&nbsp;list in&nbsp;<code>componentDidMount</code>, maps them to dropdown options, and binds them to the Fluent UI dropdown.</p>



<p>Check out <a href="https://www.spguides.com/sharepoint-framework-interview-questions-and-answers/">SharePoint Framework (SPFx) Interview Questions and Answers</a></p>



<h2 class="wp-block-heading" id="update-the-web-part-entry-file">Update the Web Part Entry File</h2>



<p>Open&nbsp;<code>src\webparts\productDropdown\ProductDropdownWebPart.ts</code>&nbsp;and use this code:</p>



<pre class="wp-block-preformatted">import * as React from 'react';<br>import * as ReactDom from 'react-dom';<br>import { Version } from '@microsoft/sp-core-library';<br>import {<br>  IPropertyPaneConfiguration,<br>  PropertyPaneTextField<br>} from '@microsoft/sp-property-pane';<br>import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';<br><br>import * as strings from 'ProductDropdownWebPartStrings';<br>import ProductDropdown from './components/ProductDropdown';<br>import { IProductDropdownProps } from './components/IProductDropdownProps';<br><br>export interface IProductDropdownWebPartProps {<br>  description: string;<br>}<br><br>export default class ProductDropdownWebPart extends BaseClientSideWebPart&lt;IProductDropdownWebPartProps&gt; {<br><br>  public async render(): Promise &lt;void&gt; {<br>    const element: React.ReactElement&lt;IProductDropdownProps&gt; = React.createElement(<br>      ProductDropdown,<br>    );<br><br>    ReactDom.render(element, this.domElement);<br>  }<br><br>  protected onDispose(): void {<br>    ReactDom.unmountComponentAtNode(this.domElement);<br>  }<br><br>  protected get dataVersion(): Version {<br>    return Version.parse('1.0');<br>  }<br><br>  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {<br>    return {<br>      pages: [<br>        {<br>          header: {<br>            description: strings.PropertyPaneDescription<br>          },<br>          groups: [<br>            {<br>              groupName: strings.BasicGroupName,<br>              groupFields: [<br>                PropertyPaneTextField('description', {<br>                  label: strings.DescriptionFieldLabel<br>                })<br>              ]<br>            }<br>          ]<br>        }<br>      ]<br>    };<br>  }<br>}</pre>



<p>This wires the React component into the SPFx web part and keeps a simple property pane.</p>



<h2 class="wp-block-heading" id="configure-serve-url-and-test-the-web-part">Configure Gulp Serve URL and Test the Web Part</h2>



<ol class="wp-block-list">
<li>Open&nbsp;<code>config\serve.json</code>&nbsp;and set your SharePoint site URL in the&nbsp;<code>pageUrl</code>&nbsp;property so the local workbench loads against your site; like the below screenshot:</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="199" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2023/04/populate-the-dropdown-with-list-items-in-spfx-webpart-1024x199.jpg" alt="populate the dropdown with list items in spfx webpart" class="wp-image-65429" title="populate the dropdown with list items in spfx webpart" srcset="https://www.spguides.com/wp-content/uploads/2023/04/populate-the-dropdown-with-list-items-in-spfx-webpart-1024x199.jpg 1024w, https://www.spguides.com/wp-content/uploads/2023/04/populate-the-dropdown-with-list-items-in-spfx-webpart-300x58.jpg 300w, https://www.spguides.com/wp-content/uploads/2023/04/populate-the-dropdown-with-list-items-in-spfx-webpart-768x149.jpg 768w, https://www.spguides.com/wp-content/uploads/2023/04/populate-the-dropdown-with-list-items-in-spfx-webpart.jpg 1240w" /></figure></div>


<ol start="2" class="wp-block-list">
<li>Start the local server: <code>gulp serve</code></li>



<li>In the modern workbench, add the&nbsp;<strong>ProductDropdown</strong>&nbsp;web part to the page.</li>



<li>Click the dropdown to see all&nbsp;<strong>ProductName</strong>&nbsp;values from the Product list; any new items you add to the list will automatically appear in the dropdown. </li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="234" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2023/04/How-to-bind-SharePoint-list-items-in-the-Spfx-webpart-dropdown-1024x234.jpg" alt="How to bind SharePoint list items in the Spfx webpart dropdown" class="wp-image-65436" title="How to bind SharePoint list items in the Spfx webpart dropdown" srcset="https://www.spguides.com/wp-content/uploads/2023/04/How-to-bind-SharePoint-list-items-in-the-Spfx-webpart-dropdown-1024x234.jpg 1024w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-bind-SharePoint-list-items-in-the-Spfx-webpart-dropdown-300x69.jpg 300w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-bind-SharePoint-list-items-in-the-Spfx-webpart-dropdown-768x176.jpg 768w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-bind-SharePoint-list-items-in-the-Spfx-webpart-dropdown-1536x351.jpg 1536w, https://www.spguides.com/wp-content/uploads/2023/04/How-to-bind-SharePoint-list-items-in-the-Spfx-webpart-dropdown-2048x468.jpg 2048w" /></figure></div>


<h2 class="wp-block-heading" id="download-the-complete-spfx-solution">Download the Complete SPFx Solution</h2>



<p>You can download the full solution as a zip file and run it locally.</p>



<ul class="wp-block-list">
<li>Download:<br><code>https://www.spguides.com/wp-content/uploads/2023/04/bind-the-SharePoint-list-item-in-the-Spfx-webpart-dropdown.zip</code></li>
</ul>



<p>After unzipping, install dependencies:</p>



<pre class="wp-block-preformatted">npm i</pre>



<h2 class="wp-block-heading" id="wrap-up">Wrap-up</h2>



<p>This tutorial walked through creating an SPFx React web part that reads items from a SharePoint list using PnP JS and binds them to a Fluent UI dropdown. You now have a reusable pattern for populating dropdowns from SharePoint lists, and any new items in the list will automatically appear to users in the web part.</p>



<p>You may also like the following tutorials:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/">Build a Custom Slides Manager in SPFx Web Part Property Pane (Drag &amp; Drop, Reorder, Hide Slides)</a></li>



<li><a href="https://www.spguides.com/spfx-swatchcolorpicker-fluent-ui-react-control/">SPFX SwatchColorPicker Fluent UI React Control</a></li>



<li><a href="https://www.spguides.com/fluent-ui-documentcard-in-spfx-web-part/">Fluent UI DocumentCard in SPFx Web Part</a></li>



<li><a href="https://www.spguides.com/spfx-fluent-ui-basic-list/">SharePoint Framework (SPFx) Fluent UI Basic List Example</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Customize SharePoint List Command Bar Download Button Using SPFx Extension</title>
		<link>https://www.spguides.com/customize-sharepoint-list-command-bar-download-button-using-spfx-extension/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Sat, 28 Mar 2026 13:09:00 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Customize SharePoint List Command Bar Download Button Using SPFx Extension]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=121564</guid>

					<description><![CDATA[A few weeks before, I was working with a client on the SharePoint Online document management system. In this setup, guest users can also read, edit, and download files from the document library. Here, the client was required to track guest users who download any file from the document library by sending an email to ... <a title="Customize SharePoint List Command Bar Download Button Using SPFx Extension" class="read-more" href="https://www.spguides.com/customize-sharepoint-list-command-bar-download-button-using-spfx-extension/" aria-label="Read more about Customize SharePoint List Command Bar Download Button Using SPFx Extension">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>A few weeks before, I was working with a client on the SharePoint Online document management system. In this setup, guest users can also read, edit, and download files from the <a href="https://www.spguides.com/give-sharepoint-library-upload-access-external-users/">document library.</a></p>



<p>Here, the client was required to track guest users who download any file from the document library by sending an email to the authorised person notifying them that someone had downloaded the file. </p>



<p>But in the SharePoint library command bar, the &#8220;Download&#8221; option doesn&#8217;t automatically include the option to send emails and notifications. So, after researching, we found a way to customise the default &#8220;Download&#8221; button using the <a href="https://www.spguides.com/restrict-spfx-list-view-command-set-specific-list/">SPFx list view command set extension</a>.</p>



<p>In this article, I will explain how to <strong>customize SharePoint list command bar download button to send an email using SharePoint Framework</strong> (SPFx).</p>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://academy.spguides.com/Download-SPFx-Solutions" target="_blank" rel="noopener">Download Complete Solution</a></div>
</div>



<h2 class="wp-block-heading">Customize SharePoint List Download Button to Send Emails Using SPFx Extension</h2>



<p>In the<a href="https://www.spguides.com/spfx-preconfiguredentries/"> SharePoint framework</a>, with the list view command set extension, we can customize the SharePoint list command bars and context menu buttons by adding custom buttons based on our requirements.</p>



<p>But here, we need to modify the existing [Download] button functionality, such as sending an email to an authorised person to notify them that the file has been downloaded by this person.</p>



<h3 class="wp-block-heading">Get Unique Identifier for SharePoint List Command Bar Buttons</h3>



<p>To do this, we first need to find the unique identifier of that &#8220;Download&#8221; button. Follow the steps below to identify the unique identifier.</p>



<ol class="wp-block-list">
<li>Open the <a href="https://www.spguides.com/set-column-default-value-in-sharepoint-library/">SharePoint document library </a>-&gt; Select one or two files, and then in the command bar, or in the context menu, you&#8217;ll see the &#8220;Download&#8221; button.</li>



<li>Then, click on the [<strong>Ctrl + Shift + I</strong>] keys at the same time on the keyboard. Otherwise, right-click and a pop-up will come; click on the <strong>inspect </strong>option.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="663" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2025/10/spfx-extension-to-customize-sharepoint-list-command-bar-1024x663.png" alt="spfx extension to customize sharepoint list command bar" class="wp-image-121565" title="spfx extension to customize sharepoint list command bar" srcset="https://www.spguides.com/wp-content/uploads/2025/10/spfx-extension-to-customize-sharepoint-list-command-bar-1024x663.png 1024w, https://www.spguides.com/wp-content/uploads/2025/10/spfx-extension-to-customize-sharepoint-list-command-bar-300x194.png 300w, https://www.spguides.com/wp-content/uploads/2025/10/spfx-extension-to-customize-sharepoint-list-command-bar-768x497.png 768w, https://www.spguides.com/wp-content/uploads/2025/10/spfx-extension-to-customize-sharepoint-list-command-bar.png 1112w" /></figure></div>


<ol start="2" class="wp-block-list">
<li>Then, it will open the inspection page and click the 1st icon in the top toolbar on the right side pane. Then, keep your cursor on the &#8220;Download&#8221; button and click on it. You will find the button code on the right side. Now you can see the &#8220;<strong>downloadCommand</strong>&#8221; as the ID for that button, and copy it.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="469" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2025/10/ListView-Command-Set-extension-1024x469.png" alt="ListView Command Set extension" class="wp-image-121567" title="ListView Command Set extension" srcset="https://www.spguides.com/wp-content/uploads/2025/10/ListView-Command-Set-extension-1024x469.png 1024w, https://www.spguides.com/wp-content/uploads/2025/10/ListView-Command-Set-extension-300x137.png 300w, https://www.spguides.com/wp-content/uploads/2025/10/ListView-Command-Set-extension-768x351.png 768w, https://www.spguides.com/wp-content/uploads/2025/10/ListView-Command-Set-extension-1536x703.png 1536w, https://www.spguides.com/wp-content/uploads/2025/10/ListView-Command-Set-extension.png 1840w" /></figure></div>


<p>Now, we need to implement the functionality to send emails when we click this button. Let&#8217;s see how to do that in the section below!</p>



<h3 class="wp-block-heading">Create SPFx List View Command Set Extension</h3>



<p>Follow the steps below to create a <a href="https://www.spguides.com/spfx-listview-command-set-extension/">SharePoint framework list view command set extension</a>. This extension is using the Microsoft Graph to send emails. With MSGraph, we can send emails to both internal and external users.</p>



<ol class="wp-block-list">
<li>Open the command prompt and run the commands below to create a solution.</li>
</ol>



<pre class="wp-block-code"><code>md SPFxListViewExtDownload

cd SPFxListViewExtDownload</code></pre>



<ol start="2" class="wp-block-list">
<li>Then run the command below to scaffold our spfx solution.</li>
</ol>



<pre class="wp-block-code"><code>yo @microsoft/sharepoint</code></pre>



<ol start="3" class="wp-block-list">
<li>This will prompt you with the following questions. Answer them as I gave below.</li>
</ol>



<ul class="wp-block-list">
<li>What is your solution name?<strong> SPFxListViewExtDownload</strong></li>



<li>Which type of client-side component to create? <strong>Extension</strong></li>



<li>Which type of client-side extension to create?<strong> ListView Command Set</strong></li>



<li>Add new Command Set to solution sp-fx-list-view-ext-download.</li>



<li>What is your Command Set name? <strong>custDownload</strong></li>
</ul>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="731" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2025/10/customize-the-sharepoint-list-command-bar-with-spfx-1024x731.png" alt="customize the sharepoint list command bar with spfx" class="wp-image-121573" title="customize the sharepoint list command bar with spfx" srcset="https://www.spguides.com/wp-content/uploads/2025/10/customize-the-sharepoint-list-command-bar-with-spfx-1024x731.png 1024w, https://www.spguides.com/wp-content/uploads/2025/10/customize-the-sharepoint-list-command-bar-with-spfx-300x214.png 300w, https://www.spguides.com/wp-content/uploads/2025/10/customize-the-sharepoint-list-command-bar-with-spfx-768x549.png 768w, https://www.spguides.com/wp-content/uploads/2025/10/customize-the-sharepoint-list-command-bar-with-spfx.png 1064w" /></figure></div>


<ol start="4" class="wp-block-list">
<li>Once the solution is created successfully, open the &#8220;package-solution.json&#8221; located in the<strong> config</strong> folder. Then add the code below as shown.</li>
</ol>



<pre class="wp-block-code"><code>"webApiPermissionRequests": &#91;
      {
        "resource": "Microsoft Graph",
        "scope": "Mail.Send"
      }
    ]</code></pre>



<p>In this code, we are adding <a href="https://www.spguides.com/spfx-send-email-using-pnpjs/">permission to send emails</a>, so we need to get approval for this permission from the admin team in the &#8220;SharePoint Admin Centre&#8221; under &#8220;API access&#8221;. Otherwise, the email won&#8217;t be sent to the user mentioned in the code.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="640" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2025/10/add-new-functionality-to-sharepoint-library-command-bar-buttons-using-SPFx-1024x640.png" alt="add new functionality to sharepoint library command bar buttons using SPFx" class="wp-image-121575" title="add new functionality to sharepoint library command bar buttons using SPFx" srcset="https://www.spguides.com/wp-content/uploads/2025/10/add-new-functionality-to-sharepoint-library-command-bar-buttons-using-SPFx-1024x640.png 1024w, https://www.spguides.com/wp-content/uploads/2025/10/add-new-functionality-to-sharepoint-library-command-bar-buttons-using-SPFx-300x188.png 300w, https://www.spguides.com/wp-content/uploads/2025/10/add-new-functionality-to-sharepoint-library-command-bar-buttons-using-SPFx-768x480.png 768w, https://www.spguides.com/wp-content/uploads/2025/10/add-new-functionality-to-sharepoint-library-command-bar-buttons-using-SPFx.png 1392w" /></figure></div>


<ol start="5" class="wp-block-list">
<li>Then<span style="box-sizing: border-box; margin: 0px; padding: 0px;">&nbsp;open the &#8220;CustDownloadCommandSet.ts&#8221; file in the&nbsp;<strong>src</strong>&nbsp;folder and replace</span> the default code with the code below.</li>
</ol>



<pre class="wp-block-code"><code>import { Log } from '@microsoft/sp-core-library';
import {
  BaseListViewCommandSet,
  type Command,
  type IListViewCommandSetExecuteEventParameters,
  type ListViewStateChangedEventArgs
} from '@microsoft/sp-listview-extensibility';
import { MSGraphClientV3 } from '@microsoft/sp-http';

export interface ICustDownloadCommandSetProperties {
  // This is an example; replace with your own properties
  sampleTextOne: string;
  sampleTextTwo: string;
}

const LOG_SOURCE: string = 'CustDownloadCommandSet';
const EMAIL_RECIPIENT: string = 'Provie your email address'; 

export default class CustDownloadCommandSet extends BaseListViewCommandSet&lt;ICustDownloadCommandSetProperties&gt; {

  public onInit(): Promise&lt;void&gt; {
    Log.info(LOG_SOURCE, 'Initialized CustDownloadCommandSet');

    // initial state of the command's visibility
    const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
    compareOneCommand.visible = false;
    this.context.listView.listViewStateChangedEvent.add(this, this._onListViewStateChanged);
   
    this._attachDownloadClickHandler();
    return Promise.resolve();
  }

  public onExecute(event: IListViewCommandSetExecuteEventParameters): void {
    switch (event.itemId) {
      case 'COMMAND_1':
        break;
      case 'COMMAND_2':
        break;
      default:
        throw new Error('Unknown command');
    }
  }

  private _onListViewStateChanged = (args: ListViewStateChangedEventArgs): void =&gt; {
    Log.info(LOG_SOURCE, 'List view state changed');

    const compareOneCommand: Command = this.tryGetCommand('COMMAND_1');
    const comparetwoCommand: Command = this.tryGetCommand('COMMAND_2');
    if (compareOneCommand) {
      // This command should be hidden unless exactly one row is selected.
      compareOneCommand.visible = this.context.listView.selectedRows?.length === 1;
    }
    if (comparetwoCommand) {
      comparetwoCommand.visible = false;
    }
    // TODO: Add your logic here

    // You should call this.raiseOnChage() to update the command bar
    this.raiseOnChange();
  }

  //Attaches a click listener to the existing default "Download"button.

private _attachDownloadClickHandler(): void {
  const attachHandler = () =&gt; {
    const downloadButton = document.querySelector('button&#91;data-automationid="downloadCommand"]') as HTMLElement;
    if (downloadButton &amp;&amp; !downloadButton.getAttribute('listener-attached')) {
      downloadButton.setAttribute('listener-attached', 'true');
      downloadButton.addEventListener('click', this._onDownloadClicked.bind(this));
      console.log('%cDownload button listener attached (current instance)', 'color: green');
    }
  };

  // Initial attempt
  attachHandler();

  // Watch for DOM changes in the toolbar or context menu area
  const observer = new MutationObserver(() =&gt; {
    attachHandler(); // reattach when DOM changes
  });

  observer.observe(document.body, {
    childList: true,
    subtree: true
  });

  console.log('%cWatching for Download button re-render...', 'color: orange');
}
//Executes when the built-in Download button is clicked.
private _onDownloadClicked(): void {
    try {
      const selectedRows = this.context.listView.selectedRows;
      if (selectedRows &amp;&amp; selectedRows.length &gt; 0) {
        const fileNames = selectedRows.map((r: any) =&gt; r.getValueByName('FileLeafRef'));
        const user = this.context.pageContext.user.displayName;

        alert(`${user} downloaded: ${fileNames.join(', ')}`);

        this._sendDownloadEmail(fileNames, user);
      }
    } catch (err) {
      console.error("Error handling Download click:", err);
    }
  }
    //Sends an email notification via MS Graph when files are downloaded.    
private _sendDownloadEmail(fileNames: string&#91;], user: string): void {
  console.log('Preparing to send email through MSGraphClientV3...');
  this.context.msGraphClientFactory
    .getClient('3')
    .then((client: MSGraphClientV3) =&gt; {
      const siteUrl = this.context.pageContext.web.absoluteUrl;
      const siteName = this.context.pageContext.web.title;
      const emailBody = `
        &lt;div style="font-family:Segoe UI, Arial, sans-serif; font-size:14px; color:#333;"&gt;
          &lt;p&gt;Hi &lt;strong&gt;Bijay&lt;/strong&gt;,&lt;/p&gt;
          
          &lt;p&gt;This is to inform you that &lt;strong&gt;${user}&lt;/strong&gt; has downloaded the following file(s) from the SharePoint site 
          &lt;a href="${siteUrl}" style="color:#0078D4; text-decoration:none;"&gt;${siteName}&lt;/a&gt;:&lt;/p&gt;

          &lt;ul style="margin-top:8px; margin-bottom:8px;"&gt;
            ${fileNames.map(f =&gt; `&lt;li&gt;${f}&lt;/li&gt;`).join('')}
          &lt;/ul&gt;

          &lt;p style="margin-top:16px;"&gt;Best regards,&lt;br&gt;
          &lt;strong&gt;SharePoint System&lt;/strong&gt;&lt;/p&gt;
        &lt;/div&gt;
      `;

      const email = {
        message: {
          subject: `File Download Notification - ${user}`,
          body: {
            contentType: 'HTML',
            content: emailBody
          },
          toRecipients: &#91;
            {
              emailAddress: { address: EMAIL_RECIPIENT }
            }
          ]
        },
        saveToSentItems: false
      };

      client.api('/me/sendMail').post(email)
        .then(() =&gt; console.log('Email sent successfully to', EMAIL_RECIPIENT))
        .catch(err =&gt; console.error('Error sending email:', err));
    })
    .catch(err =&gt; console.error('Error initializing MSGraphClientV3:', err));
}
}</code></pre>



<ul class="wp-block-list">
<li>At the start, we imported the<strong> MSGraphClientV3</strong> from the @microsoft/sp-http to send emails.</li>



<li><strong>const EMAIL_RECIPIENT: string = &#8216;Provie your email address&#8217;</strong> = This variable holds the user email adrress.</li>



<li><strong>this._attachDownloadClickHandler()</strong>; = We called the function in the OnInit method, which attaches the handler to the default &#8220;Download&#8221; button.</li>



<li><strong>onExecute()</strong> = This is the default code that runs when a custom button is clicked, but since we are not adding any custom buttons, no action will be performed.</li>



<li><strong>_onListViewStateChanged()</strong> = The default function that runs when changes occur in the SharePoint list or document library. Here, we are adding the visibility logic for the custom buttons. Since we are not using the custom buttons, I set both to a false value, so they won&#8217;t be visible when something happens in the list view.</li>



<li> <strong>_attachDownloadClickHandler()</strong> = This function will perform the following actions:
<ul class="wp-block-list">
<li>Detect the default “Download” button rendered by SharePoint using the code below:</li>



<li>const downloadButton = document.querySelector(<strong>&#8216;button[data-automationid=&#8221;downloadCommand&#8221;]</strong>&#8216;) as HTMLElement;</li>



<li>Attach a custom event handler to it without modifying the page directly.</li>



<li>And keep reattaching it whenever SharePoint re-renders the toolbar.</li>
</ul>
</li>



<li><strong>_onDownloadClicked() </strong>= This method is a custom event handler that runs when the default SharePoint &#8220;Download&#8221; button is clicked, the one attached using the previous function.
<ul class="wp-block-list">
<li>It will detect which files the user is downloading and then run custom logic, such as showing an alert and sending an email.</li>
</ul>
</li>



<li><strong> _sendDownloadEmail(fileNames: string[], user: string) </strong>= In this function we called the _onDownloadClicked() after detecing  a file downloaded.
<ul class="wp-block-list">
<li>This function takes the downloaded file names and the user name who downloaded them as input and does not return anything.</li>



<li>this.context.msGraphClientFactory.getClient(&#8216;3&#8217;).then((client: MSGraphClientV3) =&gt; {..} allows us to connect to <a href="https://www.spguides.com/spfx-send-email-using-pnpjs/">Microsoft Graph</a> to access APIs such as Outlook, Users, Groups, and more.</li>



<li>We are using the vGraph client version 3.</li>



<li>Then we fetched the <strong>siteUrl</strong> and<strong> siteName</strong> from the context and prepared the email body.</li>



<li>Sent email using the MSGraph<strong> &#8216;/me/sendMail&#8217;</strong> API.</li>
</ul>
</li>
</ul>



<ol start="6" class="wp-block-list">
<li>To test this extension locally, open the<strong> serve.json </strong>file located in the <strong>config</strong> folder. There, you can see the &#8220;pageUrl&#8221; as given below.</li>
</ol>



<pre class="wp-block-code"><code>https:&#47;&#47;{tenantDomain}/SitePages/myPage.aspx</code></pre>



<p>Update that with your SharePoint library URL, like below.</p>



<pre class="wp-block-code"><code>"https://szg52.sharepoint.com/sites/SPFXDevelopment/HRDocuments/Forms/AllItems.aspx"</code></pre>



<ol start="7" class="wp-block-list">
<li>Once it&#8217;s over, run the below command either in the command prompt or in the Terminal pane.</li>
</ol>



<pre class="wp-block-code"><code>gulp serve</code></pre>



<ol start="8" class="wp-block-list">
<li>Now, as shown below, click Load debug scripts, select the files in the library, and click the &#8220;Download&#8221; button. You&#8217;ll see an alert, and then you&#8217;ll receive an email.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img loading="lazy" decoding="async" width="1016" height="712" sizes="(max-width: 1016px) 100vw, 1016px" src="https://www.spguides.com/wp-content/uploads/2025/10/sharepoint-list-view-command-set-extension-to-modify-existing-sharepoint-command-bar-buttons.gif" alt="sharepoint list view command set extension to modify existing sharepoint command bar buttons" class="wp-image-121592" title="sharepoint list view command set extension to modify existing sharepoint command bar buttons"></figure></div>


<p>That&#8217;s it, this way we can easily customise the existing command buttons in the SharePoint list or library using the SPFx list view command set extension.</p>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://academy.spguides.com/Download-SPFx-Solutions" target="_blank" rel="noopener">Download Complete Solution</a></div>
</div>



<p>I hope you found this article helpful!, Here, I have explained how to access the default buttons in a SharePoint list or library command bar, context menu, and customize them using the SharePoint framework list view command set extension.</p>



<p>I will recomended, download this solution and try it once. In the comments, let me know if you run into any issues and share your feedback on this tutorial.</p>



<p>You may also like the following SPFx tutorials:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/sharepoint-framework-user-profile-web-part/">SharePoint Framework User Profile Web Part [Using MS Graph API]</a></li>



<li><a href="https://www.spguides.com/get-current-sharepoint-site-information-in-spfx-using-ms-graph-api/">Get Current SharePoint Site Information in SPFx using MS Graph API</a></li>



<li><a href="https://www.spguides.com/create-list-spfx/">Create a SharePoint List using SharePoint Framework [Including Adding Columns]</a></li>



<li><a href="https://www.spguides.com/create-folders-and-subfolders-in-sharepoint-document-library-using-spfx/">Create Folders and Subfolders in SharePoint document library using SPFx</a></li>



<li><a href="https://www.spguides.com/spfx-application-customizer/">SPFx Application Customizer Example</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Upload File to SharePoint Document Library With Metadata in SPFx</title>
		<link>https://www.spguides.com/spfx-upload-file-to-sharepoint-document-library-with-metadata/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Fri, 27 Mar 2026 18:05:03 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[SPFx Upload File to SharePoint Document Library With Metadata]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=66696</guid>

					<description><![CDATA[A few weeks ago, I created an SPFx web part for a USA Citizenship form that requires users to upload their identification documents along with personal details. Everything needs to be stored in one place and in a structured way, so I decided to use a SharePoint document library to hold both the files and ... <a title="Upload File to SharePoint Document Library With Metadata in SPFx" class="read-more" href="https://www.spguides.com/spfx-upload-file-to-sharepoint-document-library-with-metadata/" aria-label="Read more about Upload File to SharePoint Document Library With Metadata in SPFx">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>A few weeks ago, I created an <a href="https://www.spguides.com/pnp-react-pagination-control-spfx/">SPFx web part</a> for a USA Citizenship form that requires users to upload their identification documents along with personal details. Everything needs to be stored in one place and in a structured way, so I decided to use a <a href="https://www.spguides.com/create-and-delete-sharepoint-document-library-using-powershell/">SharePoint document library</a> to hold both the files and the metadata.</p>



<p>While implementing this solution, I followed a clean approach where the SPFx form uploads the file and updates the document metadata in a single step.</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download Complete Solution</a></div>
</div>



<p>In this tutorial, I will explain <strong>how to upload files to a SharePoint document library and update metadata using SPFx</strong>.</p>



<h2 class="wp-block-heading">Upload File to SharePoint Document Library With Metadata in SPF Client Side WebPart</h2>



<p>In the image below, you can see the <a href="https://www.spguides.com/sharepoint-document-library-best-practices/">SharePoint document library</a> named &#8220;USA Citizenship,&#8221; which stores the files and their metadata.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="298" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2025/11/spfx-upload-file-to-document-library-1024x298.png" alt="spfx upload file to document library" class="wp-image-123913" title="spfx upload file to document library" srcset="https://www.spguides.com/wp-content/uploads/2025/11/spfx-upload-file-to-document-library-1024x298.png 1024w, https://www.spguides.com/wp-content/uploads/2025/11/spfx-upload-file-to-document-library-300x87.png 300w, https://www.spguides.com/wp-content/uploads/2025/11/spfx-upload-file-to-document-library-768x223.png 768w, https://www.spguides.com/wp-content/uploads/2025/11/spfx-upload-file-to-document-library.png 1472w" /></figure></div>


<p>This library has the following fields:</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Column Name</th><th>Data Type</th></tr></thead><tbody><tr><td>Name</td><td>Default field</td></tr><tr><td>CurrentLegalName&nbsp;</td><td>Single line of text</td></tr><tr><td>NameExactlyOnYourPRC&nbsp;</td><td>Single line of text</td></tr><tr><td>DOB&nbsp;</td><td>Date and Time</td></tr><tr><td>CountryOfBirth&nbsp;</td><td>Single line of text</td></tr><tr><td>CountryOfNationality&nbsp;</td><td>Single line of text</td></tr><tr><td>MaritalStatus&nbsp;</td><td>Choice</td></tr><tr><td>Email id</td><td>Single line of text</td></tr><tr><td>Contact&nbsp;</td><td>Number</td></tr><tr><td>Gender</td><td>Choice</td></tr><tr><td>Disability&nbsp;</td><td>Choice (enable multiple selections)</td></tr></tbody></table></figure>



<p>Here is the SPFx web part that renders the complete citizenship form. It includes all required metadata fields, a file upload control for attaching identity documents, and Submit/Reset buttons to submit the form and clear the data.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="828" height="1024" sizes="(max-width: 828px) 100vw, 828px" src="https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-client-side-webpart-828x1024.png" alt="upload a file and update the metadata using spfx client side webpart" class="wp-image-123938" title="upload a file and update the metadata using spfx client side webpart" srcset="https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-client-side-webpart-828x1024.png 828w, https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-client-side-webpart-242x300.png 242w, https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-client-side-webpart-768x950.png 768w, https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-client-side-webpart.png 1213w" /></figure></div>


<p>Now, we&#8217;ll see how to create this form in the SPFx web part and submit the input data to the SharePoint document library. We will use the<strong> PnPJS library </strong>to interact with SharePoint.</p>



<p>I hope by this time, you know <a href="https://www.spguides.com/sharepoint-framework-crud-operations-using-react/">how to create SPFx web part using React</a>, and in case you&#8217;re new to SPFx, you can check how to<a href="https://www.spguides.com/set-up-development-environment-for-sharepoint-framework/"> set up an SPFx development environment</a>.</p>



<ol class="wp-block-list">
<li>Run the command below to install the PnPJS library into our solution.</li>
</ol>



<pre class="wp-block-code"><code>npm install @pnp/sp --save</code></pre>



<ol start="2" class="wp-block-list">
<li>Open the <strong>.ts file</strong> and add the following imports and PnPJS setup into the existing code.</li>
</ol>



<pre class="wp-block-code"><code>import { spfi, SPFx } from "@pnp/sp";
import { SPFI } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import "@pnp/sp/fields";
import "@pnp/sp/folders";
import "@pnp/sp/files";
import "@pnp/sp/files/web";
export interface IUsaCitizenshipFormWebPartProps {
  description: string;
}

export default class UsaCitizenshipFormWebPart extends BaseClientSideWebPart&lt;IUsaCitizenshipFormWebPartProps&gt; {

  private _isDarkTheme: boolean = false;
  private _environmentMessage: string = '';
  private _sp: SPFI

  public render(): void {
    const element: React.ReactElement&lt;IUsaCitizenshipFormProps&gt; = React.createElement(
      UsaCitizenshipForm,
      {
        description: this.properties.description,
        isDarkTheme: this._isDarkTheme,
        environmentMessage: this._environmentMessage,
        hasTeamsContext: !!this.context.sdks.microsoftTeams,
        userDisplayName: this.context.pageContext.user.displayName,
        sp:this._sp,
        context:this.context,
      }
    );

    ReactDom.render(element, this.domElement);
  }

  protected onInit(): Promise&lt;void&gt; {
    return this._getEnvironmentMessage().then(message =&gt; {
      this._environmentMessage = message;
      this._sp = spfi().using(SPFx(this.context));
    });
  }</code></pre>



<p>Here:</p>



<ul class="wp-block-list">
<li>We imported the PnPJS library statements required to interact with SharePoint.</li>



<li>Initialized a variable <strong>_sp</strong> to hold the PnPJs instance.</li>



<li>In the <strong>onInit()</strong> method, I created the PnPJs instance, and in the render() method, I assigned that instance to the prop <strong>sp</strong>.</li>
</ul>



<ol start="3" class="wp-block-list">
<li>Also, update the <strong>Props.ts</strong> file code with the code below.</li>
</ol>



<pre class="wp-block-code"><code>import { WebPartContext } from "@microsoft/sp-webpart-base";
import { SPFI } from "@pnp/sp";
export interface IUsaCitizenshipFormProps {
  description: string;
  isDarkTheme: boolean;
  environmentMessage: string;
  hasTeamsContext: boolean;
  userDisplayName: string;
  sp:SPFI;
  context: WebPartContext
}</code></pre>



<p>Here, we <span style="box-sizing: border-box; margin: 0px; padding: 0px;">also added the&nbsp;<strong>sp </strong>and</span> <strong>context</strong> props to the existing props.</p>



<ol start="4" class="wp-block-list">
<li>Now open the<strong> .tsx file</strong> and replace your default code with the code below.</li>
</ol>



<pre class="wp-block-code"><code>import * as React from "react";
import type { IUsaCitizenshipFormProps } from "./IUsaCitizenshipFormProps";
import styles from "./UsaCitizenshipForm.module.scss";

export interface IUsaCitizenshipFormState {
  CurrentLegalName: string;
  NameExactlyOnYourPRC: string;
  DOB: string;
  MaritalStatus: string;
  Disability: string&#91;];
  CountryOfNationality: string;
  CountryOfBirth: string;
  Emailid: string;
  Contact: string;
  Gender: string;
  file: File | null;
  statusMessage: string;
  errors: string&#91;];
  isSubmitting: boolean;
  statusType: "success" | "error" | "";
}

export default class UsaCitizenshipForm extends React.Component&lt;
  IUsaCitizenshipFormProps,
  IUsaCitizenshipFormState
&gt; {
  constructor(props: IUsaCitizenshipFormProps) {
    super(props);


    this.state = {
      CurrentLegalName: "",
      NameExactlyOnYourPRC: "",
      DOB: "",
      MaritalStatus: "",
      Disability: &#91;],
      CountryOfNationality: "",
      CountryOfBirth: "",
      Emailid: "",
      Contact: "",
      Gender: "",
      file: null,
      statusMessage: "",
      errors: &#91;],
      isSubmitting: false,
      statusType:""
    };
  }


  private handleInputChange = (
    e: React.ChangeEvent&lt;HTMLInputElement | HTMLSelectElement&gt;
  ) =&gt; {
    this.setState({ &#91;e.target.name]: e.target.value } as any);
  };

  private handleMultiSelect = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    const { value, checked } = e.target;
    let selected = &#91;...this.state.Disability];

    if (checked) {
      if (!selected.includes(value)) selected.push(value);
    } else {
      selected = selected.filter((v) =&gt; v !== value);
    }

    this.setState({ Disability: selected });
  };

  private handleFileSelect = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
    this.setState({ file: e.target.files ? e.target.files&#91;0] : null });
  };

  private validateForm = (): boolean =&gt; {
    let errors: string&#91;] = &#91;];

    if (!this.state.CurrentLegalName.trim())
      errors.push("Current Legal Name is required.");

    if (!this.state.CountryOfNationality.trim())
      errors.push("Country of Nationality is required.");

    if (!this.state.CountryOfBirth.trim())
      errors.push("Country of Birth is required.");

    if (!this.state.Gender.trim())
      errors.push("Gender is required.");

    if (!this.state.file)
      errors.push("Identity Proof file must be uploaded.");

    this.setState({ errors });
    return errors.length === 0;
  };
private uploadFormData = async () =&gt; {
  if (!this.validateForm()) {
    this.setState({ 
      statusMessage: "Please fill the mandatory fields",
      statusType: "error"
    });
    return;
  }

  this.setState({ statusMessage: "Submitting...", isSubmitting: true, statusType: "" });

  try {
    const sp = this.props.sp;
    const libraryPath = "/sites/SPFXDevelopment/USACitizenship";
    const file = this.state.file;

    if (!file) {
      this.setState({ statusMessage: "Please select a file.", statusType: "error", isSubmitting: false });
      return;
    }

    const folder = sp.web.getFolderByServerRelativePath(libraryPath);
    await folder.files.addUsingPath(file.name, file, { Overwrite: true });

    const filePath = `${libraryPath}/${file.name}`;
    const spFile = sp.web.getFileByServerRelativePath(filePath);
    const item = await spFile.getItem();

    await item.update({
      Title: this.state.CurrentLegalName,
      CurrentLegalName: this.state.CurrentLegalName,
      NameExactlyOnYourPRC: this.state.NameExactlyOnYourPRC,
      DOB: this.state.DOB,
      MaritalStatus: this.state.MaritalStatus,
      Disability: this.state.Disability,
      CountryOfNationality: this.state.CountryOfNationality,
      CountryOfBirth: this.state.CountryOfBirth,
      Emailid: this.state.Emailid,
      Contact: this.state.Contact,
      Gender: this.state.Gender
    });

    this.setState({ statusMessage: "Form submitted successfully!", statusType: "success", isSubmitting: false });
  } catch (err: any) {
    this.setState({ statusMessage: "Error: " + err.message, statusType: "error", isSubmitting: false });
  }
};
private resetForm = () =&gt; {
  this.setState({
    CurrentLegalName: "",
    NameExactlyOnYourPRC: "",
    DOB: "",
    MaritalStatus: "",
    Disability: &#91;],
    CountryOfNationality: "",
    CountryOfBirth: "",
    Emailid: "",
    Contact: "",
    Gender: "",
    file: null,
    statusMessage: "",
    errors: &#91;],
    isSubmitting: false,
    statusType: ""
  });
};

  public render() {
    return (
      &lt;div className={styles.formContainer}&gt;

        &lt;h2 className={styles.formTitle}&gt;Citizenship Form&lt;/h2&gt;


        &lt;label&gt;Current Legal Name&lt;span style={{ color: "red" }}&gt;*&lt;/span&gt;&lt;/label&gt;
        &lt;input
          type="text"
          name="CurrentLegalName"
          className={styles.input}
          value={this.state.CurrentLegalName}
          onChange={this.handleInputChange}
        /&gt;


        &lt;label&gt;Name exactly as it appears on your Permanent Resident Card (PRC)&lt;/label&gt;
        &lt;input
          type="text"
          name="NameExactlyOnYourPRC"
          className={styles.input}
          value={this.state.NameExactlyOnYourPRC}
          onChange={this.handleInputChange}
        /&gt;
        &lt;label&gt;Date of Birth&lt;/label&gt;
        &lt;input
          type="date"
          name="DOB"
          className={styles.input}
          value={this.state.DOB}
          onChange={this.handleInputChange}
        /&gt;

        &lt;label&gt;Marital Status&lt;/label&gt;
        &lt;select
          name="MaritalStatus"
          className={styles.input}
          value={this.state.MaritalStatus}
          onChange={this.handleInputChange}
        &gt;
          &lt;option value=""&gt;-- Select Marital Status --&lt;/option&gt;
          &lt;option value="Married"&gt;Married&lt;/option&gt;
          &lt;option value="Single"&gt;Single&lt;/option&gt;
          &lt;option value="Divorced"&gt;Divorced&lt;/option&gt;
          &lt;option value="Widowed"&gt;Widowed&lt;/option&gt;
        &lt;/select&gt;


        &lt;label&gt;Disability Impairment:&lt;/label&gt;

        &lt;div className={styles.checkboxGroup}&gt;
          &lt;label&gt;
            &lt;input
              type="checkbox"
              value="I am deaf or hearing impaired and need a sign language interpreter who uses my language"
              onChange={this.handleMultiSelect}
              checked={this.state.Disability.includes(
        "I am deaf or hearing impaired and need a sign language interpreter who uses my language"
      )}
            /&gt;
            I am deaf or hearing impaired and need a sign language interpreter who uses my language
          &lt;/label&gt;

          &lt;label&gt;
            &lt;input type="checkbox" value="I use a wheelchair" onChange={this.handleMultiSelect} checked={this.state.Disability.includes("I use a wheelchair")} /&gt;
            I use a wheelchair
          &lt;/label&gt;

          &lt;label&gt;
            &lt;input
              type="checkbox"
              value="I am blind or sight impaired"
              onChange={this.handleMultiSelect}
              checked={this.state.Disability.includes("I am blind or sight impaired")}
            /&gt;
            I am blind or sight impaired
          &lt;/label&gt;

          &lt;label&gt;
            &lt;input
              type="checkbox"
              value="I will need another type of accommodation"
              onChange={this.handleMultiSelect}
              checked={this.state.Disability.includes("I will need another type of accommodation")}
            /&gt;
            I will need another type of accommodation
          &lt;/label&gt;
        &lt;/div&gt;

        &lt;label&gt;Country Of Nationality&lt;span style={{ color: "red" }}&gt;*&lt;/span&gt;&lt;/label&gt;
        &lt;input
          type="text"
          name="CountryOfNationality"
          className={styles.input}
          value={this.state.CountryOfNationality}
          onChange={this.handleInputChange}
        /&gt;


        &lt;label&gt;Country Of Birth&lt;span style={{ color: "red" }}&gt;*&lt;/span&gt;&lt;/label&gt;
        &lt;input
          type="text"
          name="CountryOfBirth"
          className={styles.input}
          value={this.state.CountryOfBirth}
          onChange={this.handleInputChange}
        /&gt;

        &lt;label&gt;Email Id&lt;/label&gt;
        &lt;input
          type="text"
          name="Emailid"
          className={styles.input}
          value={this.state.Emailid}
          onChange={this.handleInputChange}
        /&gt;

        &lt;label&gt;Contact Number&lt;/label&gt;
        &lt;input
          type="text"
          name="Contact"
          className={styles.input}
          value={this.state.Contact}
          onChange={this.handleInputChange}
        /&gt;

        &lt;label&gt;Gender&lt;/label&gt;
        &lt;select
          name="Gender"
          className={styles.input}
          value={this.state.Gender}
          onChange={this.handleInputChange}
        &gt;
          &lt;option value=""&gt;-- Select gender --&lt;/option&gt;
          &lt;option value="Male"&gt;Male&lt;/option&gt;
          &lt;option value="Female"&gt;Female&lt;/option&gt;
          &lt;option value="Other"&gt;Other&lt;/option&gt;
        &lt;/select&gt;
        &lt;label&gt;Upload Identity Proof&lt;/label&gt;
        &lt;input type="file" className={styles.input} onChange={this.handleFileSelect} /&gt;
&lt;div style={{ marginTop: '10px' }}&gt;
        &lt;button
        className={styles.submitBtn}
        onClick={this.uploadFormData}
        disabled={this.state.isSubmitting}
      &gt;
        {this.state.isSubmitting ? "Submitting..." : "Submit"}
      &lt;/button&gt;
  &lt;button
    className={styles.submitBtn}
    style={{ background: "#6c757d", marginLeft: "10px" }}
    onClick={this.resetForm}
    disabled={this.state.isSubmitting} 
  &gt;
    Reset
  &lt;/button&gt;
  &lt;/div&gt;
       
      {this.state.statusMessage &amp;&amp; (
        &lt;div
          className={styles.status}
          style={{ color: this.state.statusType === "success" ? "green" : this.state.statusType === "error" ? "red" : "black" }}
        &gt;
          {this.state.statusMessage}
        &lt;/div&gt;
      )}
      {this.state.errors.length &gt; 0 &amp;&amp; (
        &lt;div className={styles.errorBox}&gt;
          {this.state.errors.map((err, index) =&gt; (
            &lt;div key={index}&gt;• {err}&lt;/div&gt;
          ))}
        &lt;/div&gt;
      )}
    
      &lt;/div&gt;
    );
  }
}</code></pre>



<p>Here:</p>



<ul class="wp-block-list">
<li><strong>IUsaCitizenshipFormState </strong>= Created this state to hold the form input data for saving to the library. It contains all the SharePoint library fields, along with states to handle errors and change the button title.</li>



<li>Within the <strong>constructor()</strong>, we initialized these states with empty values.</li>



<li>Created <strong>handleInputChange()</strong> and <strong>handleMultiSelect() </strong>helper methods to update the state values when the user enters data in the form input controls.</li>



<li>This <strong>handleFileSelect()</strong> method stores the selected file in the <strong>file </strong>state.</li>



<li><span style="box-sizing: border-box; margin: 0px; padding: 0px;">The&nbsp;<strong>validateForm()</strong>&nbsp;method checks whether we have provided data for the mandatory fields</span>. If not, it adds the validation messages to the state <strong>errors<span style="box-sizing: border-box; margin: 0px; padding: 0px;"> </span></strong>array.</li>



<li>In the <strong>resetForm()</strong> method, we set the state values to empty, so when we click the Reset button, the form fields are cleared.</li>



<li>The <strong>uploadFormData()</strong> will be triggered when we click the <strong>Submit </strong>button. 
<ul class="wp-block-list">
<li><span style="box-sizing: border-box; margin: 0px; padding: 0px;">It first calls the&nbsp;<strong>validateForm()</strong>&nbsp;method to check whether any fields are missing data, then updates the <strong>statusMessage </strong>state so the submit button text changes to &#8220;Submitt</span>ing&#8230;&#8221;</li>



<li>In the <strong>try{}</strong> block, we check whether the file exists. If yes, then we are uploading it into the &#8220;USACitizenship&#8221; document library using PnPJs. And then we retrieve that item and update its metadata.</li>
</ul>
</li>



<li><span style="box-sizing: border-box; margin: 0px; padding: 0px;">In&nbsp;the <strong>render()</strong>&nbsp;method, it displays the form with various input controls for the meta</span>data, along with buttons. Down to the buttons, showing the error block so the user knows.</li>
</ul>



<ol start="5" class="wp-block-list">
<li>Also, add the styles to this web part by updating the CSS styles in the <strong>.scss file</strong>.</li>
</ol>



<pre class="wp-block-code"><code>.formContainer {
  width: 70%;
  margin: auto;
  background: #f8f8f8;
  padding: 25px;
  border-radius: 6px;
  border: 1px solid #ccc;
}

.formTitle {
  text-align: center;
  margin-bottom: 20px;
  font-size: 26px;
  font-weight: bold;
}

.input {
  width: 100%;
  padding: 8px;
  margin-bottom: 12px;
  border: 1px solid #ccc;
  border-radius: 4px;
  box-sizing: border-box;
}

.checkboxGroup {
  margin-left: 5px;
  margin-bottom: 15px;
}

.checkboxGroup label {
  display: block;
  margin-bottom: 6px;
}

.submitBtn {
  background: #0078d4;
  color: white;
  padding: 10px 18px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.submitBtn:hover {
  background: #005a9e;
}

.status {
  margin-top: 15px;
  font-weight: bold;
}
.errorInput {
  border: 2px solid red !important;
}

.errorBox {
  margin-top: 15px;
  padding: 12px;
  background: #ffe5e5;
  color: #b40000;
  border-left: 4px solid red;
  border-radius: 4px;
  font-size: 14px;
}</code></pre>



<ol start="6" class="wp-block-list">
<li>Once the implementation is done, run the <strong>gulp serve</strong> command to test this web part locally. The web part will be displayed as shown in the image below. </li>



<li>When we click the Submit button without entering any input in the form fields, custom error messages will be displayed below it, as shown in the image below. After filling out the form with the correct data and clicking the submit button, the file and metadata will be uploaded to the SharePoint library.</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="676" height="1024" sizes="(max-width: 676px) 100vw, 676px" src="https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-webpart-676x1024.png" alt="upload a file and update the metadata using spfx webpart" class="wp-image-123960" title="upload a file and update the metadata using spfx webpart" srcset="https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-webpart-676x1024.png 676w, https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-webpart-198x300.png 198w, https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-webpart-768x1164.png 768w, https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-webpart-1014x1536.png 1014w, https://www.spguides.com/wp-content/uploads/2025/11/upload-a-file-and-update-the-metadata-using-spfx-webpart.png 1213w" /></figure></div>


<p>This way, you can upload files to a document library along with metadata using SPFx.</p>



<div class="wp-block-buttons is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download Complete Solution</a></div>
</div>



<h2 class="wp-block-heading">Conclusion</h2>



<p>I hope you found this tutorial helpful. Here, I explained how to <strong>upload files to the SharePoint document library along with metadata using the PnPJS library in the SPFx web part</strong>. Also, I covered adding validations to the form before submitting to collect the required metadata fields.</p>



<p>You can download this solution and test it. If you face any issues with this, you can post your doubts in the comments below. Follow the steps mentioned in this article if you are also looking to upload files to the document library with metadata using SPFx.</p>



<p>You may also like the following related tutorials:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/fluent-ui-documentcard-in-spfx-web-part/">Fluent UI DocumentCard in SPFx Web Part</a></li>



<li><a href="https://www.spguides.com/create-folders-and-subfolders-in-sharepoint-document-library-using-spfx/">Create Folders and Subfolders in SharePoint document library using SPFx</a></li>



<li><a href="https://www.spguides.com/sharepoint-framework-extension-field-customizer/">SPFx Field Customizer Example</a></li>



<li><a href="https://www.spguides.com/get-current-sharepoint-site-information-in-spfx-using-ms-graph-api/">Get Current SharePoint Site Information in SPFx using MS Graph API</a></li>



<li><a href="https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/">Build a Custom Slides Manager in SPFx Web Part Property Pane (Drag &amp; Drop, Reorder, Hide Slides)</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Build a Custom Slides Manager in SPFx Web Part Property Pane (Drag &#038; Drop, Reorder, Hide Slides)</title>
		<link>https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/</link>
		
		<dc:creator><![CDATA[Bijay Kumar]]></dc:creator>
		<pubDate>Fri, 27 Mar 2026 17:52:43 +0000</pubDate>
				<category><![CDATA[SharePoint Framework]]></category>
		<category><![CDATA[Custom Slides Manager in SPFx Property Pane]]></category>
		<guid isPermaLink="false">https://www.spguides.com/?p=130148</guid>

					<description><![CDATA[While working on a SharePoint Framework project for one of our clients, we were required to build a carousel web part to display company updates, internal communications, and related content. Here, the main requirement is that, for this web part, we need to allow users to choose which slides to display in the carousel. For ... <a title="Build a Custom Slides Manager in SPFx Web Part Property Pane (Drag &#38; Drop, Reorder, Hide Slides)" class="read-more" href="https://www.spguides.com/spfx-property-pane-slide-manager-drag-drop/" aria-label="Read more about Build a Custom Slides Manager in SPFx Web Part Property Pane (Drag &#38; Drop, Reorder, Hide Slides)">read more...</a>]]></description>
										<content:encoded><![CDATA[
<p>While working on a <a href="https://www.spguides.com/spfx-training-course/">SharePoint Framework </a>project for one of our clients, we were required to build a carousel web part to display company updates, internal communications, and related content. </p>



<p>Here, the main requirement is that, for this web part, we need to allow users to choose which slides to display in the carousel. For the best practices, I took reference from the&nbsp;<a href="https://www.spguides.com/hero-web-part-sharepoint-online-modern-site/">SharePoint Hero web part</a>.</p>



<p>As you can see in the <strong>property pane</strong>, after selecting the SharePoint list and fields, the information was displayed under the <strong>slides</strong>. I can now easily drag and drop to reorder which slide needs to be visible first. Also, through menu items, I can move up or down. Additionally, I can remove the slides I don&#8217;t want displayed in the web part and even restore them.</p>


<div class="wp-block-image">
<figure class="aligncenter size-large"><img data-dominant-color="f9f9f7" data-has-transparency="false" style="--dominant-color: #f9f9f7;" loading="lazy" decoding="async" width="1124" height="686" sizes="(max-width: 1024px) 100vw, 1024px" src="https://www.spguides.com/wp-content/uploads/2026/02/Build-a-dynamic-slide-management-UI-in-SPFx-property-pane-using-react.gif" alt="Build a dynamic slide management UI in SPFx property pane using react" class="wp-image-130152 not-transparent" title="Build a dynamic slide management UI in SPFx property pane using react"></figure></div>


<p>In this tutorial, we’ll build a <strong>custom slide manager inside the SPFx property pane</strong>, similar to the <strong>SharePoint Hero web part</strong>.</p>



<p>By the end of this article, you’ll learn how to:</p>



<ul class="wp-block-list">
<li>Show dynamic items (slides) inside the property pane</li>



<li>Reorder slides using <strong>drag and drop</strong></li>



<li>Move slides up or down</li>



<li>Temporarily remove slides without deleting list items</li>



<li>Restore hidden slides later</li>



<li>Keep everything in sync with the web part UI</li>
</ul>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download SPFx Solutions</a></div>
</div>



<p>You can reuse this in carousels, banners, hero sections, and announcement web parts.</p>



<p>Want to learn SharePoint Framework development? Check out the <a href="https://www.spguides.com/spfx-training-course/" target="_blank" rel="noreferrer noopener">SPFx training course</a>.</p>



<h2 class="wp-block-heading">Build a Slide Manager in SPFx Property Pane Using React</h2>



<p>Before starting the implementation, let&#8217;s have a look at the SharePoint list I took for this SPFx web part. We&#8217;ll mainly focus on how to manage the slides on the <a href="https://www.spguides.com/add-custom-controls-in-spfx-property-pane/">SPFx web part property pane</a>. </p>



<p>Below is the SharePoint list named &#8220;Company Announcements&#8221; having the following fields:</p>



<ul class="wp-block-list">
<li><strong>Title </strong>= Default title field.</li>



<li><strong>Announcement Image </strong>= Image field.</li>



<li><strong>Announcement Link </strong>= Hyperlink field.</li>
</ul>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="dee0e3" data-has-transparency="false" style="--dominant-color: #dee0e3;" loading="lazy" decoding="async" width="998" height="598" sizes="(max-width: 998px) 100vw, 998px" src="https://www.spguides.com/wp-content/uploads/2026/02/spfx-property-pane-file-picker.avif" alt="spfx property pane file picker" class="wp-image-130154 not-transparent" title="spfx property pane file picker" srcset="https://www.spguides.com/wp-content/uploads/2026/02/spfx-property-pane-file-picker.avif 998w, https://www.spguides.com/wp-content/uploads/2026/02/spfx-property-pane-file-picker-300x180.avif 300w, https://www.spguides.com/wp-content/uploads/2026/02/spfx-property-pane-file-picker-768x460.avif 768w" /></figure></div>


<p>This way, im storing the announcement information for the <a href="https://www.spguides.com/add-new-webpart-in-spfx-solution/">SPFx web part</a>.</p>



<p>Now, look at the SPFx web part property pane example below. I gave some configurations.</p>



<ul class="wp-block-list">
<li><strong>Select List or Library</strong> = This dropdown lets you choose a SharePoint list or library available on the SharePoint site.</li>



<li><strong>Number of Items to Display </strong>= Allows selection of the number of items to display in the carousel web part.</li>



<li><strong>Title Field</strong>&nbsp;= Allows selection of the Image Title field.</li>



<li><strong>Image Field</strong> = Allows selection of an image field.</li>



<li><strong>Link Field</strong> = Allows selection of the Hyperlink field.</li>



<li><strong>Autoplay</strong> = Control the carousel&#8217;s moving slides.</li>



<li><span style="box-sizing: border-box; margin: 0px; padding: 0px;"><strong>Slides</strong> = To display the items from the <a href="https://www.spguides.com/read-excel-file-and-add-bulk-data-to-sharepoint-list-pnp-powershell/" target="_blank" rel="noreferrer noopener">SharePoint list</a> that are going to be visible in th</span>e web part. Here, we can drag and drop, move slides up and down, and either remove or restore slides.<br><br></li>
</ul>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="f5f5f3" data-has-transparency="false" style="--dominant-color: #f5f5f3;" loading="lazy" decoding="async" width="414" height="790" sizes="(max-width: 414px) 100vw, 414px" src="https://www.spguides.com/wp-content/uploads/2026/02/dynamic-slide-management-UI-in-SPFx-property-pane-using-react.gif" alt="dynamic slide management UI in SPFx property pane using react" class="wp-image-130157 not-transparent" title="dynamic slide management UI in SPFx property pane using react"></figure></div>


<p>Now let&#8217;s see the implementation.</p>



<p>I hope by this time, you know how to create an SPFx web part with the React framework; if not, <a href="https://www.spguides.com/sharepoint-framework-client-web-part/">follow this article</a>.</p>



<ol class="wp-block-list">
<li>Once the web part is created, run the following npm command to install the PnPJS.</li>
</ol>



<pre class="wp-block-code"><code>npm install @pnp/sp --save</code></pre>



<p>We are using this to interact with the<a href="https://www.spguides.com/create-a-sharepoint-list-or-library-spfx/"> SharePoint list</a> for fetching items.</p>



<ol start="2" class="wp-block-list">
<li>Run the command below to install PnP Property pane controls; this will auto-populate SharePoint lists, fields, etc.</li>
</ol>



<pre class="wp-block-code"><code>npm install @pnp/spfx-property-controls --save</code></pre>



<ol start="3" class="wp-block-list">
<li>After that, open the <strong>Props.ts</strong> file and add the following code.</li>
</ol>



<pre class="wp-block-code"><code>export interface ISpFxCarouselProps {
  description: string;
  isDarkTheme: boolean;
  environmentMessage: string;
  hasTeamsContext: boolean;
  userDisplayName: string;
  autoplayEnabled: boolean;
}</code></pre>



<ol start="4" class="wp-block-list">
<li>Then, we need to create some folders and files for the slides management in the property pane. So, as shown in the image below, add the folders and files.
<ul class="wp-block-list">
<li><strong>models </strong>[Folder] = Under this path &#8220;src/webparts/spFxCarousel/&#8221;
<ul class="wp-block-list">
<li><strong>ISlidesConfig.ts </strong>[File] = In this path &#8220;src/webparts/spFxCarousel/models/&#8221;</li>
</ul>
</li>



<li><strong>propertyPane</strong> [Folder] = Under this path &#8220;src/webparts/spFxCarousel/&#8221;
<ul class="wp-block-list">
<li>ISlidesConfig.ts [File] =  In this path &#8220;src/webparts/spFxCarousel/propertyPane/&#8221;</li>



<li>PropertyPaneSlidesManager.ts [File] =  In this path &#8220;src/webparts/spFxCarousel/propertyPane/&#8221;</li>



<li>SlidesManager.tsx [File] =  In this path &#8220;src/webparts/spFxCarousel/propertyPane/&#8221;</li>
</ul>
</li>
</ul>
</li>
</ol>


<div class="wp-block-image">
<figure class="aligncenter size-full"><img data-dominant-color="ebe8e9" data-has-transparency="false" style="--dominant-color: #ebe8e9;" loading="lazy" decoding="async" width="372" height="700" sizes="(max-width: 372px) 100vw, 372px" src="https://www.spguides.com/wp-content/uploads/2026/02/Custom-Slides-Manager-in-SPFx-Web-Part-Property-Pane.avif" alt="Custom Slides Manager in SPFx Web Part Property Pane" class="wp-image-130209 not-transparent" title="Custom Slides Manager in SPFx Web Part Property Pane" srcset="https://www.spguides.com/wp-content/uploads/2026/02/Custom-Slides-Manager-in-SPFx-Web-Part-Property-Pane.avif 372w, https://www.spguides.com/wp-content/uploads/2026/02/Custom-Slides-Manager-in-SPFx-Web-Part-Property-Pane-159x300.avif 159w" /></figure></div>


<ol start="5" class="wp-block-list">
<li>Open the <strong>ISlideConfig.ts</strong> file located in the <strong>models </strong>folder.</li>
</ol>



<pre class="wp-block-code"><code>export interface ISlideConfig {
  id: number;     
  visible: boolean; 
}</code></pre>



<ul class="wp-block-list">
<li><strong>id:</strong> The SharePoint list item ID (matches the &#8220;Id&#8221; column)</li>



<li><strong>visible:</strong>  true = slide is shown in the carousel, false = slide is hidden</li>
</ul>



<ol start="6" class="wp-block-list">
<li>Then, open the <strong>ISlidesManagerProps.ts file</strong> located in the <strong>propertyPane </strong>folder.</li>
</ol>



<pre class="wp-block-code"><code>import { ISlideConfig } from '../models/ISlidesConfig';

export interface ISlidesManagerProps {
  slidesConfig: ISlideConfig&#91;];                      
  allItems: { id: number; title: string }&#91;];        
  onConfigChanged: (config: ISlideConfig&#91;]) =&gt; void; 
}</code></pre>



<p>Here:</p>



<ul class="wp-block-list">
<li>This file stores the Props interface for the <strong>SlidesManager </strong>React component.</li>



<li>These props are passed from <strong>PropertyPaneSlidesManager.ts</strong> when the component is created.</li>



<li><strong>slidesConfig</strong> = Current slide order and visibility (from web part properties)</li>



<li><strong>allItems </strong>= All items fetched from the SharePoint list (used to display titles)</li>



<li><strong>onConfigChanged </strong>= Callback to save changes back to the web part property bag</li>
</ul>



<ol start="7" class="wp-block-list">
<li>Add the code below to the <strong>PropertyPaneSlidesManager.ts</strong> file located in the <strong>propertyPane </strong>folder.</li>
</ol>



<pre class="wp-block-code"><code>import * as React from 'react';
import * as ReactDom from 'react-dom';
import {
  IPropertyPaneField,
  IPropertyPaneCustomFieldProps,
  PropertyPaneFieldType
} from '@microsoft/sp-property-pane';
import { SlidesManager } from './SlidesManager';
import { ISlidesManagerProps } from './ISlidesManagerProps';
import { ISlideConfig } from '../models/ISlidesConfig';


export interface IPropertyPaneSlidesManagerConfig {
  key: string;                                       
  slidesConfig: ISlideConfig&#91;];                      
  allItems: { id: number; title: string }&#91;];         
  onConfigChanged: (config: ISlideConfig&#91;]) =&gt; void; 
}

export function PropertyPaneSlidesManager(
  config: IPropertyPaneSlidesManagerConfig
): IPropertyPaneField&lt;IPropertyPaneCustomFieldProps&gt; {

  return {
   
    type: PropertyPaneFieldType.Custom,
    targetProperty: 'slidesConfig',

    properties: {
      key: config.key,
      onRender: (elem: HTMLElement) =&gt; {
        const el = React.createElement(SlidesManager, {
          slidesConfig: config.slidesConfig,
          allItems: config.allItems,
          onConfigChanged: config.onConfigChanged
        } as ISlidesManagerProps);

        ReactDom.render(el, elem);
      },

      onDispose: (elem: HTMLElement) =&gt; {
        ReactDom.unmountComponentAtNode(elem);
      }
    }
  };
}</code></pre>



<p>Here:</p>



<ul class="wp-block-list">
<li>This file <span style="box-sizing: border-box; margin: 0px; padding: 0px;">defines</span> the config interface for creating this custom property pane field.</li>



<li>IPropertyPaneSlidesManagerConfig:
<ul class="wp-block-list">
<li><strong>key </strong>= Unique key for the property pane field (required by SPFx)</li>



<li><strong>slidesConfig </strong>= Current slide order and visibility</li>



<li><strong>allItems </strong>= All SharePoint list items (id + title)</li>



<li><strong>onConfigChanged </strong>= Callback when user changes slide order or visibility</li>
</ul>
</li>



<li><strong>PropertyPaneSlidesManager</strong>() = Creates a custom SPFx property pane field. 
<ul class="wp-block-list">
<li>Because SPFx only supports built-in fields (dropdowns, toggles, etc.) by default.</li>



<li>To render our own React component (SlidesManager) inside the property pane, </li>



<li>we use PropertyPaneFieldType.Custom and manually mount the React component.</li>



<li><strong>type</strong>: PropertyPaneFieldType.Custom = Tell SPFx that this is a custom field, not a built-in one.</li>



<li><strong>targetProperty</strong>: &#8216;slidesConfig&#8217; = The web part property this field is associated with.</li>



<li><strong>onRender()</strong> under <strong>properties</strong>{} = Called by SPFx when the property pane needs to display this field.</li>



<li>We create the SlidesManager React component and mount it into the provided DOM element.</li>
</ul>
</li>
</ul>



<ol start="8" class="wp-block-list">
<li>Then add the code below to the <strong>SlidesManager.tsx </strong>file present in the <strong>propertyPane</strong> folder.</li>
</ol>



<pre class="wp-block-code"><code>import * as React from 'react';
import { ISlidesManagerProps } from './ISlidesManagerProps';
import { ISlideConfig } from '../models/ISlidesConfig';
import { IconButton } from '@fluentui/react/lib/Button';


interface IState {
  config: ISlideConfig&#91;];
}

export class SlidesManager extends React.Component&lt;ISlidesManagerProps, IState&gt; {

  
  private dragIndex: number | null = null;
  private dragOverIndex: number | null = null;

  constructor(props: ISlidesManagerProps) {
    super(props);
    this.state = { config: props.slidesConfig.slice() };
  }


  public componentDidUpdate(prev: ISlidesManagerProps): void {
    if (JSON.stringify(prev.slidesConfig) !== JSON.stringify(this.props.slidesConfig)) {
      this.setState({ config: this.props.slidesConfig.slice() });
    }
  }

 
  public render(): JSX.Element {

    const visible: ISlideConfig&#91;] = &#91;];
    const hidden: ISlideConfig&#91;] = &#91;];

    for (const c of this.state.config) {
      c.visible ? visible.push(c) : hidden.push(c);
    }

    return (
      &lt;div style={{ marginTop: 8 }}&gt;

    
        {visible.map((c, index) =&gt; {

          let item = null;
          for (let i = 0; i &lt; this.props.allItems.length; i++) {
            if (this.props.allItems&#91;i].id === c.id) {
              item = this.props.allItems&#91;i];
              break;
            }
          }
          if (!item) return null;

          return (
            &lt;div
              key={c.id}
              draggable
              onDragStart={(e) =&gt; { this.dragIndex = index; e.dataTransfer.effectAllowed = 'move'; }}
              onDragEnter={() =&gt; this.dragOverIndex = index}
              onDragOver={(e) =&gt; { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }}
              onDrop={(e) =&gt; { e.preventDefault(); this.onDrop(); }}
              onDragEnd={() =&gt; { this.dragIndex = this.dragOverIndex = null; }}
              style={{
                display: 'flex',
                alignItems: 'center',
                padding: '6px 0',
                borderBottom: '1px solid #edebe9',
                cursor: 'grab'
              }}
            &gt;

              &lt;span style={{ padding: '0 6px', color: '#605e5c' }}&gt;⋮⋮&lt;/span&gt;

              {/* Slide title */}
              &lt;span style={{
                flex: 1,
                fontSize: 13,
                overflow: 'hidden',
                whiteSpace: 'nowrap',
                textOverflow: 'ellipsis'
              }}&gt;
                {item.title}
              &lt;/span&gt;

             
              &lt;IconButton
                iconProps={{ iconName: 'Hide3' }}
                title="Remove"
                onClick={() =&gt; this.hide(c.id)}
              /&gt;
            &lt;/div&gt;
          );
        })}

 
        {hidden.length &gt; 0 &amp;&amp; (
          &lt;div style={{ marginTop: 10 }}&gt;
            &lt;strong style={{ fontSize: 12 }}&gt;Hidden slides&lt;/strong&gt;

            {hidden.map(h =&gt; {

              let item = null;
              for (let i = 0; i &lt; this.props.allItems.length; i++) {
                if (this.props.allItems&#91;i].id === h.id) {
                  item = this.props.allItems&#91;i];
                  break;
                }
              }
              if (!item) return null;

              return (
                &lt;div key={h.id} style={{ fontSize: 13, marginTop: 4 }}&gt;
                  {item.title}
                  &lt;IconButton
                    iconProps={{ iconName: 'RedEye' }}
                    title="Show"
                    onClick={() =&gt; this.restore(h.id)}
                  /&gt;
                &lt;/div&gt;
              );
            })}
          &lt;/div&gt;
        )}
      &lt;/div&gt;
    );
  }


  private onDrop = (): void =&gt; {
    if (this.dragIndex === null || this.dragOverIndex === null) return;
    if (this.dragIndex === this.dragOverIndex) {
      this.dragIndex = this.dragOverIndex = null;
      return;
    }

    const visible: ISlideConfig&#91;] = &#91;];
    const hidden: ISlideConfig&#91;] = &#91;];

    for (const c of this.state.config) {
      if (c.visible) visible.push(c);
      else hidden.push(c);
    }

    const dragged = visible.splice(this.dragIndex, 1)&#91;0];
    visible.splice(this.dragOverIndex, 0, dragged);

    const newConfig = &#91;...visible, ...hidden];

    this.update(newConfig);
    this.dragIndex = this.dragOverIndex = null;
  };

 
  private hide(id: number): void {
    const updated: ISlideConfig&#91;] = &#91;];

    for (const c of this.state.config) {
      updated.push(
        c.id === id ? { id: c.id, visible: false } : c
      );
    }

    this.update(updated);
  }


  private restore(id: number): void {
    const updated: ISlideConfig&#91;] = &#91;];

    for (const c of this.state.config) {
      updated.push(
        c.id === id ? { id: c.id, visible: true } : c
      );
    }

    this.update(updated);
  }

  private update(config: ISlideConfig&#91;]): void {
    this.setState({ config });
    this.props.onConfigChanged(config);
  }
}</code></pre>



<p>Here:</p>



<ul class="wp-block-list">
<li>This file is a SlidesManager React component rendered inside the SPFx property pane.</li>



<li>It lets the user:
<ul class="wp-block-list">
<li>See all visible slides in their current order</li>



<li>Drag-and-drop to reorder visible slides</li>



<li>Hide a visible slide (click the hide icon)</li>



<li>Restore a hidden slide (click the eye icon)</li>
</ul>
</li>



<li><strong>dragIndex, dragOverIndex</strong> =These store the index of the item being dragged and the index it&#8217;s hovering over.</li>



<li><strong>constructor()</strong> = Initialize state with a copy of the slidesConfig from props</li>



<li><strong>componentDidUpdate()</strong> = Sync state when props change from outside.</li>



<li><strong>render</strong>() = Splits config into visible and hidden slides, then renders both sections.</li>



<li><strong>onDrop</strong>() = Handles the drag-and-drop reorder when a slide is dropped.
<ul class="wp-block-list">
<li>Takes the dragged item out of its old position and inserts it at the new position.</li>



<li>The final config is: reordered visible slides first, then hidden slides.</li>
</ul>
</li>



<li><strong>restore</strong>() = Sets a hidden slide&#8217;s visible flag back to true
<ul class="wp-block-list">
<li>The slide moves from the &#8220;hidden&#8221; section back to the &#8220;visible&#8221; section.</li>
</ul>
</li>



<li><strong>update</strong>() = Saves the new config to local state and notifies the parent
<ul class="wp-block-list">
<li>The parent callback (onConfigChanged) saves the config as a JSON string</li>



<li>back into the web part&#8217;s property bag.</li>
</ul>
</li>
</ul>



<ol start="9" class="wp-block-list">
<li><span style="box-sizing: border-box; margin: 0px; padding: 0px;">Then open the&nbsp;<strong>.ts</strong>&nbsp;file located in &#8220;src/webparts/spFxCarousel/&#8221;, which is the main entry p</span>oint, and replace it with the following code.</li>
</ol>



<pre class="wp-block-code"><code>import * as React from "react";
import * as ReactDom from "react-dom";
import { Version } from "@microsoft/sp-core-library";
import {
  IPropertyPaneConfiguration,
  PropertyPaneDropdown,
  PropertyPaneToggle,
  IPropertyPaneDropdownOption,
} from "@microsoft/sp-property-pane";
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
import { IReadonlyTheme } from "@microsoft/sp-component-base";
import {
  PropertyFieldListPicker,
  PropertyFieldListPickerOrderBy,
} from "@pnp/spfx-property-controls/lib/PropertyFieldListPicker";
import { PropertyFieldNumber } from "@pnp/spfx-property-controls/lib/PropertyFieldNumber";
import SpFxCarousel from "./components/SpFxCarousel";
import { ISpFxCarouselProps } from "./components/ISpFxCarouselProps";
import { PropertyPaneSlidesManager } from "./propertyPane/PropertyPaneSlidesManager";
import { spfi, SPFx } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";

export interface ISpFxCarouselWebPartProps {
  selectedListId: string;      
  titleFieldName: string;       
  imageFieldName: string;       
  hyperlinkFieldName: string;  
  numberOfItems: number;        
  autoplayEnabled: boolean;     
  slidesConfig: string;     
}

export default class SpFxCarouselWebPart extends BaseClientSideWebPart&lt;ISpFxCarouselWebPartProps&gt; {

  
  private _isDarkTheme: boolean = false;                     
  private _sp = spfi();                                        
  private _titleFields: IPropertyPaneDropdownOption&#91;] = &#91;];    
  private _imageFields: IPropertyPaneDropdownOption&#91;] = &#91;];    
  private _linkFields: IPropertyPaneDropdownOption&#91;] = &#91;];     
  private _announcementItems: { id: number; title: string }&#91;] = &#91;]; 

  public render(): void {
    const element: React.ReactElement&lt;ISpFxCarouselProps&gt; = React.createElement(
      SpFxCarousel,
      {
        description: "",
        isDarkTheme: this._isDarkTheme,
        environmentMessage: "",
        hasTeamsContext: !!this.context.sdks.microsoftTeams,
        userDisplayName: this.context.pageContext.user.displayName,
        autoplayEnabled: this.properties.autoplayEnabled,
      },
    );

    ReactDom.render(element, this.domElement);
  }

  protected async onInit(): Promise&lt;void&gt; {
    await super.onInit();
    this._sp = spfi().using(SPFx(this.context));
    await this._loadFieldOptions();
  }

  
  protected onThemeChanged(theme: IReadonlyTheme | undefined): void {
    if (!theme) return;
    this._isDarkTheme = !!theme.isInverted;
  }

  protected async onPropertyPaneConfigurationStart(): Promise&lt;void&gt; {
    await this._loadFieldOptions();
    await this._loadAnnouncementItems();
  }

  
  private async _loadAnnouncementItems(): Promise&lt;void&gt; {
    if (!this.properties.selectedListId) {
      this._announcementItems = &#91;];
      return;
    }


    const items = await this._sp.web.lists
      .getById(this.properties.selectedListId)
      .items.select("Id", this.properties.titleFieldName)
      .top(this.properties.numberOfItems || 5)();

    
    this._announcementItems = items.map((i: any) =&gt; ({
      id: i.Id,
      title: i&#91;this.properties.titleFieldName],
    }));

   
    let slidesConfig: { id: number; visible: boolean }&#91;] = &#91;];
    try {
      slidesConfig = JSON.parse(this.properties.slidesConfig || "&#91;]");
    } catch {
      slidesConfig = &#91;];
    }

    const existingIds = new Set(slidesConfig.map((c) =&gt; c.id));
    let changed = false;

    for (const item of this._announcementItems) {
      if (!existingIds.has(item.id)) {
        slidesConfig.push({ id: item.id, visible: true });
        changed = true;
      }
    }

    if (changed) {
      this.properties.slidesConfig = JSON.stringify(slidesConfig);
    }
  }

  
  protected async onPropertyPaneFieldChanged(
    propertyPath: string,
    oldValue: any,
    newValue: any,
  ): Promise&lt;void&gt; {
    super.onPropertyPaneFieldChanged(propertyPath, oldValue, newValue);

    
    if (propertyPath === "selectedListId" &amp;&amp; oldValue !== newValue) {
      this.properties.titleFieldName = "";
      this.properties.imageFieldName = "";
      this.properties.hyperlinkFieldName = "";
      this.properties.slidesConfig = "&#91;]";
      this._announcementItems = &#91;];

      await this._loadFieldOptions();
      this.context.propertyPane.refresh();
      return;
    }


    const isConfigured =
      this.properties.selectedListId &amp;&amp;
      this.properties.titleFieldName &amp;&amp;
      this.properties.imageFieldName &amp;&amp;
      this.properties.hyperlinkFieldName;

    if (isConfigured) {
      await this._loadAnnouncementItems();
      this.context.propertyPane.refresh();
    }
  }


  private async _loadFieldOptions(): Promise&lt;void&gt; {
    if (!this.properties.selectedListId) {
      this._titleFields = &#91;];
      this._imageFields = &#91;];
      this._linkFields = &#91;];
      return;
    }

    this._titleFields = &#91;{ key: "Title", text: "Title" }];
    this._imageFields = &#91;{ key: "Image", text: "Image" }];
    this._linkFields = &#91;{ key: "Link", text: "Link" }];
  }


  protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
    const groups: any&#91;] = &#91;];



    const configFields: any&#91;] = &#91;

      PropertyFieldListPicker("selectedListId", {
        label: "Select List or Library",
        selectedList: this.properties.selectedListId,
        includeHidden: false,
        orderBy: PropertyFieldListPickerOrderBy.Title,
        onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
        properties: this.properties,
        context: this.context as any,
        key: "listPicker",
      }),

      PropertyFieldNumber("numberOfItems", {
        key: "numberOfItems",
        label: "Number of items to display",
        value: this.properties.numberOfItems || 5,
        minValue: 1,
        maxValue: 50,
      }),
    ];

    if (this.properties.selectedListId) {
      configFields.push(
        PropertyPaneDropdown("titleFieldName", {
          label: "Title Field",
          options: this._titleFields,
          selectedKey: this.properties.titleFieldName,
        }),
        PropertyPaneDropdown("imageFieldName", {
          label: "Image Field",
          options: this._imageFields,
          selectedKey: this.properties.imageFieldName,
        }),
        PropertyPaneDropdown("hyperlinkFieldName", {
          label: "Link Field",
          options: this._linkFields,
          selectedKey: this.properties.hyperlinkFieldName,
        }),
        PropertyPaneToggle("autoplayEnabled", {
          label: "Enable Autoplay",
          onText: "On",
          offText: "Off",
        }),
      );
    }

    groups.push({
      groupName: "Configuration",
      groupFields: configFields,
    });

    

    const isConfigured =
      this.properties.selectedListId &amp;&amp;
      this.properties.titleFieldName &amp;&amp;
      this.properties.imageFieldName &amp;&amp;
      this.properties.hyperlinkFieldName;

    if (isConfigured &amp;&amp; this._announcementItems.length &gt; 0) {
      let slidesConfig: any&#91;] = &#91;];
      try {
        slidesConfig = JSON.parse(this.properties.slidesConfig || "&#91;]");
      } catch {
        slidesConfig = &#91;];
      }

    
      groups.push({
        groupName: "Slides",
        groupFields: &#91;
          PropertyPaneSlidesManager({
            key: "slidesManager",
            slidesConfig,
            allItems: this._announcementItems,
            onConfigChanged: (cfg: any&#91;]) =&gt; {
              this.properties.slidesConfig = JSON.stringify(cfg);
              this.render();
              this.context.propertyPane.refresh();
            },
          }) as any,
        ],
      });
    }


    return {
      pages: &#91;
        {
          header: { description: "SPFx Carousel Property Pane" },
          groups,
        },
      ],
    };
  }

  protected get dataVersion(): Version {
    return Version.parse("1.0");
  }
}
</code></pre>



<p>Here:</p>



<ul class="wp-block-list">
<li>To <a href="https://www.spguides.com/retrieve-sharepoint-list-items-date-range-power-automate/">retrieve SharePoint list items</a>, we used the PnPJS library. So, at the start, we added the PnPJS import statements.</li>



<li><strong>ISpFxCarouselWebPartProps </strong>= Define the web part property interface.
<ul class="wp-block-list">
<li><strong>selectedListId </strong>= &nbsp;GUID of the selected SharePoint list</li>



<li><strong>titleFieldName </strong>= Internal name of the column used for slide titles</li>



<li><strong>imageFieldName </strong>= Internal name of the column used for slide images</li>



<li><strong>hyperlinkFieldName </strong>= Internal name of the column used for slide links</li>



<li><strong>numberOfItems </strong>= Max number of items to fetch from the list</li>



<li><strong>autoplayEnabled </strong>= Whether the carousel auto-advances</li>



<li><strong>slidesConfig </strong>= JSON string of ISlideConfig[] — stores slide order and visibility.</li>
</ul>
</li>



<li><strong>_titleFields </strong>= Dropdown options for the Title field picker</li>



<li><strong>_imageFields</strong> = Dropdown options for the Image field picker</li>



<li><strong>_linkFields </strong>= Dropdown options for the Link field picker</li>



<li><strong>_announcementItems </strong>= List items fetched from SharePoint</li>



<li><strong>render</strong>() = Called automatically whenever a web part property changes.</li>



<li><strong>onInit</strong>() = Initializes the PnP SP instance with the current SPFx context so we can call SharePoint APIs.</li>



<li><strong>onPropertyPaneConfigurationStart</strong>() = Fires when the user opens the property pane. Loads field options and list items so the pane shows up-to-date data.</li>



<li><strong>_loadAnnouncementItems</strong>() = Fetches items from the selected SharePoint list. Uses PnP SP to query items, then syncs them into slidesConfig so new items appear automatically.
<ul class="wp-block-list">
<li><strong>items </strong>= Query SharePoint, select only the Id and Title columns, limited by numberOfItems.</li>



<li><strong>this._announcementItems</strong> = Map raw SharePoint response into a simple { id, title } array.</li>



<li><strong>slidesConfig </strong>= Sync slidesConfig; any new list item not already in slidesConfig gets added as visible.</li>
</ul>
</li>



<li><strong>onPropertyPaneFieldChanged</strong>() = Fires whenever the user changes any property pane field.
<ul class="wp-block-list">
<li>Handles two scenarios: list change (reset everything) or field mapping change (reload items).</li>



<li>If the user picked a different list, reset all field mappings and slides.</li>



<li>If all four required fields are configured, fetch items and refresh the pane</li>
</ul>
</li>



<li><strong>_loadFieldOptions</strong>() = Populates the dropdown options for Title, Image, and Link fields.
<ul class="wp-block-list">
<li>When no list is selected, the dropdowns are empty. Otherwise, they show the available columns.</li>
</ul>
</li>



<li><strong>getPropertyPaneConfiguration</strong>() = &nbsp;Builds the entire property pane UI.
<ul class="wp-block-list">
<li>Returns the configuration object that SPFx uses to render the property pane panel.</li>



<li>configFields = &#8220;Configuration&#8221; group, always visible
<ul class="wp-block-list">
<li><strong>PropertyFieldListPicker </strong>= &nbsp;List picker dropdown, shows all lists/libraries in the current site.</li>



<li><strong>PropertyFieldNumber </strong>= Number field, how many items to fetch from the list.</li>
</ul>
</li>



<li><strong>this.properties.selectedListId</strong> = Field mapping dropdowns, only shown after a list is selected</li>



<li><strong>isConfigured </strong>= &#8220;Slides&#8221; group, only shown when all fields are configured, AND items exist.</li>



<li><strong>PropertyPaneSlidesManager </strong>= Renders the custom SlidesManager component inside the property pane. When the user reorders or hides/shows slides, onConfigChanged saves the new config.</li>
</ul>
</li>
</ul>



<p>This way, you can easily build a drag &amp; drop slide on the SPFx web part property pane.</p>



<div class="wp-block-buttons alignwide is-content-justification-center is-layout-flex wp-container-core-buttons-is-layout-16018d1d wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://www.spguides.com/download-spfx-solutions/">Download SPFx Solutions</a></div>
</div>



<h2 class="wp-block-heading">Conclusion</h2>



<p>In this post, we learned how to build a <strong>custom slide manager inside the SPFx property pane</strong> that lets editors reorder slides, move them up or down, remove them, and restore them later, all without touching the original SharePoint list items.</p>



<p>This approach works well when you’re building carousel or banner web parts and want to give users control similar to the SharePoint Hero web part. It keeps the editing experience simple, safe, and easy to manage.</p>



<p>If you’re working on advanced<a href="https://www.spguides.com/sharepoint-framework-crud-operations-using-react/"> SPFx web parts</a> and need better content control in the property pane, this pattern is worth using.</p>



<p>Also, you may like:</p>



<ul class="wp-block-list">
<li><a href="https://www.spguides.com/sharepoint-client-side-web-part-configurable-properties-in-property-pane-using-spfx/">SPFx Property Pane Controls</a></li>



<li><a href="https://www.spguides.com/create-folders-and-subfolders-in-sharepoint-document-library-using-spfx/">Create Folders and Subfolders in SharePoint document library using SPFx</a></li>



<li><a href="https://www.spguides.com/spfx-upload-file-to-sharepoint-document-library-with-metadata/">SPFx Upload File to SharePoint Document Library With Metadata [Complete Example]</a></li>



<li><a href="https://www.spguides.com/spfx-dynamic-accordion-webpart-pnp-react-controls/">Create SPFx Dynamic Accordion Webpart Using PnP Controls React</a></li>
</ul>
<div class="saboxplugin-wrap" itemtype="http://schema.org/Person" itemscope itemprop="author"><div class="saboxplugin-tab"><div class="saboxplugin-gravatar"><img loading="lazy" decoding="async" src="https://www.spguides.com/wp-content/uploads/2026/02/Bijay-White-500.avif" width="100" height="100" alt="Microsoft MVP - Power Apps and Power Automate" itemprop="image" title="Bijay White 500"></div><div class="saboxplugin-authorname"><a href="https://www.spguides.com/author/fewlines4biju/" class="vcard author" rel="author"><span class="fn">Bijay Kumar</span></a></div><div class="saboxplugin-desc"><div itemprop="description"><p>Hey! I’m Bijay Kumar, founder of SPGuides.com and a <a href="https://mvp.microsoft.com/en-US/mvp/profile/b59207f9-3c9a-e411-93f2-9cb65495d3c4" target="_blank" rel="nofollow noopener">Microsoft Business Applications MVP</a> (Power Automate, Power Apps). I launched this site in 2020 because I truly enjoy working with SharePoint, Power Platform, and SharePoint Framework (SPFx), and wanted to share that passion through step-by-step tutorials, guides, and <a href="https://www.youtube.com/@SPGuides?sub_confirmation=1" target="_blank" rel="noopener">training videos</a>. My mission is to help you learn these technologies so you can utilize SharePoint, enhance productivity, and potentially build business solutions along the way.</p>
</div></div><div class="saboxplugin-web "><a href="https://www.enjoysharepoint.com" target="_self" rel="noopener">www.enjoysharepoint.com</a></div><div class="clearfix"></div><div class="saboxplugin-socials sabox-colored"><a title="Linkedin" target="_self" href="https://www.linkedin.com/in/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-linkedin" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#0077b5" /><polygon class="st1" points="500.3 374.1 500.3 500.6 278.2 500.6 141.1 363.6 176.3 220.6 144.3 183 182.4 144.4 250.3 212.7 262.2 212.7 271.7 222 342.2 218.1" /><path class="st2" d="m187.9 363.6h-46.9v-150.9h46.9v150.9zm-23.4-171.5c-15 0-27.1-12.4-27.1-27.4s12.2-27.1 27.1-27.1c15 0 27.1 12.2 27.1 27.1 0 15-12.1 27.4-27.1 27.4zm198.8 171.5h-46.8v-73.4c0-17.5-0.4-39.9-24.4-39.9-24.4 0-28.1 19-28.1 38.7v74.7h-46.8v-151h44.9v20.6h0.7c6.3-11.9 21.5-24.4 44.3-24.4 47.4 0 56.1 31.2 56.1 71.8l0.1 82.9z" /></svg></span></a><a title="Behance" target="_self" href="http://Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-behance" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".2" y=".3" width="500" height="500" fill="#1769ff" /><polygon class="st1" points="500.2 297.6 500.2 500.3 280.8 500.3 108.6 327.8 135.7 171.3 233 164.4 285 215.9 303.7 219.9 335 224 293.5 179.9 364.1 162.7" /><path class="st2" d="m222.7 233.1c15.6-7.5 23.8-18.8 23.8-36.4 0-34.7-25.9-43.2-55.7-43.2h-82.2v174.2h84.5c31.7 0 61.4-15.2 61.4-50.6 0-21.8-10.4-37.9-31.8-44zm-75.8-49.8h35.9c13.8 0 26.3 3.9 26.3 19.9 0 14.8-9.7 20.7-23.4 20.7h-38.8v-40.6zm41 114.9h-41v-48h41.7c16.9 0 27.5 7 27.5 24.9 0.1 17.6-12.7 23.1-28.2 23.1zm176.2-118.3h-70.7v-17.2h70.7v17.2zm27.7 86.6c0-37.3-21.8-68.4-61.4-68.4-38.4 0-64.6 28.9-64.6 66.8 0 39.3 24.7 66.2 64.6 66.2 30.1 0 49.7-13.6 59-42.4h-30.6c-3.3 10.8-16.9 16.5-27.4 16.5-20.3 0-31-11.9-31-32.1h91c0.3-2.1 0.4-4.3 0.4-6.6zm-91.3-15.3c1.1-16.6 12.1-26.9 28.8-26.9 17.4 0 26.2 10.2 27.6 26.9h-56.4z" /></svg></span></a><a title="Pinterest" target="_self" href="https://in.pinterest.com/fewlines4biju/" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-pinterest" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".3" y=".6" width="500" height="500" fill="#bd081c" /><path class="st1" d="m500.3 310.4v190.2h-227.8l-87.7-88.2 17.2-85.2-43-45s-9-64-7-70 21-49 21-49 40-30 44-30 115.7 9.1 115.7 9.1l167.6 168.1z" /><path class="st2" d="m257.5 115.4c-61.4 0-122.1 40.9-122.1 107.2 0 42.1 23.7 66.1 38.1 66.1 5.9 0 9.3-16.5 9.3-21.2 0-5.6-14.2-17.4-14.2-40.6 0-48.1 36.6-82.3 84-82.3 40.8 0 70.9 23.2 70.9 65.7 0 31.8-12.8 91.4-54.1 91.4-14.9 0-27.7-10.8-27.7-26.2 0-22.6 15.8-44.5 15.8-67.9 0-39.6-56.2-32.4-56.2 15.4 0 10.1 1.3 21.2 5.7 30.4-8.3 35.6-25.1 88.5-25.1 125.2 0 11.3 1.6 22.4 2.7 33.8 2 2.3 1 2 4.1 0.9 30.2-41.3 29.1-49.4 42.7-103.4 7.4 14 26.4 21.6 41.5 21.6 63.6 0 92.1-62 92.1-117.8 0.2-59.5-51.1-98.3-107.5-98.3z" /></svg></span></a><a title="Twitter" target="_self" href="https://twitter.com/fewlines4biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-twitter" id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
  <path d="M 9.398 6.639 L 16.922 17.361 L 14.922 17.361 L 7.412 6.639 L 9.398 6.639 Z M 24.026 24.026 L -0.026 24.026 L -0.026 -0.026 L 24.026 -0.026 L 24.026 24.026 Z M 19.4 18.681 L 13.807 10.677 L 18.379 5.319 L 16.627 5.319 L 13.014 9.541 L 10.065 5.319 L 4.921 5.319 L 10.187 12.846 L 5.193 18.681 L 6.975 18.681 L 10.985 13.983 L 14.269 18.681 L 19.4 18.681 Z" />
</svg></span></a><a title="Whatsapp" target="_self" href="https://wa.me/+919916854253" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-whatsapp" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500.7" xml:space="preserve"><rect x="-0.9" y="0.2" class="st0" width="500" height="500" fill="#25d366" />
<path class="st1" d="M499.1,304.9v195.3H225.9L118.6,393.4l0.1-0.2l13-35.5l11.2-27.7l9.4-2L138,308.2l-5-15l-4-30l-3-18l7-28  l13-26.1l18-25.9l23-20l37-15h76l41.9,17.1l22.6,22.7c0,0,0,0,0,0L499.1,304.9z" /><path fill="#25d366" class="st2" d="M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1c-3.1-1.2-5.4-1.7-7.7,1.7   c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7c1.1-2.3,0.6-4.3-0.3-6   c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2c-3.1,3.5-12,11.7-12,28.5   c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6c6.6-1,20.2-8.3,23-16.3   C326.2,294.9,326.2,288.1,325.3,286.7z M325.3,286.7c-0.8-1.5-3.1-2.4-6.5-4.1c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3C326.2,294.9,326.2,288.1,325.3,286.7z M364.6,170C364.6,170,364.6,170,364.6,170   c-3.5-4.5-7.3-8.7-11.3-12.7c-25.8-25.9-60.2-40.1-96.7-40.1c-75.4,0-136.8,61.4-136.8,136.8c0,24.1,6.3,47.6,18.2,68.4l-19.4,70.9   l0.1,0l72.4-19c20,10.9,42.4,16.6,65.4,16.6h0.1c75.3,0,138.1-61.4,138.1-136.8C394.6,223.2,383.5,194,364.6,170z M256.5,367.8   c-20.5,0-40.5-5.5-57.9-15.8l-4.1-2.5l-43,11.3l11.5-41.9l-2.7-4.3c-11.4-18.1-17.4-39-17.4-60.5c0-62.7,51-113.7,113.7-113.7   c30.4,0,58.9,11.8,80.3,33.3s34.6,50,34.6,80.4C371.5,316.7,319.2,367.8,256.5,367.8z M318.9,282.6c-3.4-1.7-20.2-10-23.3-11.1   c-3.1-1.2-5.4-1.7-7.7,1.7c-2.3,3.5-8.8,11.1-10.8,13.4c-2,2.3-4,2.6-7.4,0.9c-20.1-10-33.3-17.9-46.5-40.7c-3.5-6,3.5-5.6,10-18.7   c1.1-2.3,0.6-4.3-0.3-6c-0.9-1.7-7.7-18.5-10.5-25.4c-2.8-6.7-5.6-5.7-7.7-5.9c-2-0.1-4.2-0.1-6.5-0.1c-2.3,0-6,0.9-9.1,4.2   c-3.1,3.5-12,11.7-12,28.5c0,16.8,12.3,33.1,13.9,35.4c1.7,2.3,24.1,36.8,58.4,51.6c21.7,9.4,30.2,10.2,41,8.6   c6.6-1,20.2-8.3,23-16.3c2.8-8,2.8-14.8,2-16.3C324.5,285.1,322.3,284.3,318.9,282.6z" /></svg></span></a><a title="Facebook" target="_self" href="https://www.facebook.com/Fewlines4Biju" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-facebook" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x="-.3" y=".3" width="500" height="500" fill="#3b5998" /><polygon class="st1" points="499.7 292.6 499.7 500.3 331.4 500.3 219.8 388.7 221.6 385.3 223.7 308.6 178.3 264.9 219.7 233.9 249.7 138.6 321.1 113.9" /><path class="st2" d="M219.8,388.7V264.9h-41.5v-49.2h41.5V177c0-42.1,25.7-65,63.3-65c18,0,33.5,1.4,38,1.9v44H295  c-20.4,0-24.4,9.7-24.4,24v33.9h46.1l-6.3,49.2h-39.8v123.8" /></svg></span></a><a title="Youtube" target="_self" href="https://www.youtube.com/@SPGuides?sub_confirmation=1" rel="nofollow noopener" class="saboxplugin-icon-color"><svg class="sab-youtube" viewBox="0 0 500 500.7" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect class="st0" x=".4" y="-.3" width="500" height="500" fill="#ff0000" /><polygon class="st1" points="500.4 311.3 500.4 499.7 311.8 499.7 139.5 326.7 205 196.6 360.9 172.5" /><path class="st2" d="m371.3 188.8c-2.9-10.9-11.4-19.5-22.3-22.4-19.7-5.3-98.6-5.3-98.6-5.3s-78.9 0-98.6 5.3c-10.9 2.9-19.4 11.5-22.3 22.4-5.3 19.8-5.3 61.1-5.3 61.1s0 41.3 5.3 61.1c2.9 10.9 11.4 19.2 22.3 22.1 19.7 5.3 98.6 5.3 98.6 5.3s78.9 0 98.6-5.3c10.9-2.9 19.4-11.2 22.3-22.1 5.3-19.8 5.3-61.1 5.3-61.1s0-41.3-5.3-61.1zm-146.7 98.6v-75l65.9 37.5-65.9 37.5z" /></svg></span></a></div></div></div>]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
